Skip to content

Commit 4cef291

Browse files
committed
feat(internal/trace): add OpenTelemetry support
Add GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING env var flag for opt-in OpenTelemetry tracing. refs: googleapis#2205
1 parent 525abde commit 4cef291

File tree

4 files changed

+368
-10
lines changed

4 files changed

+368
-10
lines changed

go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ require (
99
github.com/google/martian/v3 v3.3.2
1010
github.com/googleapis/gax-go/v2 v2.12.0
1111
go.opencensus.io v0.24.0
12+
go.opentelemetry.io/otel v1.19.0
13+
go.opentelemetry.io/otel/trace v1.19.0
1214
golang.org/x/oauth2 v0.11.0
1315
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
1416
google.golang.org/api v0.128.0
@@ -23,11 +25,14 @@ require (
2325
cloud.google.com/go/compute v1.23.0 // indirect
2426
cloud.google.com/go/compute/metadata v0.2.3 // indirect
2527
cloud.google.com/go/iam v1.1.1 // indirect
28+
github.com/go-logr/logr v1.2.4 // indirect
29+
github.com/go-logr/stdr v1.2.2 // indirect
2630
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
2731
github.com/golang/snappy v0.0.4 // indirect
2832
github.com/google/s2a-go v0.1.4 // indirect
2933
github.com/google/uuid v1.3.1 // indirect
3034
github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect
35+
go.opentelemetry.io/otel/metric v1.19.0 // indirect
3136
golang.org/x/crypto v0.14.0 // indirect
3237
golang.org/x/net v0.17.0 // indirect
3338
golang.org/x/sync v0.3.0 // indirect

go.sum

+15
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
2020
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
2121
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
2222
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
23+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2324
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2425
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
2526
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -29,6 +30,11 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m
2930
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
3031
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
3132
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
33+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
34+
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
35+
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
36+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
37+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
3238
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
3339
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
3440
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
@@ -74,6 +80,7 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5
7480
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
7581
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
7682
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
83+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
7784
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7885
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
7986
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@@ -85,9 +92,16 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
8592
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
8693
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
8794
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
95+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
8896
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
8997
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
9098
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
99+
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
100+
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
101+
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
102+
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
103+
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
104+
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
91105
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
92106
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
93107
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -206,6 +220,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
206220
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
207221
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
208222
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
223+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
209224
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
210225
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
211226
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

internal/trace/trace.go

+105-10
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,74 @@ package trace
1616

1717
import (
1818
"context"
19+
"errors"
1920
"fmt"
21+
"os"
22+
"sort"
23+
"strings"
2024

2125
"go.opencensus.io/trace"
22-
"golang.org/x/xerrors"
26+
"go.opentelemetry.io/otel"
27+
"go.opentelemetry.io/otel/attribute"
28+
"go.opentelemetry.io/otel/codes"
29+
ottrace "go.opentelemetry.io/otel/trace"
2330
"google.golang.org/api/googleapi"
2431
"google.golang.org/genproto/googleapis/rpc/code"
2532
"google.golang.org/grpc/status"
2633
)
2734

35+
const (
36+
telemetryPlatformTracing = "GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING"
37+
telemetryPlatformTracingOpenCensus = "opencensus"
38+
telemetryPlatformTracingOpenTelemetry = "opentelemetry"
39+
)
40+
41+
var (
42+
// TODO(chrisdsmith): What is the correct name for the OpenTelemetry tracer?
43+
OpenTelemetryTracerName string = "cloud.google.com/go/internal/trace"
44+
)
45+
46+
func IsOpenCensusTracingEnabled() bool {
47+
return !IsOpenTelemetryTracingEnabled()
48+
}
49+
50+
func IsOpenTelemetryTracingEnabled() bool {
51+
env := strings.TrimSpace(os.Getenv(telemetryPlatformTracing))
52+
return strings.EqualFold(env, telemetryPlatformTracingOpenTelemetry)
53+
}
54+
2855
// StartSpan adds a span to the trace with the given name.
2956
func StartSpan(ctx context.Context, name string) context.Context {
30-
ctx, _ = trace.StartSpan(ctx, name)
57+
if IsOpenTelemetryTracingEnabled() {
58+
ctx, _ = otel.GetTracerProvider().Tracer(OpenTelemetryTracerName).Start(ctx, name)
59+
} else {
60+
ctx, _ = trace.StartSpan(ctx, name)
61+
}
3162
return ctx
3263
}
3364

3465
// EndSpan ends a span with the given error.
3566
func EndSpan(ctx context.Context, err error) {
36-
span := trace.FromContext(ctx)
37-
if err != nil {
38-
span.SetStatus(toStatus(err))
67+
if IsOpenTelemetryTracingEnabled() {
68+
span := ottrace.SpanFromContext(ctx)
69+
if err != nil {
70+
span.SetStatus(codes.Error, toOpenTelemetryStatusDescription(err))
71+
span.RecordError(err)
72+
}
73+
span.End()
74+
} else {
75+
span := trace.FromContext(ctx)
76+
if err != nil {
77+
span.SetStatus(toStatus(err))
78+
}
79+
span.End()
3980
}
40-
span.End()
4181
}
4282

43-
// toStatus interrogates an error and converts it to an appropriate
44-
// OpenCensus status.
83+
// toStatus converts an error to an equivalent OpenCensus status.
4584
func toStatus(err error) trace.Status {
4685
var err2 *googleapi.Error
47-
if ok := xerrors.As(err, &err2); ok {
86+
if ok := errors.As(err, &err2); ok {
4887
return trace.Status{Code: httpStatusCodeToOCCode(err2.Code), Message: err2.Message}
4988
} else if s, ok := status.FromError(err); ok {
5089
return trace.Status{Code: int32(s.Code()), Message: s.Message()}
@@ -53,6 +92,18 @@ func toStatus(err error) trace.Status {
5392
}
5493
}
5594

95+
// toOpenTelemetryStatus converts an error to an equivalent OpenTelemetry status description.
96+
func toOpenTelemetryStatusDescription(err error) string {
97+
var err2 *googleapi.Error
98+
if ok := errors.As(err, &err2); ok {
99+
return err2.Message
100+
} else if s, ok := status.FromError(err); ok {
101+
return s.Message()
102+
} else {
103+
return err.Error()
104+
}
105+
}
106+
56107
// TODO(deklerk): switch to using OpenCensus function when it becomes available.
57108
// Reference: https://github.com/googleapis/googleapis/blob/26b634d2724ac5dd30ae0b0cbfb01f07f2e4050e/google/rpc/code.proto
58109
func httpStatusCodeToOCCode(httpStatusCode int) int32 {
@@ -86,10 +137,25 @@ func httpStatusCodeToOCCode(httpStatusCode int) int32 {
86137
}
87138
}
88139

140+
// TracePrintf retrieves the current OpenCensus or OpenTelemetry span from context, then:
141+
// * calls Span.Annotatef if OpenCensus is enabled; or
142+
// * calls Span.AddEvent if OpenTelemetry is enabled.
143+
//
89144
// TODO: (odeke-em): perhaps just pass around spans due to the cost
90145
// incurred from using trace.FromContext(ctx) yet we could avoid
91146
// throwing away the work done by ctx, span := trace.StartSpan.
92147
func TracePrintf(ctx context.Context, attrMap map[string]interface{}, format string, args ...interface{}) {
148+
if IsOpenTelemetryTracingEnabled() {
149+
attrs := otAttrs(attrMap)
150+
ottrace.SpanFromContext(ctx).AddEvent(fmt.Sprintf(format, args...), ottrace.WithAttributes(attrs...))
151+
} else {
152+
attrs := ocAttrs(attrMap)
153+
trace.FromContext(ctx).Annotatef(attrs, format, args...)
154+
}
155+
}
156+
157+
// ocAttrs converts a generic map to OpenCensus attributes.
158+
func ocAttrs(attrMap map[string]interface{}) []trace.Attribute {
93159
var attrs []trace.Attribute
94160
for k, v := range attrMap {
95161
var a trace.Attribute
@@ -107,5 +173,34 @@ func TracePrintf(ctx context.Context, attrMap map[string]interface{}, format str
107173
}
108174
attrs = append(attrs, a)
109175
}
110-
trace.FromContext(ctx).Annotatef(attrs, format, args...)
176+
return attrs
177+
}
178+
179+
// otAttrs converts a generic map to OpenTelemetry attributes.
180+
func otAttrs(attrMap map[string]interface{}) []attribute.KeyValue {
181+
var attrs []attribute.KeyValue
182+
// Sort the input map by its keys for predictable order in tests.
183+
keys := make([]string, 0, len(attrMap))
184+
for k := range attrMap {
185+
keys = append(keys, k)
186+
}
187+
sort.Strings(keys)
188+
for _, k := range keys {
189+
v := attrMap[k]
190+
var a attribute.KeyValue
191+
switch v := v.(type) {
192+
case string:
193+
a = attribute.Key(k).String(v)
194+
case bool:
195+
a = attribute.Key(k).Bool(v)
196+
case int:
197+
a = attribute.Key(k).Int(v)
198+
case int64:
199+
a = attribute.Key(k).Int64(v)
200+
default:
201+
a = attribute.Key(k).String(fmt.Sprintf("%#v", v))
202+
}
203+
attrs = append(attrs, a)
204+
}
205+
return attrs
111206
}

0 commit comments

Comments
 (0)