From 1ff2e71e7d43c652f505b0680f8550ef0c863233 Mon Sep 17 00:00:00 2001 From: Damien Mathieu <42@dmathieu.com> Date: Mon, 15 Apr 2024 16:33:25 +0200 Subject: [PATCH] Add span flags to OTLP exported data (#5194) * add trace flags to OTLP export * add changelog entry * add span flags to links too * rely on the parent span context for span flags * test BuildSpanFlags, not with an actual span * Update exporters/otlp/otlptrace/internal/tracetransform/span.go Co-authored-by: Tyler Yahn --------- Co-authored-by: Tyler Yahn Co-authored-by: Chester Cheung --- CHANGELOG.md | 1 + .../otlptrace/internal/tracetransform/span.go | 13 ++++++++++ .../internal/tracetransform/span_test.go | 26 +++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0611a13cecc..d42a24eb9a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Added - Add `Recorder` in `go.opentelemetry.io/otel/log/logtest` to facilitate testing the log bridge implementations. (#5134) +- Add span flags to OTLP spans and links exported by `go.opentelemetry.io/otel/exporters/otlp/otlptrace`. (#5194) ### Changed diff --git a/exporters/otlp/otlptrace/internal/tracetransform/span.go b/exporters/otlp/otlptrace/internal/tracetransform/span.go index e03bf46a5ad..c3c69c5a0d6 100644 --- a/exporters/otlp/otlptrace/internal/tracetransform/span.go +++ b/exporters/otlp/otlptrace/internal/tracetransform/span.go @@ -110,6 +110,7 @@ func span(sd tracesdk.ReadOnlySpan) *tracepb.Span { if psid := sd.Parent().SpanID(); psid.IsValid() { s.ParentSpanId = psid[:] } + s.Flags = buildSpanFlags(sd.Parent()) return s } @@ -146,16 +147,28 @@ func links(links []tracesdk.Link) []*tracepb.Span_Link { tid := otLink.SpanContext.TraceID() sid := otLink.SpanContext.SpanID() + flags := buildSpanFlags(otLink.SpanContext) + sl = append(sl, &tracepb.Span_Link{ TraceId: tid[:], SpanId: sid[:], Attributes: KeyValues(otLink.Attributes), DroppedAttributesCount: uint32(otLink.DroppedAttributeCount), + Flags: flags, }) } return sl } +func buildSpanFlags(sc trace.SpanContext) uint32 { + flags := tracepb.SpanFlags_SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK + if sc.IsRemote() { + flags |= tracepb.SpanFlags_SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK + } + + return uint32(flags) +} + // spanEvents transforms span Events to an OTLP span events. func spanEvents(es []tracesdk.Event) []*tracepb.Span_Event { if len(es) == 0 { diff --git a/exporters/otlp/otlptrace/internal/tracetransform/span_test.go b/exporters/otlp/otlptrace/internal/tracetransform/span_test.go index f22ebab7b77..ef2a87ca66a 100644 --- a/exporters/otlp/otlptrace/internal/tracetransform/span_test.go +++ b/exporters/otlp/otlptrace/internal/tracetransform/span_test.go @@ -122,6 +122,7 @@ func TestLinks(t *testing.T) { TraceId: []uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, SpanId: []uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, DroppedAttributesCount: 3, + Flags: 0x100, } assert.Equal(t, expected, got[0]) @@ -166,6 +167,30 @@ func TestStatus(t *testing.T) { } } +func TestBuildSpanFlags(t *testing.T) { + for _, tt := range []struct { + name string + spanContext trace.SpanContext + wantFlags uint32 + }{ + { + name: "with an empty span context", + wantFlags: 0x100, + }, + { + name: "with a remote span context", + spanContext: trace.NewSpanContext(trace.SpanContextConfig{ + Remote: true, + }), + wantFlags: 0x300, + }, + } { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.wantFlags, buildSpanFlags(tt.spanContext)) + }) + } +} + func TestNilSpan(t *testing.T) { assert.Nil(t, span(nil)) } @@ -270,6 +295,7 @@ func TestSpanData(t *testing.T) { SpanId: []byte{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8}, ParentSpanId: []byte{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8}, TraceState: "key1=val1,key2=val2", + Flags: 0x300, Name: spanData.Name, Kind: tracepb.Span_SPAN_KIND_SERVER, StartTimeUnixNano: uint64(startTime.UnixNano()),