Skip to content

Commit ae4136a

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

File tree

10 files changed

+576
-0
lines changed

10 files changed

+576
-0
lines changed

detectors/gcp/README.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
// use the resource in your tracerprovider (or meterprovider)
28+
tp := trace.NewTracerProvider(
29+
// ... other options
30+
trace.WithResource(res),
31+
)
32+
```
33+
34+
## Setting Kubernetes attributes
35+
36+
Previous iterations of GCP resource detection attempted to detect
37+
container.name, k8s.pod.name and k8s.namespace.name. When using this detector,
38+
you should use this in your Pod Spec to set these using
39+
OTEL_RESOURCE_ATTRIBUTES:
40+
41+
```yaml
42+
env:
43+
- name: POD_NAME
44+
valueFrom:
45+
fieldRef:
46+
fieldPath: metadata.name
47+
- name: NAMESPACE_NAME
48+
valueFrom:
49+
fieldRef:
50+
fieldPath: metadata.namespace
51+
- name: CONTAINER_NAME
52+
value: my-container-name
53+
- name: OTEL_RESOURCE_ATTRIBUTES
54+
value: k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE_NAME),k8s.container.name=$(CONTAINER_NAME)

detectors/gcp/cloud-function.go

+1
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

+2
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

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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+
"go.opentelemetry.io/otel/attribute"
24+
"go.opentelemetry.io/otel/sdk/resource"
25+
semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
26+
)
27+
28+
// NewDetector returns a resource detector which detects resource attributes on:
29+
// * Google Compute Engine (GCE)
30+
// * Google Kubernetes Engine (GKE)
31+
// * Google App Engine (GAE)
32+
// * Cloud Run
33+
// * Cloud Functions
34+
func NewDetector() resource.Detector {
35+
return &detector{detector: gcp.NewDetector()}
36+
}
37+
38+
type detector struct {
39+
detector gcpDetector
40+
}
41+
42+
// Detect detects associated resources when running on GCE, GKE, GAE,
43+
// Cloud Run, and Cloud functions.
44+
func (d *detector) Detect(ctx context.Context) (*resource.Resource, error) {
45+
if !metadata.OnGCE() {
46+
return nil, nil
47+
}
48+
projectID, err := d.detector.ProjectID()
49+
if err != nil {
50+
return nil, err
51+
}
52+
attributes := []attribute.KeyValue{semconv.CloudProviderGCP, semconv.CloudAccountIDKey.String(projectID)}
53+
54+
switch d.detector.CloudPlatform() {
55+
case gcp.GKE:
56+
attributes = append(attributes, semconv.CloudPlatformGCPKubernetesEngine)
57+
v, locType, err := d.detector.GKEAvailabilityZoneOrRegion()
58+
if err != nil {
59+
return nil, err
60+
}
61+
switch locType {
62+
case gcp.Zone:
63+
attributes = append(attributes, semconv.CloudAvailabilityZoneKey.String(v))
64+
case gcp.Region:
65+
attributes = append(attributes, semconv.CloudRegionKey.String(v))
66+
default:
67+
return nil, fmt.Errorf("location must be zone or region. Got %v", locType)
68+
}
69+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
70+
semconv.K8SClusterNameKey: d.detector.GKEClusterName,
71+
semconv.HostIDKey: d.detector.GKEHostID,
72+
semconv.HostNameKey: d.detector.GKEHostName,
73+
})
74+
case gcp.CloudRun:
75+
attributes = append(attributes, semconv.CloudPlatformGCPCloudRun)
76+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
77+
semconv.FaaSNameKey: d.detector.FaaSName,
78+
semconv.FaaSVersionKey: d.detector.FaaSVersion,
79+
semconv.FaaSIDKey: d.detector.FaaSID,
80+
semconv.CloudRegionKey: d.detector.FaaSCloudRegion,
81+
})
82+
case gcp.CloudFunctions:
83+
attributes = append(attributes, semconv.CloudPlatformGCPCloudFunctions)
84+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
85+
semconv.FaaSNameKey: d.detector.FaaSName,
86+
semconv.FaaSVersionKey: d.detector.FaaSVersion,
87+
semconv.FaaSIDKey: d.detector.FaaSID,
88+
semconv.CloudRegionKey: d.detector.FaaSCloudRegion,
89+
})
90+
case gcp.AppEngine:
91+
attributes = append(attributes, semconv.CloudPlatformGCPAppEngine)
92+
zone, region, err := d.detector.AppEngineAvailabilityZoneAndRegion()
93+
if err != nil {
94+
return nil, err
95+
}
96+
attributes = append(attributes, semconv.CloudAvailabilityZoneKey.String(zone))
97+
attributes = append(attributes, semconv.CloudRegionKey.String(region))
98+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
99+
semconv.FaaSNameKey: d.detector.AppEngineServiceName,
100+
semconv.FaaSVersionKey: d.detector.AppEngineServiceVersion,
101+
semconv.FaaSIDKey: d.detector.AppEngineServiceInstance,
102+
})
103+
case gcp.GCE:
104+
attributes = append(attributes, semconv.CloudPlatformGCPComputeEngine)
105+
zone, region, err := d.detector.GCEAvailabilityZoneAndRegion()
106+
if err != nil {
107+
return nil, err
108+
}
109+
attributes = append(attributes, semconv.CloudAvailabilityZoneKey.String(zone))
110+
attributes = append(attributes, semconv.CloudRegionKey.String(region))
111+
return detectWithFuncs(attributes, map[attribute.Key]detectionFunc{
112+
semconv.HostTypeKey: d.detector.GCEHostType,
113+
semconv.HostIDKey: d.detector.GCEHostID,
114+
semconv.HostNameKey: d.detector.GCEHostName,
115+
})
116+
default:
117+
// We don't support this platform yet, so just return with what we have
118+
return resource.NewWithAttributes(semconv.SchemaURL, attributes...), nil
119+
}
120+
}
121+
122+
type detectionFunc func() (string, error)
123+
124+
// detectWithFuncs is a helper to reduce the amount of error handling code
125+
func detectWithFuncs(attributes []attribute.KeyValue, funcs map[attribute.Key]detectionFunc) (*resource.Resource, error) {
126+
for key, detect := range funcs {
127+
v, err := detect()
128+
if err != nil {
129+
return nil, err
130+
}
131+
attributes = append(attributes, key.String(v))
132+
}
133+
return resource.NewWithAttributes(semconv.SchemaURL, attributes...), nil
134+
}

0 commit comments

Comments
 (0)