Skip to content

Commit

Permalink
feat: add otel support for ExtractSampledTraceID (#46)
Browse files Browse the repository at this point in the history
Signed-off-by: Juraci Paixão Kröhling <[email protected]>
Co-authored-by: Juraci Paixão Kröhling <[email protected]>
  • Loading branch information
leveyjam and jpkrohling authored Jun 28, 2023
1 parent b4f5c5d commit fe211cd
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 18 deletions.
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ require (
github.com/prometheus/common v0.42.0
github.com/prometheus/prometheus v1.8.2-0.20220620125440-d7e7b8e04b5e
github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b
github.com/stretchr/testify v1.8.2
github.com/stretchr/testify v1.8.3
github.com/uber/jaeger-client-go v2.30.0+incompatible
github.com/uber/jaeger-lib v2.4.1+incompatible
github.com/weaveworks/common v0.0.0-20230119144549-0aaa5abd1e63
Expand Down Expand Up @@ -55,7 +55,7 @@ require (
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
github.com/fatih/color v1.14.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.20.3 // indirect
Expand Down Expand Up @@ -129,7 +129,10 @@ require (
go.opentelemetry.io/collector/semconv v0.73.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/bridge/opentracing v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect
go.opentelemetry.io/otel/metric v0.37.0 // indirect
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/goleak v1.2.1 // indirect
Expand Down
18 changes: 18 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY=
Expand Down Expand Up @@ -666,6 +668,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/thanos-io/objstore v0.0.0-20230201072718-11ffbc490204 h1:W4w5Iph7j32Sf1QFWLJDCqvO0WgZS0jHGID+qnq3wV0=
github.com/thanos-io/objstore v0.0.0-20230201072718-11ffbc490204/go.mod h1:STSgpY8M6EKF2G/raUFdbIMf2U9GgYlEjAEHJxjvpAo=
github.com/themihai/gomemcache v0.0.0-20180902122335-24332e2d58ab h1:7ZR3hmisBWw77ZpO1/o86g+JV3VKlk3d48jopJxzTjU=
Expand Down Expand Up @@ -728,10 +732,24 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 h1:lE9EJyw
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0/go.mod h1:pcQ3MM3SWvrA71U4GDqv9UFDJ3HQsW7y5ZO3tDTlUdI=
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
go.opentelemetry.io/otel/bridge/opentracing v1.14.0 h1:IHlyjkJCOJQdX70C4r7PXm4LCMmGfGVsU/54KDVCtVI=
go.opentelemetry.io/otel/bridge/opentracing v1.14.0/go.mod h1:9cMHS7NzQ0vKwnrhN2CDXqLKI57TUyl9qLUiGBR/JmU=
go.opentelemetry.io/otel/bridge/opentracing v1.16.0 h1:Bgwi7P5NCV3bv2T13bwG0WfsxaT4SjQ1rDdmFc5P7do=
go.opentelemetry.io/otel/bridge/opentracing v1.16.0/go.mod h1:X2Y6v3RnoiBGtVFd4KoHy/ftHiCJKJXzlv6W2gPsN1Q=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 h1:sEL90JjOO/4yhquXl5zTAkLLsZ5+MycAgX99SDsxGc8=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0/go.mod h1:oCslUcizYdpKYyS9e8srZEqM6BB8fq41VJBjLAE6z1w=
go.opentelemetry.io/otel/metric v0.37.0 h1:pHDQuLQOZwYD+Km0eb657A25NaRzy0a+eLyKfDXedEs=
go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s=
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
Expand Down
33 changes: 17 additions & 16 deletions pkg/server/middleware/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"

opentracing "github.com/opentracing/opentracing-go"
"go.opentelemetry.io/otel/trace"

"github.com/opentracing-contrib/go-stdlib/nethttp"
jaeger "github.com/uber/jaeger-client-go"
Expand Down Expand Up @@ -43,29 +44,29 @@ func (t Tracer) Wrap(next http.Handler) http.Handler {

// ExtractTraceID extracts the trace id, if any from the context.
func ExtractTraceID(ctx context.Context) (string, bool) {
sp := opentracing.SpanFromContext(ctx)
if sp == nil {
return "", false
}
sctx, ok := sp.Context().(jaeger.SpanContext)
if !ok {
return "", false
}

return sctx.TraceID().String(), true
traceID, _ := ExtractSampledTraceID(ctx)
return traceID, traceID != ""
}

// ExtractSampledTraceID works like ExtractTraceID but the returned bool is only
// true if the returned trace id is sampled.
func ExtractSampledTraceID(ctx context.Context) (string, bool) {
// the most common case, where jaeger and opentracing is used
sp := opentracing.SpanFromContext(ctx)
if sp == nil {
return "", false
if sp != nil {
sctx, ok := sp.Context().(jaeger.SpanContext)
if ok {
return sctx.TraceID().String(), sctx.IsSampled()
}
}
sctx, ok := sp.Context().(jaeger.SpanContext)
if !ok {
return "", false

// opentelemetry with and without the bridge
otelSp := trace.SpanFromContext(ctx)
traceID, sampled := otelSp.SpanContext().TraceID(), otelSp.SpanContext().IsSampled()
if traceID.IsValid() { // when noop span is used, the traceID is not valid
return traceID.String(), sampled
}

return sctx.TraceID().String(), sctx.IsSampled()
// when nothing is in the context
return "", false
}
129 changes: 129 additions & 0 deletions pkg/server/middleware/tracer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package middleware

import (
"context"
"go.opentelemetry.io/otel/trace"
"testing"

opentracing "github.com/opentracing/opentracing-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/uber/jaeger-client-go"
"github.com/uber/jaeger-client-go/config"
"go.opentelemetry.io/otel"
bridge "go.opentelemetry.io/otel/bridge/opentracing"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

func TestExtractSampledTraceID(t *testing.T) {
testCases := []struct {
desc string
ctx func(*testing.T) (context.Context, func())
empty bool
}{
{
desc: "OpenTracing with Jaeger",
ctx: getContextWithOpenTracing,
},
{
desc: "OpenTelemetry",
ctx: getContextWithOpenTelemetry,
},
{
desc: "OpenTelemetry with the OpentTracing bridge",
ctx: getContextWithOpenTelemetryWithBridge,
},
{
desc: "No tracer",
ctx: func(_ *testing.T) (context.Context, func()) {
return context.Background(), func() {}
},
empty: true,
},
{
desc: "OpenTelemetry with the noop",
ctx: getContextWithOpenTelemetryNoop,
empty: true,
},
}
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
ctx, closer := tC.ctx(t)
defer closer()
// test contract of ExtractSampledTraceID
sampledTraceID, sampled := ExtractSampledTraceID(ctx)
traceID, ok := ExtractTraceID(ctx)

assert.Equal(t, sampledTraceID, traceID, "Expected sampledTraceID to equal traceID")
if tC.empty {
assert.Empty(t, traceID, "Expected traceID to be empty")
assert.False(t, sampled, "Expected sampled to be false")
assert.False(t, ok, "Expected ok to be false")
} else {
assert.NotEmpty(t, traceID, "Expected traceID to be non-empty")
assert.True(t, sampled, "Expected sampled to be true")
assert.True(t, ok, "Expected ok to be true")
}
})
}
}

func getContextWithOpenTracing(t *testing.T) (context.Context, func()) {
jCfg, err := config.FromEnv()
require.NoError(t, err)

jCfg.ServiceName = "test"
jCfg.Sampler.Options = append(jCfg.Sampler.Options, jaeger.SamplerOptions.InitialSampler(jaeger.NewConstSampler(true)))

tracer, closer, err := jCfg.NewTracer()
require.NoError(t, err)

opentracing.SetGlobalTracer(tracer)

sp := opentracing.GlobalTracer().StartSpan("test")
return opentracing.ContextWithSpan(context.Background(), sp), func() {
sp.Finish()
closer.Close()
}
}

func getContextWithOpenTelemetryWithBridge(t *testing.T) (context.Context, func()) {
previous := otel.GetTracerProvider()
tp := sdktrace.NewTracerProvider()
otel.SetTracerProvider(tp)

tr := tp.Tracer("test")

otTracer, _ := bridge.NewTracerPair(tr)
opentracing.SetGlobalTracer(otTracer)

sp := opentracing.GlobalTracer().StartSpan("test")
return opentracing.ContextWithSpan(context.Background(), sp), func() {
sp.Finish()
otel.SetTracerProvider(previous)
}
}

func getContextWithOpenTelemetry(t *testing.T) (context.Context, func()) {
previous := otel.GetTracerProvider()
tp := sdktrace.NewTracerProvider()
otel.SetTracerProvider(tp)

tr := tp.Tracer("test")
ctx, sp := tr.Start(context.Background(), "test")
return ctx, func() {
sp.End()
otel.SetTracerProvider(previous)
}
}

func getContextWithOpenTelemetryNoop(t *testing.T) (context.Context, func()) {
ctx, sp := trace.NewNoopTracerProvider().Tracer("test").Start(context.Background(), "test")

// sanity check
require.False(t, sp.SpanContext().TraceID().IsValid())

return ctx, func() {
sp.End()
}
}

0 comments on commit fe211cd

Please sign in to comment.