diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md
index e9511d1e8e1..db15d7b076d 100644
--- a/src/OpenTelemetry.Api/CHANGELOG.md
+++ b/src/OpenTelemetry.Api/CHANGELOG.md
@@ -16,6 +16,10 @@ changed to match the
gets removed.
([#954](https://github.com/open-telemetry/opentelemetry-dotnet/pull/954)).
* HttpStatusCode in all spans attribute (http.status_code) to use int value.
+* `ITextFormatActivity` got replaced by `ITextFormat` with an additional method
+ to be implemented (`IsInjected`)
+* Added `CompositePropagator` that accepts a list of `ITextFormat` following
+ [specification](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/context/api-propagators.md#create-a-composite-propagator)
## 0.4.0-beta.2
diff --git a/src/OpenTelemetry.Api/Context/Propagation/CompositePropagator.cs b/src/OpenTelemetry.Api/Context/Propagation/CompositePropagator.cs
new file mode 100644
index 00000000000..ef69bca4490
--- /dev/null
+++ b/src/OpenTelemetry.Api/Context/Propagation/CompositePropagator.cs
@@ -0,0 +1,74 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+
+namespace OpenTelemetry.Context.Propagation
+{
+ ///
+ /// CompositePropagator provides a mechanism for combining multiple propagators into a single one.
+ ///
+ public class CompositePropagator : ITextFormat
+ {
+ private static readonly ISet EmptyFields = new HashSet();
+ private readonly List textFormats;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// List of wire context propagator.
+ public CompositePropagator(List textFormats)
+ {
+ this.textFormats = textFormats ?? throw new ArgumentNullException(nameof(textFormats));
+ }
+
+ ///
+ public ISet Fields => EmptyFields;
+
+ ///
+ public ActivityContext Extract(ActivityContext activityContext, T carrier, Func> getter)
+ {
+ foreach (var textFormat in this.textFormats)
+ {
+ activityContext = textFormat.Extract(activityContext, carrier, getter);
+ if (activityContext.IsValid())
+ {
+ return activityContext;
+ }
+ }
+
+ return activityContext;
+ }
+
+ ///
+ public void Inject(ActivityContext activityContext, T carrier, Action setter)
+ {
+ foreach (var textFormat in this.textFormats)
+ {
+ textFormat.Inject(activityContext, carrier, setter);
+ }
+ }
+
+ ///
+ public bool IsInjected(T carrier, Func> getter)
+ {
+ return this.textFormats.All(textFormat => textFormat.IsInjected(carrier, getter));
+ }
+ }
+}
diff --git a/src/OpenTelemetry.Api/Context/Propagation/ITextFormat.cs b/src/OpenTelemetry.Api/Context/Propagation/ITextFormat.cs
index ca35d32a7d0..135a246412b 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/ITextFormat.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/ITextFormat.cs
@@ -45,10 +45,11 @@ public interface ITextFormat
/// Extracts activity context from textual representation.
///
/// Type of object to extract context from. Typically HttpRequest or similar.
+ /// The default activity context to be used if Extract fails.
/// Object to extract context from. Instance of this object will be passed to the getter.
/// Function that will return string value of a key with the specified name.
/// Activity context from it's text representation.
- ActivityContext Extract(T carrier, Func> getter);
+ ActivityContext Extract(ActivityContext activityContext, T carrier, Func> getter);
///
/// Tests if an activity context has been injected into a carrier.
diff --git a/src/OpenTelemetry.Api/Context/Propagation/TraceContextFormat.cs b/src/OpenTelemetry.Api/Context/Propagation/TraceContextFormat.cs
index ed0c53a79bb..ee1525aa573 100644
--- a/src/OpenTelemetry.Api/Context/Propagation/TraceContextFormat.cs
+++ b/src/OpenTelemetry.Api/Context/Propagation/TraceContextFormat.cs
@@ -30,7 +30,6 @@ public class TraceContextFormat : ITextFormat
private const string TraceParent = "traceparent";
private const string TraceState = "tracestate";
- private static readonly int VersionLength = "00".Length;
private static readonly int VersionPrefixIdLength = "00-".Length;
private static readonly int TraceIdLength = "0af7651916cd43dd8448eb211c80319c".Length;
private static readonly int VersionAndTraceIdLength = "00-0af7651916cd43dd8448eb211c80319c-".Length;
@@ -74,18 +73,18 @@ public bool IsInjected(T carrier, Func> getter
}
///
- public ActivityContext Extract(T carrier, Func> getter)
+ public ActivityContext Extract(ActivityContext activityContext, T carrier, Func> getter)
{
if (carrier == null)
{
OpenTelemetryApiEventSource.Log.FailedToInjectActivityContext("null carrier");
- return default;
+ return activityContext;
}
if (getter == null)
{
OpenTelemetryApiEventSource.Log.FailedToExtractContext("null getter");
- return default;
+ return activityContext;
}
try
@@ -95,22 +94,22 @@ public ActivityContext Extract(T carrier, Func
// There must be a single traceparent
if (traceparentCollection == null || traceparentCollection.Count() != 1)
{
- return default;
+ return activityContext;
}
var traceparent = traceparentCollection.First();
- var traceparentParsed = this.TryExtractTraceparent(traceparent, out var traceId, out var spanId, out var traceoptions);
+ var traceparentParsed = TryExtractTraceparent(traceparent, out var traceId, out var spanId, out var traceoptions);
if (!traceparentParsed)
{
- return default;
+ return activityContext;
}
- string tracestate = null;
+ string tracestate = string.Empty;
var tracestateCollection = getter(carrier, TraceState);
- if (tracestateCollection != null)
+ if (tracestateCollection?.Any() ?? false)
{
- this.TryExtractTracestate(tracestateCollection.ToArray(), out tracestate);
+ TryExtractTracestate(tracestateCollection.ToArray(), out tracestate);
}
return new ActivityContext(traceId, spanId, traceoptions, tracestate, isRemote: true);
@@ -121,7 +120,7 @@ public ActivityContext Extract(T carrier, Func
}
// in case of exception indicate to upstream that there is no parseable context from the top
- return default;
+ return activityContext;
}
///
@@ -157,7 +156,7 @@ public void Inject(ActivityContext activityContext, T carrier, Action= '0') && (c <= '9'))
- {
- return (byte)(c - '0');
- }
-
- if ((c >= 'a') && (c <= 'f'))
- {
- return (byte)(c - 'a' + 10);
- }
-
- if ((c >= 'A') && (c <= 'F'))
- {
- return (byte)(c - 'A' + 10);
- }
-
- throw new ArgumentOutOfRangeException(nameof(c), $"Invalid character: {c}.");
- }
-
- private bool TryExtractTracestate(string[] tracestateCollection, out string tracestateResult)
+ internal static bool TryExtractTracestate(string[] tracestateCollection, out string tracestateResult)
{
tracestateResult = string.Empty;
@@ -304,5 +283,17 @@ private bool TryExtractTracestate(string[] tracestateCollection, out string trac
return true;
}
+
+ private static byte HexCharToByte(char c)
+ {
+ if (((c >= '0') && (c <= '9'))
+ || ((c >= 'a') && (c <= 'f'))
+ || ((c >= 'A') && (c <= 'F')))
+ {
+ return Convert.ToByte(c);
+ }
+
+ throw new ArgumentOutOfRangeException(nameof(c), $"Invalid character: {c}.");
+ }
}
}
diff --git a/src/OpenTelemetry.Api/Trace/SpanContext.cs b/src/OpenTelemetry.Api/Trace/SpanContext.cs
index 895b3fc759e..b1717e6762a 100644
--- a/src/OpenTelemetry.Api/Trace/SpanContext.cs
+++ b/src/OpenTelemetry.Api/Trace/SpanContext.cs
@@ -120,6 +120,12 @@ public IEnumerable> TraceState
}
}
+ ///
+ /// Converts a into an .
+ ///
+ /// source.
+ public static implicit operator ActivityContext(SpanContext spanContext) => spanContext.ActivityContext;
+
///
/// Compare two for equality.
///
diff --git a/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs b/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs
index 9c80344b06c..954ed844609 100644
--- a/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs
+++ b/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs
@@ -63,7 +63,7 @@ public override void OnStartActivity(Activity activity, object payload)
{
// This requires to ignore the current activity and create a new one
// using the context extracted using the format TextFormat supports.
- var ctx = this.options.TextFormat.Extract(request, HttpRequestHeaderValuesGetter);
+ var ctx = this.options.TextFormat.Extract(default, request, HttpRequestHeaderValuesGetter);
// Create a new activity with its parent set from the extracted context.
// This makes the new activity as a "sibling" of the activity created by
diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs
index 284f0fe2c35..15b1f65377a 100644
--- a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs
+++ b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs
@@ -50,9 +50,7 @@ public HttpInListener(string name, AspNetCoreInstrumentationOptions options, Act
public override void OnStartActivity(Activity activity, object payload)
{
- var context = this.startContextFetcher.Fetch(payload) as HttpContext;
-
- if (context == null)
+ if (!(this.startContextFetcher.Fetch(payload) is HttpContext context))
{
AspNetCoreInstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStartActivity));
return;
@@ -72,7 +70,7 @@ public override void OnStartActivity(Activity activity, object payload)
// using the context extracted from w3ctraceparent header or
// using the format TextFormat supports.
- var ctx = this.options.TextFormat.Extract(request, HttpRequestHeaderValuesGetter);
+ var ctx = this.options.TextFormat.Extract(default, request, HttpRequestHeaderValuesGetter);
// Create a new activity with its parent set from the extracted context.
// This makes the new activity as a "sibling" of the activity created by
diff --git a/src/OpenTelemetry.Shims.OpenTracing/TracerShim.cs b/src/OpenTelemetry.Shims.OpenTracing/TracerShim.cs
index 7227eb59f0a..a75ed3a5f1c 100644
--- a/src/OpenTelemetry.Shims.OpenTracing/TracerShim.cs
+++ b/src/OpenTelemetry.Shims.OpenTracing/TracerShim.cs
@@ -81,7 +81,7 @@ IEnumerable GetCarrierKeyValue(Dictionary> s
return value;
}
- activityContext = this.textFormat.Extract(carrierMap, GetCarrierKeyValue);
+ activityContext = this.textFormat.Extract(default, carrierMap, GetCarrierKeyValue);
}
return !activityContext.IsValid() ? null : new SpanContextShim(new Trace.SpanContext(activityContext));
@@ -115,8 +115,7 @@ public void Inject(
if ((format == BuiltinFormats.TextMap || format == BuiltinFormats.HttpHeaders) && carrier is ITextMap textMapCarrier)
{
- // Remove comment after spanshim changes
- // this.textFormat.Inject(shim.SpanContext, textMapCarrier, (instrumentation, key, value) => instrumentation.Set(key, value));
+ this.textFormat.Inject(shim.SpanContext, textMapCarrier, (instrumentation, key, value) => instrumentation.Set(key, value));
}
}
}
diff --git a/src/OpenTelemetry/Context/Propagation/B3Format.cs b/src/OpenTelemetry/Context/Propagation/B3Format.cs
index 261514a3394..8ec7513826d 100644
--- a/src/OpenTelemetry/Context/Propagation/B3Format.cs
+++ b/src/OpenTelemetry/Context/Propagation/B3Format.cs
@@ -107,27 +107,27 @@ public bool IsInjected(T carrier, Func> getter
}
///
- public ActivityContext Extract(T carrier, Func> getter)
+ public ActivityContext Extract(ActivityContext activityContext, T carrier, Func> getter)
{
if (carrier == null)
{
OpenTelemetrySdkEventSource.Log.FailedToExtractContext("null carrier");
- return default;
+ return activityContext;
}
if (getter == null)
{
OpenTelemetrySdkEventSource.Log.FailedToExtractContext("null getter");
- return default;
+ return activityContext;
}
if (this.singleHeader)
{
- return ExtractFromSingleHeader(carrier, getter);
+ return ExtractFromSingleHeader(activityContext, carrier, getter);
}
else
{
- return ExtractFromMultipleHeaders(carrier, getter);
+ return ExtractFromMultipleHeaders(activityContext, carrier, getter);
}
}
@@ -177,7 +177,7 @@ public void Inject(ActivityContext activityContext, T carrier, Action(T carrier, Func> getter)
+ private static ActivityContext ExtractFromMultipleHeaders(ActivityContext activityContext, T carrier, Func> getter)
{
try
{
@@ -195,7 +195,7 @@ private static ActivityContext ExtractFromMultipleHeaders(T carrier, Func(T carrier, Func(T carrier, Func(T carrier, Func> getter)
+ private static ActivityContext ExtractFromSingleHeader(ActivityContext activityContext, T carrier, Func> getter)
{
try
{
var header = getter(carrier, XB3Combined)?.FirstOrDefault();
if (string.IsNullOrWhiteSpace(header))
{
- return default;
+ return activityContext;
}
var parts = header.Split(XB3CombinedDelimiter);
if (parts.Length < 2 || parts.Length > 4)
{
- return default;
+ return activityContext;
}
var traceIdStr = parts[0];
if (string.IsNullOrWhiteSpace(traceIdStr))
{
- return default;
+ return activityContext;
}
if (traceIdStr.Length == 16)
@@ -258,7 +258,7 @@ private static ActivityContext ExtractFromSingleHeader(T carrier, Func(T carrier, Func();
- textFormat.Setup(m => m.Extract(It.IsAny(), It.IsAny>>())).Returns(new ActivityContext(
+ textFormat.Setup(m => m.Extract(It.IsAny(), It.IsAny(), It.IsAny>>())).Returns(new ActivityContext(
expectedTraceId,
expectedSpanId,
ActivityTraceFlags.Recorded));
diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs
index 918ed707d93..892fd0dc51c 100644
--- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs
+++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs
@@ -142,7 +142,7 @@ public async Task CustomTextFormat()
var expectedSpanId = ActivitySpanId.CreateRandom();
var textFormat = new Mock();
- textFormat.Setup(m => m.Extract(It.IsAny(), It.IsAny>>())).Returns(new ActivityContext(
+ textFormat.Setup(m => m.Extract(It.IsAny(), It.IsAny(), It.IsAny>>())).Returns(new ActivityContext(
expectedTraceId,
expectedSpanId,
ActivityTraceFlags.Recorded));
diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/TracerShimTests.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/TracerShimTests.cs
index 2bac270d93d..ad6ddaca3f9 100644
--- a/test/OpenTelemetry.Shims.OpenTracing.Tests/TracerShimTests.cs
+++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/TracerShimTests.cs
@@ -148,11 +148,9 @@ public void Extract_InvalidTraceParent()
Assert.Null(spanContextShim);
}
- [Fact(Skip = "Enable after actual spanshim")]
+ [Fact]
public void InjectExtract_TextMap_Ok()
{
- var tracerMock = new Mock();
-
var carrier = new TextMapCarrier();
var spanContextShim = new SpanContextShim(new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None));
diff --git a/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/B3FormatTest.cs b/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/B3FormatTest.cs
index c4075c7167e..0769b4596b2 100644
--- a/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/B3FormatTest.cs
+++ b/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/B3FormatTest.cs
@@ -78,7 +78,7 @@ public void ParseMissingSampledAndMissingFlag()
{ B3Format.XB3TraceId, TraceIdBase16 }, { B3Format.XB3SpanId, SpanIdBase16 },
};
var spanContext = new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None);
- Assert.Equal(spanContext, this.b3Format.Extract(headersNotSampled, Getter));
+ Assert.Equal(spanContext, this.b3Format.Extract(default, headersNotSampled, Getter));
}
[Fact]
@@ -88,7 +88,7 @@ public void ParseSampled()
{
{ B3Format.XB3TraceId, TraceIdBase16 }, { B3Format.XB3SpanId, SpanIdBase16 }, { B3Format.XB3Sampled, "1" },
};
- Assert.Equal(new ActivityContext(TraceId, SpanId, TraceOptions), this.b3Format.Extract(headersSampled, Getter));
+ Assert.Equal(new ActivityContext(TraceId, SpanId, TraceOptions), this.b3Format.Extract(default, headersSampled, Getter));
}
[Fact]
@@ -98,7 +98,7 @@ public void ParseZeroSampled()
{
{ B3Format.XB3TraceId, TraceIdBase16 }, { B3Format.XB3SpanId, SpanIdBase16 }, { B3Format.XB3Sampled, "0" },
};
- Assert.Equal(new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None), this.b3Format.Extract(headersNotSampled, Getter));
+ Assert.Equal(new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None), this.b3Format.Extract(default, headersNotSampled, Getter));
}
[Fact]
@@ -108,7 +108,7 @@ public void ParseFlag()
{
{ B3Format.XB3TraceId, TraceIdBase16 }, { B3Format.XB3SpanId, SpanIdBase16 }, { B3Format.XB3Flags, "1" },
};
- Assert.Equal(new ActivityContext(TraceId, SpanId, TraceOptions), this.b3Format.Extract(headersFlagSampled, Getter));
+ Assert.Equal(new ActivityContext(TraceId, SpanId, TraceOptions), this.b3Format.Extract(default, headersFlagSampled, Getter));
}
[Fact]
@@ -118,7 +118,7 @@ public void ParseZeroFlag()
{
{ B3Format.XB3TraceId, TraceIdBase16 }, { B3Format.XB3SpanId, SpanIdBase16 }, { B3Format.XB3Flags, "0" },
};
- Assert.Equal(new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None), this.b3Format.Extract(headersFlagNotSampled, Getter));
+ Assert.Equal(new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None), this.b3Format.Extract(default, headersFlagNotSampled, Getter));
}
[Fact]
@@ -130,7 +130,7 @@ public void ParseEightBytesTraceId()
{ B3Format.XB3SpanId, SpanIdBase16 },
{ B3Format.XB3Sampled, "1" },
};
- Assert.Equal(new ActivityContext(TraceIdEightBytes, SpanId, TraceOptions), this.b3Format.Extract(headersEightBytes, Getter));
+ Assert.Equal(new ActivityContext(TraceIdEightBytes, SpanId, TraceOptions), this.b3Format.Extract(default, headersEightBytes, Getter));
}
[Fact]
@@ -140,7 +140,7 @@ public void ParseEightBytesTraceId_NotSampledSpanContext()
{
{ B3Format.XB3TraceId, TraceIdBase16EightBytes }, { B3Format.XB3SpanId, SpanIdBase16 },
};
- Assert.Equal(new ActivityContext(TraceIdEightBytes, SpanId, ActivityTraceFlags.None), this.b3Format.Extract(headersEightBytes, Getter));
+ Assert.Equal(new ActivityContext(TraceIdEightBytes, SpanId, ActivityTraceFlags.None), this.b3Format.Extract(default, headersEightBytes, Getter));
}
[Fact]
@@ -150,7 +150,7 @@ public void ParseInvalidTraceId()
{
{ B3Format.XB3TraceId, InvalidId }, { B3Format.XB3SpanId, SpanIdBase16 },
};
- Assert.Equal(default, this.b3Format.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3Format.Extract(default, invalidHeaders, Getter));
}
[Fact]
@@ -161,14 +161,14 @@ public void ParseInvalidTraceId_Size()
{ B3Format.XB3TraceId, InvalidSizeId }, { B3Format.XB3SpanId, SpanIdBase16 },
};
- Assert.Equal(default, this.b3Format.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3Format.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseMissingTraceId()
{
var invalidHeaders = new Dictionary { { B3Format.XB3SpanId, SpanIdBase16 }, };
- Assert.Equal(default, this.b3Format.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3Format.Extract(default, invalidHeaders, Getter));
}
[Fact]
@@ -178,7 +178,7 @@ public void ParseInvalidSpanId()
{
{ B3Format.XB3TraceId, TraceIdBase16 }, { B3Format.XB3SpanId, InvalidId },
};
- Assert.Equal(default, this.b3Format.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3Format.Extract(default, invalidHeaders, Getter));
}
[Fact]
@@ -188,14 +188,14 @@ public void ParseInvalidSpanId_Size()
{
{ B3Format.XB3TraceId, TraceIdBase16 }, { B3Format.XB3SpanId, InvalidSizeId },
};
- Assert.Equal(default, this.b3Format.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3Format.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseMissingSpanId()
{
var invalidHeaders = new Dictionary { { B3Format.XB3TraceId, TraceIdBase16 } };
- Assert.Equal(default, this.b3Format.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3Format.Extract(default, invalidHeaders, Getter));
}
[Fact]
@@ -224,7 +224,7 @@ public void ParseMissingSampledAndMissingFlag_SingleHeader()
{ B3Format.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}" },
};
var spanContext = new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None);
- Assert.Equal(spanContext, this.b3FormatSingleHeader.Extract(headersNotSampled, Getter));
+ Assert.Equal(spanContext, this.b3FormatSingleHeader.Extract(default, headersNotSampled, Getter));
}
[Fact]
@@ -234,7 +234,7 @@ public void ParseSampled_SingleHeader()
{
{ B3Format.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}-1" },
};
- Assert.Equal(new ActivityContext(TraceId, SpanId, TraceOptions), this.b3FormatSingleHeader.Extract(headersSampled, Getter));
+ Assert.Equal(new ActivityContext(TraceId, SpanId, TraceOptions), this.b3FormatSingleHeader.Extract(default, headersSampled, Getter));
}
[Fact]
@@ -244,7 +244,7 @@ public void ParseZeroSampled_SingleHeader()
{
{ B3Format.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}-0" },
};
- Assert.Equal(new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None), this.b3FormatSingleHeader.Extract(headersNotSampled, Getter));
+ Assert.Equal(new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None), this.b3FormatSingleHeader.Extract(default, headersNotSampled, Getter));
}
[Fact]
@@ -254,7 +254,7 @@ public void ParseFlag_SingleHeader()
{
{ B3Format.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}-1" },
};
- Assert.Equal(new ActivityContext(TraceId, SpanId, TraceOptions), this.b3FormatSingleHeader.Extract(headersFlagSampled, Getter));
+ Assert.Equal(new ActivityContext(TraceId, SpanId, TraceOptions), this.b3FormatSingleHeader.Extract(default, headersFlagSampled, Getter));
}
[Fact]
@@ -264,7 +264,7 @@ public void ParseZeroFlag_SingleHeader()
{
{ B3Format.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}-0" },
};
- Assert.Equal(new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None), this.b3FormatSingleHeader.Extract(headersFlagNotSampled, Getter));
+ Assert.Equal(new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None), this.b3FormatSingleHeader.Extract(default, headersFlagNotSampled, Getter));
}
[Fact]
@@ -274,7 +274,7 @@ public void ParseEightBytesTraceId_SingleHeader()
{
{ B3Format.XB3Combined, $"{TraceIdBase16EightBytes}-{SpanIdBase16}-1" },
};
- Assert.Equal(new ActivityContext(TraceIdEightBytes, SpanId, TraceOptions), this.b3FormatSingleHeader.Extract(headersEightBytes, Getter));
+ Assert.Equal(new ActivityContext(TraceIdEightBytes, SpanId, TraceOptions), this.b3FormatSingleHeader.Extract(default, headersEightBytes, Getter));
}
[Fact]
@@ -284,7 +284,7 @@ public void ParseEightBytesTraceId_NotSampledSpanContext_SingleHeader()
{
{ B3Format.XB3Combined, $"{TraceIdBase16EightBytes}-{SpanIdBase16}" },
};
- Assert.Equal(new ActivityContext(TraceIdEightBytes, SpanId, ActivityTraceFlags.None), this.b3FormatSingleHeader.Extract(headersEightBytes, Getter));
+ Assert.Equal(new ActivityContext(TraceIdEightBytes, SpanId, ActivityTraceFlags.None), this.b3FormatSingleHeader.Extract(default, headersEightBytes, Getter));
}
[Fact]
@@ -294,7 +294,7 @@ public void ParseInvalidTraceId_SingleHeader()
{
{ B3Format.XB3Combined, $"{InvalidId}-{SpanIdBase16}" },
};
- Assert.Equal(default, this.b3FormatSingleHeader.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3FormatSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
@@ -305,14 +305,14 @@ public void ParseInvalidTraceId_Size_SingleHeader()
{ B3Format.XB3Combined, $"{InvalidSizeId}-{SpanIdBase16}" },
};
- Assert.Equal(default, this.b3FormatSingleHeader.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3FormatSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseMissingTraceId_SingleHeader()
{
var invalidHeaders = new Dictionary { { B3Format.XB3Combined, $"-{SpanIdBase16}" } };
- Assert.Equal(default, this.b3FormatSingleHeader.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3FormatSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
@@ -322,7 +322,7 @@ public void ParseInvalidSpanId_SingleHeader()
{
{ B3Format.XB3Combined, $"{TraceIdBase16}-{InvalidId}" },
};
- Assert.Equal(default, this.b3FormatSingleHeader.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3FormatSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
@@ -332,14 +332,14 @@ public void ParseInvalidSpanId_Size_SingleHeader()
{
{ B3Format.XB3Combined, $"{TraceIdBase16}-{InvalidSizeId}" },
};
- Assert.Equal(default, this.b3FormatSingleHeader.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3FormatSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseMissingSpanId_SingleHeader()
{
var invalidHeaders = new Dictionary { { B3Format.XB3Combined, $"{TraceIdBase16}-" } };
- Assert.Equal(default, this.b3FormatSingleHeader.Extract(invalidHeaders, Getter));
+ Assert.Equal(default, this.b3FormatSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
diff --git a/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/CompositePropagatorTest.cs b/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/CompositePropagatorTest.cs
new file mode 100644
index 00000000000..8e9d26131f0
--- /dev/null
+++ b/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/CompositePropagatorTest.cs
@@ -0,0 +1,110 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using OpenTelemetry.Context.Propagation;
+using Xunit;
+
+namespace OpenTelemetry.Tests.Implementation.Trace.Propagation
+{
+ public class CompositePropagatorTest
+ {
+ private const string TraceParent = "traceparent";
+ private static readonly string[] Empty = new string[0];
+ private static readonly Func, string, IEnumerable> Getter = (headers, name) =>
+ {
+ count++;
+ if (headers.TryGetValue(name, out var value))
+ {
+ return new[] { value };
+ }
+
+ return Empty;
+ };
+
+ private static readonly Action, string, string> Setter = (carrier, name, value) =>
+ {
+ carrier[name] = value;
+ };
+
+ private static int count = 0;
+
+ private readonly ActivityTraceId traceId = ActivityTraceId.CreateRandom();
+ private readonly ActivitySpanId spanId = ActivitySpanId.CreateRandom();
+
+ [Fact]
+ public void CompositePropagator_NullTextFormatList()
+ {
+ Assert.Throws(() => new CompositePropagator(null));
+ }
+
+ [Fact]
+ public void CompositePropagator_TestPropagator()
+ {
+ var compositePropagator = new CompositePropagator(new List
+ {
+ new TestPropagator("custom-traceparent-1", "custom-tracestate-1"),
+ new TestPropagator("custom-traceparent-2", "custom-tracestate-2"),
+ });
+
+ var activityContext = new ActivityContext(this.traceId, this.spanId, ActivityTraceFlags.Recorded, traceState: null);
+ var carrier = new Dictionary();
+
+ compositePropagator.Inject(activityContext, carrier, Setter);
+ Assert.Contains(carrier, kv => kv.Key == "custom-traceparent-1");
+ Assert.Contains(carrier, kv => kv.Key == "custom-traceparent-2");
+
+ bool isInjected = compositePropagator.IsInjected(carrier, Getter);
+ Assert.True(isInjected);
+ }
+
+ [Fact]
+ public void CompositePropagator_UsingSameTag()
+ {
+ const string header01 = "custom-tracestate-01";
+ const string header02 = "custom-tracestate-02";
+
+ var compositePropagator = new CompositePropagator(new List
+ {
+ new TestPropagator("custom-traceparent", header01, true),
+ new TestPropagator("custom-traceparent", header02),
+ });
+
+ var activityContext = new ActivityContext(this.traceId, this.spanId, ActivityTraceFlags.Recorded, traceState: null);
+ var carrier = new Dictionary();
+
+ compositePropagator.Inject(activityContext, carrier, Setter);
+ Assert.Contains(carrier, kv => kv.Key == "custom-traceparent");
+
+ // checking if the latest propagator is the one with the data. So, it will replace the previous one.
+ Assert.Equal($"00-{this.traceId}-{this.spanId}-{header02.Split('-').Last()}", carrier["custom-traceparent"]);
+
+ bool isInjected = compositePropagator.IsInjected(carrier, Getter);
+ Assert.True(isInjected);
+
+ // resetting counter
+ count = 0;
+ ActivityContext newContext = compositePropagator.Extract(default, carrier, Getter);
+
+ // checking if we accessed only two times: header/headerstate options
+ // if that's true, we skipped the first one since we have a logic to for the default result
+ Assert.Equal(2, count);
+ }
+ }
+}
diff --git a/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TestPropagator.cs b/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TestPropagator.cs
new file mode 100644
index 00000000000..de206634c28
--- /dev/null
+++ b/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TestPropagator.cs
@@ -0,0 +1,93 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using OpenTelemetry.Context.Propagation;
+
+namespace OpenTelemetry.Tests.Implementation.Trace.Propagation
+{
+ public class TestPropagator : ITextFormat
+ {
+ private readonly string idHeaderName;
+ private readonly string stateHeaderName;
+ private readonly bool defaultContext;
+
+ public TestPropagator(string idHeaderName, string stateHeaderName, bool defaultContext = false)
+ {
+ this.idHeaderName = idHeaderName;
+ this.stateHeaderName = stateHeaderName;
+ this.defaultContext = defaultContext;
+ }
+
+ public ISet Fields => new HashSet() { this.idHeaderName, this.stateHeaderName };
+
+ public ActivityContext Extract(ActivityContext activityContext, T carrier, Func> getter)
+ {
+ if (this.defaultContext)
+ {
+ return activityContext;
+ }
+
+ IEnumerable id = getter(carrier, this.idHeaderName);
+ if (id.Count() <= 0)
+ {
+ return activityContext;
+ }
+
+ var traceparentParsed = TraceContextFormat.TryExtractTraceparent(id.First(), out var traceId, out var spanId, out var traceoptions);
+ if (!traceparentParsed)
+ {
+ return activityContext;
+ }
+
+ string tracestate = string.Empty;
+ IEnumerable tracestateCollection = getter(carrier, this.stateHeaderName);
+ if (tracestateCollection?.Any() ?? false)
+ {
+ TraceContextFormat.TryExtractTracestate(tracestateCollection.ToArray(), out tracestate);
+ }
+
+ return new ActivityContext(traceId, spanId, traceoptions, tracestate);
+ }
+
+ public void Inject(ActivityContext activityContext, T carrier, Action setter)
+ {
+ string headerNumber = this.stateHeaderName.Split('-').Last();
+
+ var traceparent = string.Concat("00-", activityContext.TraceId.ToHexString(), "-", activityContext.SpanId.ToHexString());
+ traceparent = string.Concat(traceparent, "-", headerNumber);
+
+ setter(carrier, this.idHeaderName, traceparent);
+
+ string tracestateStr = activityContext.TraceState;
+ if (tracestateStr?.Length > 0)
+ {
+ setter(carrier, this.stateHeaderName, tracestateStr);
+ }
+ }
+
+ public bool IsInjected(T carrier, Func> getter)
+ {
+ var traceparentCollection = getter(carrier, this.idHeaderName);
+
+ // There must be a single traceparent
+ return traceparentCollection != null && traceparentCollection.Count() == 1;
+ }
+ }
+}
diff --git a/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TraceContextActivityTest.cs b/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TraceContextActivityTest.cs
deleted file mode 100644
index 0e904ab5590..00000000000
--- a/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TraceContextActivityTest.cs
+++ /dev/null
@@ -1,179 +0,0 @@
-//
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using OpenTelemetry.Context.Propagation;
-using Xunit;
-
-namespace OpenTelemetry.Impl.Trace.Propagation
-{
- public class TraceContextActivityTest
- {
- private const string TraceParent = "traceparent";
- private const string TraceState = "tracestate";
- private const string TraceId = "0af7651916cd43dd8448eb211c80319c";
- private const string SpanId = "b9c7c989f97918e1";
-
- private static readonly string[] Empty = new string[0];
- private static readonly Func, string, IEnumerable> Getter = (headers, name) =>
- {
- if (headers.TryGetValue(name, out var value))
- {
- return new[] { value };
- }
-
- return Empty;
- };
-
- private static readonly Action, string, string> Setter = (carrier, name, value) =>
- {
- carrier[name] = value;
- };
-
- [Fact]
- public void TraceContextFormatCanParseExampleFromSpec()
- {
- var headers = new Dictionary
- {
- { TraceParent, $"00-{TraceId}-{SpanId}-01" },
- { TraceState, $"congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4,rojo=00-{TraceId}-00f067aa0ba902b7-01" },
- };
-
- var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
-
- Assert.Equal(ActivityTraceId.CreateFromString(TraceId.AsSpan()), ctx.TraceId);
- Assert.Equal(ActivitySpanId.CreateFromString(SpanId.AsSpan()), ctx.SpanId);
-
- Assert.True(ctx.IsRemote);
- Assert.True(ctx.IsValid());
- Assert.True((ctx.TraceFlags & ActivityTraceFlags.Recorded) != 0);
-
- Assert.Equal($"congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4,rojo=00-{TraceId}-00f067aa0ba902b7-01", ctx.TraceState);
- }
-
- [Fact]
- public void TraceContextFormatNotSampled()
- {
- var headers = new Dictionary
- {
- { TraceParent, $"00-{TraceId}-{SpanId}-00" },
- };
-
- var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
-
- Assert.Equal(ActivityTraceId.CreateFromString(TraceId.AsSpan()), ctx.TraceId);
- Assert.Equal(ActivitySpanId.CreateFromString(SpanId.AsSpan()), ctx.SpanId);
- Assert.True((ctx.TraceFlags & ActivityTraceFlags.Recorded) == 0);
-
- Assert.True(ctx.IsRemote);
- Assert.True(ctx.IsValid());
- }
-
- [Fact]
- public void TraceContextFormat_IsBlankIfNoHeader()
- {
- var headers = new Dictionary();
-
- var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
-
- Assert.False(ctx.IsValid());
- }
-
- [Fact]
- public void TraceContextFormat_IsBlankIfInvalid()
- {
- var headers = new Dictionary
- {
- { TraceParent, $"00-xyz7651916cd43dd8448eb211c80319c-{SpanId}-01" },
- };
-
- var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
-
- Assert.False(ctx.IsValid());
- }
-
- [Fact]
- public void TraceContextFormat_TracestateToStringEmpty()
- {
- var headers = new Dictionary
- {
- { TraceParent, $"00-{TraceId}-{SpanId}-01" },
- };
-
- var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
-
- Assert.Empty(ctx.TraceState);
- }
-
- [Fact]
- public void TraceContextFormat_TracestateToString()
- {
- var headers = new Dictionary
- {
- { TraceParent, $"00-{TraceId}-{SpanId}-01" },
- { TraceState, "k1=v1,k2=v2,k3=v3" },
- };
-
- var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
-
- Assert.Equal("k1=v1,k2=v2,k3=v3", ctx.TraceState);
- }
-
- [Fact]
- public void TraceContextFormat_Inject_NoTracestate()
- {
- var traceId = ActivityTraceId.CreateRandom();
- var spanId = ActivitySpanId.CreateRandom();
- var expectedHeaders = new Dictionary
- {
- { TraceParent, $"00-{traceId}-{spanId}-01" },
- };
-
- var activityContext = new ActivityContext(traceId, spanId, ActivityTraceFlags.Recorded, traceState: null);
- var carrier = new Dictionary();
- var f = new TraceContextFormat();
- f.Inject(activityContext, carrier, Setter);
-
- Assert.Equal(expectedHeaders, carrier);
- }
-
- [Fact]
- public void TraceContextFormat_Inject_WithTracestate()
- {
- var traceId = ActivityTraceId.CreateRandom();
- var spanId = ActivitySpanId.CreateRandom();
- var expectedHeaders = new Dictionary
- {
- { TraceParent, $"00-{traceId}-{spanId}-01" },
- { TraceState, $"congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4,rojo=00-{traceId}-00f067aa0ba902b7-01" },
- };
-
- var activityContext = new ActivityContext(traceId, spanId, ActivityTraceFlags.Recorded, expectedHeaders[TraceState]);
- var carrier = new Dictionary();
- var f = new TraceContextFormat();
- f.Inject(activityContext, carrier, Setter);
-
- Assert.Equal(expectedHeaders, carrier);
- }
- }
-}
diff --git a/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TraceContextTest.cs b/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TraceContextTest.cs
index 6f7a8ed9820..c5b757f32cb 100644
--- a/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TraceContextTest.cs
+++ b/test/OpenTelemetry.Tests/Implementation/Trace/Propagation/TraceContextTest.cs
@@ -39,6 +39,11 @@ public class TraceContextTest
return Empty;
};
+ private static readonly Action, string, string> Setter = (carrier, name, value) =>
+ {
+ carrier[name] = value;
+ };
+
[Fact]
public void TraceContextFormatCanParseExampleFromSpec()
{
@@ -49,7 +54,7 @@ public void TraceContextFormatCanParseExampleFromSpec()
};
var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
+ var ctx = f.Extract(default, headers, Getter);
Assert.Equal(ActivityTraceId.CreateFromString(TraceId.AsSpan()), ctx.TraceId);
Assert.Equal(ActivitySpanId.CreateFromString(SpanId.AsSpan()), ctx.SpanId);
@@ -58,8 +63,7 @@ public void TraceContextFormatCanParseExampleFromSpec()
Assert.True(ctx.IsValid());
Assert.True((ctx.TraceFlags & ActivityTraceFlags.Recorded) != 0);
- Assert.NotNull(ctx.TraceState);
- Assert.Equal(headers[TraceState], ctx.TraceState);
+ Assert.Equal($"congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4,rojo=00-{TraceId}-00f067aa0ba902b7-01", ctx.TraceState);
}
[Fact]
@@ -71,7 +75,7 @@ public void TraceContextFormatNotSampled()
};
var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
+ var ctx = f.Extract(default, headers, Getter);
Assert.Equal(ActivityTraceId.CreateFromString(TraceId.AsSpan()), ctx.TraceId);
Assert.Equal(ActivitySpanId.CreateFromString(SpanId.AsSpan()), ctx.SpanId);
@@ -87,7 +91,7 @@ public void TraceContextFormat_IsBlankIfNoHeader()
var headers = new Dictionary();
var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
+ var ctx = f.Extract(default, headers, Getter);
Assert.False(ctx.IsValid());
}
@@ -101,9 +105,12 @@ public void TraceContextFormat_IsBlankIfInvalid()
};
var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
+ var ctx = f.Extract(default, headers, Getter);
Assert.False(ctx.IsValid());
+
+ // TODO: when ActivityContext supports IsRemote
+ // Assert.True(ctx.IsRemote);
}
[Fact]
@@ -115,9 +122,9 @@ public void TraceContextFormat_TracestateToStringEmpty()
};
var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
+ var ctx = f.Extract(default, headers, Getter);
- Assert.NotNull(ctx.TraceState);
+ Assert.Empty(ctx.TraceState);
}
[Fact]
@@ -130,10 +137,46 @@ public void TraceContextFormat_TracestateToString()
};
var f = new TraceContextFormat();
- var ctx = f.Extract(headers, Getter);
+ var ctx = f.Extract(default, headers, Getter);
- Assert.NotNull(ctx.TraceState);
Assert.Equal("k1=v1,k2=v2,k3=v3", ctx.TraceState);
}
+
+ [Fact]
+ public void TraceContextFormat_Inject_NoTracestate()
+ {
+ var traceId = ActivityTraceId.CreateRandom();
+ var spanId = ActivitySpanId.CreateRandom();
+ var expectedHeaders = new Dictionary
+ {
+ { TraceParent, $"00-{traceId}-{spanId}-01" },
+ };
+
+ var activityContext = new ActivityContext(traceId, spanId, ActivityTraceFlags.Recorded, traceState: null);
+ var carrier = new Dictionary();
+ var f = new TraceContextFormat();
+ f.Inject(activityContext, carrier, Setter);
+
+ Assert.Equal(expectedHeaders, carrier);
+ }
+
+ [Fact]
+ public void TraceContextFormat_Inject_WithTracestate()
+ {
+ var traceId = ActivityTraceId.CreateRandom();
+ var spanId = ActivitySpanId.CreateRandom();
+ var expectedHeaders = new Dictionary
+ {
+ { TraceParent, $"00-{traceId}-{spanId}-01" },
+ { TraceState, $"congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4,rojo=00-{traceId}-00f067aa0ba902b7-01" },
+ };
+
+ var activityContext = new ActivityContext(traceId, spanId, ActivityTraceFlags.Recorded, expectedHeaders[TraceState]);
+ var carrier = new Dictionary();
+ var f = new TraceContextFormat();
+ f.Inject(activityContext, carrier, Setter);
+
+ Assert.Equal(expectedHeaders, carrier);
+ }
}
}