Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

- Fix missing `request.GetBody` in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` to correctly handle HTTP2 GOAWAY frame. (#7931)
- Fix semconv v1.39.0 generated metric helpers skipping required attributes when extra attributes were empty. (#7964)
- Preserve W3C TraceFlags bitmask (including the random Trace ID flag) during trace context extraction and injection in `go.opentelemetry.io/otel/propagation`. (#7834)

### Removed

Expand Down
13 changes: 6 additions & 7 deletions propagation/trace_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ func (TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) {
carrier.Set(tracestateHeader, ts)
}

// Clear all flags other than the trace-context supported sampling bit.
Comment thread
dashpole marked this conversation as resolved.
flags := sc.TraceFlags() & trace.FlagsSampled
// Preserve only the spec-defined flags: sampled (0x01) and random (0x02).
flags := sc.TraceFlags() & (trace.FlagsSampled | trace.FlagsRandom)

var sb strings.Builder
sb.Grow(2 + 32 + 16 + 2 + 3)
Expand Down Expand Up @@ -104,14 +104,13 @@ func (TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
if !extractPart(opts[:], &h, 2) {
return trace.SpanContext{}
}
if version == 0 && (h != "" || opts[0] > 2) {
Comment thread
nikhilmantri0902 marked this conversation as resolved.
// version 0 not allow extra
// version 0 not allow other flag
if version == 0 && (h != "" || opts[0] > 3) {
// version 0 does not allow extra fields or reserved flag bits.
return trace.SpanContext{}
}

// Clear all flags other than the trace-context supported sampling bit.
scc.TraceFlags = trace.TraceFlags(opts[0]) & trace.FlagsSampled // nolint:gosec // slice size already checked.
scc.TraceFlags = trace.TraceFlags(opts[0]) & //nolint:gosec // slice size already checked.
(trace.FlagsSampled | trace.FlagsRandom)

// Ignore the error returned here. Failure to parse tracestate MUST NOT
// affect the parsing of traceparent according to the W3C tracecontext
Expand Down
70 changes: 61 additions & 9 deletions propagation/trace_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,30 @@ func TestExtractValidTraceContext(t *testing.T) {
Remote: true,
}),
},
{
name: "random",
header: http.Header{
traceparent: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-02"},
},
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.TraceFlags(0x02),
Remote: true,
}),
},
{
name: "sampled and random",
header: http.Header{
traceparent: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-03"},
},
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.TraceFlags(0x03),
Remote: true,
}),
},
{
name: "valid tracestate",
header: http.Header{
Expand Down Expand Up @@ -105,7 +129,7 @@ func TestExtractValidTraceContext(t *testing.T) {
}),
},
{
name: "future version sample bit set",
name: "future version sample bit set reserved bits zeroed",
header: http.Header{
traceparent: []string{"02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09"},
},
Expand All @@ -117,7 +141,7 @@ func TestExtractValidTraceContext(t *testing.T) {
}),
},
{
name: "future version sample bit not set",
name: "future version reserved bits zeroed",
header: http.Header{
traceparent: []string{"02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08"},
},
Expand Down Expand Up @@ -228,10 +252,6 @@ func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
name: "zero trace ID and span ID",
header: "00-00000000000000000000000000000000-0000000000000000-01",
},
{
name: "trace-flag unused bits set",
header: "00-ab000000000000000000000000000000-cd00000000000000-09",
},
{
name: "missing options",
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
Expand All @@ -240,6 +260,14 @@ func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
name: "empty options",
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
},
{
name: "version 0 reserved trace flag bits set",
header: "00-ab000000000000000000000000000000-cd00000000000000-09",
},
{
name: "version 0 with extra content",
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01-extra",
},
}

empty := trace.SpanContext{}
Expand Down Expand Up @@ -287,14 +315,38 @@ func TestInjectValidTraceContext(t *testing.T) {
}),
},
{
name: "unsupported trace flag bits dropped",
name: "reserved trace flag bits dropped on inject",
header: http.Header{
traceparent: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"},
traceparent: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-03"},
},
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.TraceFlags(0xff),
Remote: true,
}),
},
{
name: "random",
header: http.Header{
traceparent: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-02"},
},
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.TraceFlags(0x02),
Remote: true,
}),
},
{
name: "sampled and random",
header: http.Header{
traceparent: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-03"},
},
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: 0xff,
TraceFlags: trace.TraceFlags(0x03),
Remote: true,
}),
},
Expand Down
5 changes: 5 additions & 0 deletions trace/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ const (
// with the sampling bit set means the span is sampled.
FlagsSampled = TraceFlags(0x01)

// FlagsRandom is a bitmask with the random trace ID flag set. When
// set, it signals that the trace ID was generated randomly with at
// least 56 bits of randomness (W3C Trace Context Level 2).
FlagsRandom = TraceFlags(0x02)

errInvalidHexID errorConst = "trace-id and span-id can only contain [0-9a-f] characters, all lowercase"

errInvalidTraceIDLength errorConst = "hex encoded trace-id must have length equals to 32"
Expand Down
Loading