From 247982bda05f4a1a1fb96961096e77bf34cd80e1 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Fri, 17 Jan 2025 16:14:34 -0800 Subject: [PATCH] Run tests against Go. This one differs specifically because we don't run automatic instrumentation in the typical dd-trace-go setup, so the user is expected to set the default propagator. This test simply tests that using the API `otel.GetTextMapPropagator()` works as expected --- manifests/golang.yml | 3 + .../build/docker/golang/app/net-http/main.go | 112 ++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/manifests/golang.yml b/manifests/golang.yml index 49cbe414b1..57bd0f6292 100644 --- a/manifests/golang.yml +++ b/manifests/golang.yml @@ -509,6 +509,9 @@ tests/: Test_AWS_API_Gateway_Inferred_Span_Creation: missing_feature test_otel_drop_in.py: Test_Otel_Drop_In: missing_feature + Test_Otel_Drop_In_Default_Propagator: + '*': irrelevant + net-http: v1.70.1 parametric/: test_config_consistency.py: Test_Config_Dogstatsd: missing_feature diff --git a/utils/build/docker/golang/app/net-http/main.go b/utils/build/docker/golang/app/net-http/main.go index ebbfd3dff2..497d05f01e 100644 --- a/utils/build/docker/golang/app/net-http/main.go +++ b/utils/build/docker/golang/app/net-http/main.go @@ -32,6 +32,7 @@ import ( "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" oteltrace "go.opentelemetry.io/otel/trace" + otelbaggage "go.opentelemetry.io/otel/baggage" "gopkg.in/DataDog/dd-trace-go.v1/appsec" httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http" @@ -537,6 +538,79 @@ func main() { w.Write([]byte("ok")) }) + mux.HandleFunc("/otel_drop_in_default_propagator_extract", func(w http.ResponseWriter, r *http.Request) { + // Differing from other languages, the user must set the text map propagator because dd-trace-go + // doesn't automatically instrument at runtime (not including Orchestrion) + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) + + httpCarrier := HttpCarrier{header: r.Header} + + propagator := otel.GetTextMapPropagator() + ctx := propagator.Extract(r.Context(), httpCarrier) + + spanContext := oteltrace.SpanContextFromContext(ctx) + baggage := otelbaggage.FromContext(ctx) + + base := 16 + bitSize := 64 + result := make(map[string]any, 4) + + num, err := strconv.ParseInt(spanContext.TraceID().String()[16:], base, bitSize) + if err == nil { + result["trace_id"] = num + } + + num, err = strconv.ParseInt(spanContext.SpanID().String(), base, bitSize) + if err == nil { + result["span_id"] = num + } + + result["tracestate"] = spanContext.TraceState().String() + result["baggage"] = baggage.String() + + jsonData, err := json.Marshal(result) + if err != nil { + w.WriteHeader(422) + w.Write([]byte("failed to convert carrier to JSON")) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + w.Write(jsonData) + }) + + mux.HandleFunc("/otel_drop_in_default_propagator_inject", func(w http.ResponseWriter, r *http.Request) { + // Differing from other languages, the user must set the text map propagator because dd-trace-go + // doesn't automatically instrument at runtime (not including Orchestrion) + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) + + ctx := context.Background() + p := ddotel.NewTracerProvider() + tracer := p.Tracer("") + otel.SetTracerProvider(p) + + _, span := tracer.Start(ddotel.ContextWithStartOptions(ctx), "main") + newCtx := oteltrace.ContextWithSpan(ctx, span) + + propagator := otel.GetTextMapPropagator() + mapCarrier := make(MapCarrier) + propagator.Inject(newCtx, mapCarrier) + + jsonData, err := json.Marshal(mapCarrier) + span.End() + + if err != nil { + w.WriteHeader(422) + w.Write([]byte("failed to convert carrier to JSON")) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + w.Write(jsonData) + }) + mux.HandleFunc("/session/new", func(w http.ResponseWriter, r *http.Request) { sessionID := strconv.Itoa(rand.Int()) w.Header().Add("Set-Cookie", "session="+sessionID+"; Path=/; Max-Age=3600; Secure; HttpOnly") @@ -598,6 +672,44 @@ func (c carrier) ForeachKey(handler func(key, val string) error) error { return nil } +type MapCarrier map[string]string + +func (c MapCarrier) Get(key string) string { + return c[key] +} + +func (c MapCarrier) Set(key, val string) { + c[key] = val +} + +func (c MapCarrier) Keys() []string { + keys := make([]string, 0, len(c)) + for k := range c { + keys = append(keys, k) + } + return keys +} + +type HttpCarrier struct { + header http.Header +} + +func (c HttpCarrier) Get(key string) string { + return c.header.Get(key) +} + +func (c HttpCarrier) Set(key, val string) { + c.header.Set(key, val) +} + +func (c HttpCarrier) Keys() []string { + keys := make([]string, 0, len(c.header)) + for k := range c.header { + keys = append(keys, k) + } + return keys +} + func write(w http.ResponseWriter, r *http.Request, d []byte) { span, _ := ddtracer.StartSpanFromContext(r.Context(), "child.span") defer span.Finish()