diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index 723c81e61d4..40731931f75 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -6,6 +6,9 @@ ([#1415](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1415)) * Removed `IsOk` property from `Status` and fixed `StatusCode` enum values ([#1414](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1414)) +* `B3Propagator` now supports the value `true` to be passed in for the header + `X-B3-Sampled`. + ([#1413](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1413)) ## 0.7.0-beta.1 diff --git a/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs b/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs index 0b30c32c4f6..73f7677f19e 100644 --- a/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs +++ b/src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs @@ -40,14 +40,19 @@ public sealed class B3Propagator : IPropagator // ActivityTraceId.SIZE hex characters (8-bytes traceId) in the past. internal const string UpperTraceId = "0000000000000000"; - // Sampled value via the X_B3_SAMPLED header. + // Sampled values via the X_B3_SAMPLED header. internal const string SampledValue = "1"; + // Some old zipkin implementations may send true/false for the sampled header. Only use this for checking incoming values. + internal const string LegacySampledValue = "true"; + // "Debug" sampled value. internal const string FlagsValue = "1"; private static readonly HashSet AllFields = new HashSet() { XB3TraceId, XB3SpanId, XB3ParentSpanId, XB3Sampled, XB3Flags }; + private static readonly HashSet SampledValues = new HashSet(StringComparer.Ordinal) { SampledValue, LegacySampledValue }; + private readonly bool singleHeader; /// @@ -180,7 +185,7 @@ private static PropagationContext ExtractFromMultipleHeaders(PropagationConte } var traceOptions = ActivityTraceFlags.None; - if (SampledValue.Equals(getter(carrier, XB3Sampled)?.FirstOrDefault(), StringComparison.Ordinal) + if (SampledValues.Contains(getter(carrier, XB3Sampled)?.FirstOrDefault()) || FlagsValue.Equals(getter(carrier, XB3Flags)?.FirstOrDefault(), StringComparison.Ordinal)) { traceOptions |= ActivityTraceFlags.Recorded; @@ -239,7 +244,7 @@ private static PropagationContext ExtractFromSingleHeader(PropagationContext if (parts.Length > 2) { var traceFlagsStr = parts[2]; - if (SampledValue.Equals(traceFlagsStr, StringComparison.Ordinal) + if (SampledValues.Contains(traceFlagsStr) || FlagsValue.Equals(traceFlagsStr, StringComparison.Ordinal)) { traceOptions |= ActivityTraceFlags.Recorded; diff --git a/test/OpenTelemetry.Tests/Trace/Propagation/B3PropagatorTest.cs b/test/OpenTelemetry.Tests/Trace/Propagation/B3PropagatorTest.cs index e24b9ae2da9..fb430b6f1b0 100644 --- a/test/OpenTelemetry.Tests/Trace/Propagation/B3PropagatorTest.cs +++ b/test/OpenTelemetry.Tests/Trace/Propagation/B3PropagatorTest.cs @@ -81,23 +81,28 @@ public void ParseMissingSampledAndMissingFlag() Assert.Equal(new PropagationContext(spanContext, default), this.b3propagator.Extract(default, headersNotSampled, Getter)); } - [Fact] - public void ParseSampled() + [Theory] + [InlineData("1")] + [InlineData("true")] + public void ParseSampled(string sampledValue) { var headersSampled = new Dictionary { - { B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, SpanIdBase16 }, { B3Propagator.XB3Sampled, "1" }, + { B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, SpanIdBase16 }, { B3Propagator.XB3Sampled, sampledValue }, }; var activityContext = new ActivityContext(TraceId, SpanId, TraceOptions, isRemote: true); Assert.Equal(new PropagationContext(activityContext, default), this.b3propagator.Extract(default, headersSampled, Getter)); } - [Fact] - public void ParseZeroSampled() + [Theory] + [InlineData("0")] + [InlineData("false")] + [InlineData("something_else")] + public void ParseNotSampled(string sampledValue) { var headersNotSampled = new Dictionary { - { B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, SpanIdBase16 }, { B3Propagator.XB3Sampled, "0" }, + { B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, SpanIdBase16 }, { B3Propagator.XB3Sampled, sampledValue }, }; var activityContext = new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None, isRemote: true); Assert.Equal(new PropagationContext(activityContext, default), this.b3propagator.Extract(default, headersNotSampled, Getter));