Skip to content

Commit cb346ca

Browse files
committed
update GCP resource detection
1 parent 2e08c1f commit cb346ca

File tree

10 files changed

+592
-0
lines changed

10 files changed

+592
-0
lines changed

detectors/gcp/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# GCP Resource detector
2+
3+
The GCP resource detector supports detecting resources on:
4+
5+
* Google Compute Engine (GCE)
6+
* Google Kubernetes Engine (GKE)
7+
* Google App Engine (GAE)
8+
* Cloud Run
9+
* Cloud Functions
10+
11+
## Usage
12+
13+
```golang
14+
ctx := context.Background()
15+
// Detect your resources
16+
res, err := resource.New(ctx,
17+
// Use the GCP resource detector!
18+
resource.WithDetectors(gcp.NewDetector()),
19+
// Keep the default detectors
20+
resource.WithTelemetrySDK(),
21+
// Add your own custom attributes to identify your application
22+
resource.WithAttributes(
23+
semconv.ServiceNameKey.String("my-application"),
24+
semconv.ServiceNamespaceKey.String("my-company-frontend-team"),
25+
),
26+
)
27+
if err != nil {
28+
// Handle err
29+
}
30+
// Use the resource in your tracerprovider (or meterprovider)
31+
tp := trace.NewTracerProvider(
32+
// ... other options
33+
trace.WithResource(res),
34+
)
35+
```
36+
37+
## Setting Kubernetes attributes
38+
39+
Previous iterations of GCP resource detection attempted to detect
40+
container.name, k8s.pod.name and k8s.namespace.name. When using this detector,
41+
you should use this in your Pod Spec to set these using
42+
OTEL_RESOURCE_ATTRIBUTES:
43+
44+
```yaml
45+
env:
46+
- name: POD_NAME
47+
valueFrom:
48+
fieldRef:
49+
fieldPath: metadata.name
50+
- name: NAMESPACE_NAME
51+
valueFrom:
52+
fieldRef:
53+
fieldPath: metadata.namespace
54+
- name: CONTAINER_NAME
55+
value: my-container-name
56+
- name: OTEL_RESOURCE_ATTRIBUTES
57+
value: k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE_NAME),k8s.container.name=$(CONTAINER_NAME)

detectors/gcp/cloud-function.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const (
2828
)
2929

3030
// NewCloudFunction will return a GCP Cloud Function resource detector.
31+
// Deprecated: Use gcp.NewDetector() instead, which sets the same resource attributes.
3132
func NewCloudFunction() resource.Detector {
3233
return &cloudFunction{
3334
cloudRun: NewCloudRun(),

detectors/gcp/cloud-run.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type metadataClient interface {
3838
}
3939

4040
// CloudRun collects resource information of Cloud Run instance.
41+
// Deprecated: Use gcp.NewDetector() instead. Note that it sets faas.* resource attributes instead of service.* attributes.
4142
type CloudRun struct {
4243
mc metadataClient
4344
onGCE func() bool
@@ -49,6 +50,7 @@ type CloudRun struct {
4950
var _ resource.Detector = (*CloudRun)(nil)
5051

5152
// NewCloudRun creates a CloudRun detector.
53+
// Deprecated: Use gcp.NewDetector() instead. Note that it sets faas.* resource attributes instead of service.* attributes.
5254
func NewCloudRun() *CloudRun {
5355
return &CloudRun{
5456
mc: metadata.NewClient(nil),

detectors/gcp/detector.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package gcp // import "go.opentelemetry.io/contrib/detectors/gcp"
16+
17+
import (
18+
"context"
19+
"fmt"
20+
21+
"cloud.google.com/go/compute/metadata"
22+
"github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp"
23+
24+
"go.opentelemetry.io/otel/attribute"
25+
"go.opentelemetry.io/otel/sdk/resource"
26+
semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
27+
)
28+
29+
// NewDetector returns a resource detector which detects resource attributes on:
30+
// * Google Compute Engine (GCE)
31+
// * Google Kubernetes Engine (GKE)
32+
// * Google App Engine (GAE)
33+
// * Cloud Run
34+
// * Cloud Functions
35+
func NewDetector() resource.Detector {
36+
return &detector{detector: gcp.NewDetector()}
37+
}
38+
39+
type detector struct {
40+
detector gcpDetector
41+
}
42+
43+
// Detect detects associated resources when running on GCE, GKE, GAE,
44+
// Cloud Run, and Cloud functions.
45+
func (d *detector) Detect(ctx context.Context) (*resource.Resource, error) {
46+
if !metadata.OnGCE() {
47+
return nil, nil
48+
}
49+
projectID, err := d.detector.ProjectID()
50+
if err != nil {
51+
return nil, err
52+
}
53+
attributes := []attribute.KeyValue{semconv.CloudProviderGCP, semconv.CloudAccountIDKey.String(projectID)}
54+
55+
switch d.detector.CloudPlatform() {
56+
case gcp.GKE:
57+
attributes = append(attributes, semconv.CloudPlatformGCPKubernetesEngine)
58+
v, locType, err := d.detector.GKEAvailabilityZoneOrRegion()
59+
if err != nil {
60+
return nil, err
61+
}
62+
switch locType {
63+
case gcp.Zone:
64+
attributes = append(attributes, semconv.CloudAvailabilityZoneKey.String(v))
65+
case gcp.Region:
66+
attributes = append(attributes, semconv.CloudRegionKey.String(v))
67+
default:
68+
return nil, fmt.Errorf("location must be zone or region. Got %v", locType)
69+
}
70+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
71+
semconv.K8SClusterNameKey: d.detector.GKEClusterName,
72+
semconv.HostIDKey: d.detector.GKEHostID,
73+
semconv.HostNameKey: d.detector.GKEHostName,
74+
})
75+
case gcp.CloudRun:
76+
attributes = append(attributes, semconv.CloudPlatformGCPCloudRun)
77+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
78+
semconv.FaaSNameKey: d.detector.FaaSName,
79+
semconv.FaaSVersionKey: d.detector.FaaSVersion,
80+
semconv.FaaSIDKey: d.detector.FaaSID,
81+
semconv.CloudRegionKey: d.detector.FaaSCloudRegion,
82+
})
83+
case gcp.CloudFunctions:
84+
attributes = append(attributes, semconv.CloudPlatformGCPCloudFunctions)
85+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
86+
semconv.FaaSNameKey: d.detector.FaaSName,
87+
semconv.FaaSVersionKey: d.detector.FaaSVersion,
88+
semconv.FaaSIDKey: d.detector.FaaSID,
89+
semconv.CloudRegionKey: d.detector.FaaSCloudRegion,
90+
})
91+
case gcp.AppEngine:
92+
attributes = append(attributes, semconv.CloudPlatformGCPAppEngine)
93+
zone, region, err := d.detector.AppEngineAvailabilityZoneAndRegion()
94+
if err != nil {
95+
return nil, err
96+
}
97+
attributes = append(attributes, semconv.CloudAvailabilityZoneKey.String(zone))
98+
attributes = append(attributes, semconv.CloudRegionKey.String(region))
99+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
100+
semconv.FaaSNameKey: d.detector.AppEngineServiceName,
101+
semconv.FaaSVersionKey: d.detector.AppEngineServiceVersion,
102+
semconv.FaaSIDKey: d.detector.AppEngineServiceInstance,
103+
})
104+
case gcp.GCE:
105+
attributes = append(attributes, semconv.CloudPlatformGCPComputeEngine)
106+
zone, region, err := d.detector.GCEAvailabilityZoneAndRegion()
107+
if err != nil {
108+
return nil, err
109+
}
110+
attributes = append(attributes, semconv.CloudAvailabilityZoneKey.String(zone))
111+
attributes = append(attributes, semconv.CloudRegionKey.String(region))
112+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
113+
semconv.HostTypeKey: d.detector.GCEHostType,
114+
semconv.HostIDKey: d.detector.GCEHostID,
115+
semconv.HostNameKey: d.detector.GCEHostName,
116+
})
117+
default:
118+
// We don't support this platform yet, so just return with what we have
119+
return resource.NewWithAttributes(semconv.SchemaURL, attributes...), nil
120+
}
121+
}
122+
123+
type detectionFunc func() (string, error)
124+
125+
// detectWithFuncs is a helper to reduce the amount of error handling code
126+
func detectWithFuncs(attributes []attribute.KeyValue, funcs map[attribute.Key]detectionFunc) (*resource.Resource, error) {
127+
for key, detect := range funcs {
128+
v, err := detect()
129+
if err != nil {
130+
return nil, err
131+
}
132+
attributes = append(attributes, key.String(v))
133+
}
134+
return resource.NewWithAttributes(semconv.SchemaURL, attributes...), nil
135+
}

0 commit comments

Comments
 (0)