Separate OpenTelemetry.Api B3 Trace Propagator to a new Nuget Package (#3244)

This commit is contained in:
John 2022-05-10 21:09:15 +02:00 committed by GitHub
parent 9e827ece64
commit 5c168a3faf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 763 additions and 0 deletions

View File

@ -226,6 +226,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-prometheus-
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "customizing-the-sdk", "docs\logs\customizing-the-sdk\customizing-the-sdk.csproj", "{6C7A1595-36D6-4229-BBB5-5A6B5791791D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "customizing-the-sdk", "docs\logs\customizing-the-sdk\customizing-the-sdk.csproj", "{6C7A1595-36D6-4229-BBB5-5A6B5791791D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Propagators", "src\OpenTelemetry.Extensions.Propagators\OpenTelemetry.Extensions.Propagators.csproj", "{E91B2E40-E428-43B3-8A43-09709F0E69E4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Propagators.Tests", "test\OpenTelemetry.Extensions.Propagators.Tests\OpenTelemetry.Extensions.Propagators.Tests.csproj", "{476D804B-BFEC-4D34-814C-DFFD97109989}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -472,6 +476,14 @@ Global
{6C7A1595-36D6-4229-BBB5-5A6B5791791D}.Debug|Any CPU.Build.0 = Debug|Any CPU {6C7A1595-36D6-4229-BBB5-5A6B5791791D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C7A1595-36D6-4229-BBB5-5A6B5791791D}.Release|Any CPU.ActiveCfg = Release|Any CPU {6C7A1595-36D6-4229-BBB5-5A6B5791791D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C7A1595-36D6-4229-BBB5-5A6B5791791D}.Release|Any CPU.Build.0 = Release|Any CPU {6C7A1595-36D6-4229-BBB5-5A6B5791791D}.Release|Any CPU.Build.0 = Release|Any CPU
{E91B2E40-E428-43B3-8A43-09709F0E69E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E91B2E40-E428-43B3-8A43-09709F0E69E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E91B2E40-E428-43B3-8A43-09709F0E69E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E91B2E40-E428-43B3-8A43-09709F0E69E4}.Release|Any CPU.Build.0 = Release|Any CPU
{476D804B-BFEC-4D34-814C-DFFD97109989}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{476D804B-BFEC-4D34-814C-DFFD97109989}.Debug|Any CPU.Build.0 = Debug|Any CPU
{476D804B-BFEC-4D34-814C-DFFD97109989}.Release|Any CPU.ActiveCfg = Release|Any CPU
{476D804B-BFEC-4D34-814C-DFFD97109989}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -0,0 +1,6 @@
OpenTelemetry.Extensions.Propagators.B3Propagator
OpenTelemetry.Extensions.Propagators.B3Propagator.B3Propagator() -> void
OpenTelemetry.Extensions.Propagators.B3Propagator.B3Propagator(bool singleHeader) -> void
override OpenTelemetry.Extensions.Propagators.B3Propagator.Extract<T>(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func<T, string, System.Collections.Generic.IEnumerable<string>> getter) -> OpenTelemetry.Context.Propagation.PropagationContext
override OpenTelemetry.Extensions.Propagators.B3Propagator.Fields.get -> System.Collections.Generic.ISet<string>
override OpenTelemetry.Extensions.Propagators.B3Propagator.Inject<T>(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action<T, string, string> setter) -> void

View File

@ -0,0 +1,6 @@
OpenTelemetry.Extensions.Propagators.B3Propagator
OpenTelemetry.Extensions.Propagators.B3Propagator.B3Propagator() -> void
OpenTelemetry.Extensions.Propagators.B3Propagator.B3Propagator(bool singleHeader) -> void
override OpenTelemetry.Extensions.Propagators.B3Propagator.Extract<T>(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Func<T, string, System.Collections.Generic.IEnumerable<string>> getter) -> OpenTelemetry.Context.Propagation.PropagationContext
override OpenTelemetry.Extensions.Propagators.B3Propagator.Fields.get -> System.Collections.Generic.ISet<string>
override OpenTelemetry.Extensions.Propagators.B3Propagator.Inject<T>(OpenTelemetry.Context.Propagation.PropagationContext context, T carrier, System.Action<T, string, string> setter) -> void

View File

@ -0,0 +1,22 @@
// <copyright file="AssemblyInfo.cs" company="OpenTelemetry Authors">
// 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.
// </copyright>
using System.Runtime.CompilerServices;
#if SIGNED
[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Propagators.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051C1562A090FB0C9F391012A32198B5E5D9A60E9B80FA2D7B434C9E5CCB7259BD606E66F9660676AFC6692B8CDC6793D190904551D2103B7B22FA636DCBB8208839785BA402EA08FC00C8F1500CCEF28BBF599AA64FFB1E1D5DC1BF3420A3777BADFE697856E9D52070A50C3EA5821C80BEF17CA3ACFFA28F89DD413F096F898")]
#else
[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Propagators.Tests")]
#endif

View File

@ -0,0 +1,267 @@
// <copyright file="B3Propagator.cs" company="OpenTelemetry Authors">
// 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.
// </copyright>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using OpenTelemetry.Context.Propagation;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Extensions.Propagators
{
/// <summary>
/// A text map propagator for B3. See https://github.com/openzipkin/b3-propagation.
/// This has been lift-and-shifted as is from the <see cref="Context.Propagation.B3Propagator"/>.
/// </summary>
public sealed class B3Propagator : TextMapPropagator
{
internal const string XB3TraceId = "X-B3-TraceId";
internal const string XB3SpanId = "X-B3-SpanId";
internal const string XB3ParentSpanId = "X-B3-ParentSpanId";
internal const string XB3Sampled = "X-B3-Sampled";
internal const string XB3Flags = "X-B3-Flags";
internal const string XB3Combined = "b3";
internal const char XB3CombinedDelimiter = '-';
// Used as the upper ActivityTraceId.SIZE hex characters of the traceID. B3-propagation used to send
// ActivityTraceId.SIZE hex characters (8-bytes traceId) in the past.
internal const string UpperTraceId = "0000000000000000";
// 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<string> AllFields = new() { XB3TraceId, XB3SpanId, XB3ParentSpanId, XB3Sampled, XB3Flags };
private static readonly HashSet<string> SampledValues = new(StringComparer.Ordinal) { SampledValue, LegacySampledValue };
private readonly bool singleHeader;
/// <summary>
/// Initializes a new instance of the <see cref="B3Propagator"/> class.
/// </summary>
public B3Propagator()
: this(false)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="B3Propagator"/> class.
/// </summary>
/// <param name="singleHeader">Determines whether to use single or multiple headers when extracting or injecting span context.</param>
public B3Propagator(bool singleHeader)
{
this.singleHeader = singleHeader;
}
/// <inheritdoc/>
public override ISet<string> Fields => AllFields;
/// <inheritdoc/>
public override PropagationContext Extract<T>(PropagationContext context, T carrier, Func<T, string, IEnumerable<string>> getter)
{
if (context.ActivityContext.IsValid())
{
// If a valid context has already been extracted, perform a noop.
return context;
}
if (carrier == null)
{
OpenTelemetryApiEventSource.Log.FailedToExtractActivityContext(nameof(B3Propagator), "null carrier");
return context;
}
if (getter == null)
{
OpenTelemetryApiEventSource.Log.FailedToExtractActivityContext(nameof(B3Propagator), "null getter");
return context;
}
if (this.singleHeader)
{
return ExtractFromSingleHeader(context, carrier, getter);
}
else
{
return ExtractFromMultipleHeaders(context, carrier, getter);
}
}
/// <inheritdoc/>
public override void Inject<T>(PropagationContext context, T carrier, Action<T, string, string> setter)
{
if (context.ActivityContext.TraceId == default || context.ActivityContext.SpanId == default)
{
OpenTelemetryApiEventSource.Log.FailedToInjectActivityContext(nameof(B3Propagator), "invalid context");
return;
}
if (carrier == null)
{
OpenTelemetryApiEventSource.Log.FailedToInjectActivityContext(nameof(B3Propagator), "null carrier");
return;
}
if (setter == null)
{
OpenTelemetryApiEventSource.Log.FailedToInjectActivityContext(nameof(B3Propagator), "null setter");
return;
}
if (this.singleHeader)
{
var sb = new StringBuilder();
sb.Append(context.ActivityContext.TraceId.ToHexString());
sb.Append(XB3CombinedDelimiter);
sb.Append(context.ActivityContext.SpanId.ToHexString());
if ((context.ActivityContext.TraceFlags & ActivityTraceFlags.Recorded) != 0)
{
sb.Append(XB3CombinedDelimiter);
sb.Append(SampledValue);
}
setter(carrier, XB3Combined, sb.ToString());
}
else
{
setter(carrier, XB3TraceId, context.ActivityContext.TraceId.ToHexString());
setter(carrier, XB3SpanId, context.ActivityContext.SpanId.ToHexString());
if ((context.ActivityContext.TraceFlags & ActivityTraceFlags.Recorded) != 0)
{
setter(carrier, XB3Sampled, SampledValue);
}
}
}
private static PropagationContext ExtractFromMultipleHeaders<T>(PropagationContext context, T carrier, Func<T, string, IEnumerable<string>> getter)
{
try
{
ActivityTraceId traceId;
var traceIdStr = getter(carrier, XB3TraceId)?.FirstOrDefault();
if (traceIdStr != null)
{
if (traceIdStr.Length == 16)
{
// This is an 8-byte traceID.
traceIdStr = UpperTraceId + traceIdStr;
}
traceId = ActivityTraceId.CreateFromString(traceIdStr.AsSpan());
}
else
{
return context;
}
ActivitySpanId spanId;
var spanIdStr = getter(carrier, XB3SpanId)?.FirstOrDefault();
if (spanIdStr != null)
{
spanId = ActivitySpanId.CreateFromString(spanIdStr.AsSpan());
}
else
{
return context;
}
var traceOptions = ActivityTraceFlags.None;
if (SampledValues.Contains(getter(carrier, XB3Sampled)?.FirstOrDefault())
|| FlagsValue.Equals(getter(carrier, XB3Flags)?.FirstOrDefault(), StringComparison.Ordinal))
{
traceOptions |= ActivityTraceFlags.Recorded;
}
return new PropagationContext(
new ActivityContext(traceId, spanId, traceOptions, isRemote: true),
context.Baggage);
}
catch (Exception e)
{
OpenTelemetryApiEventSource.Log.ActivityContextExtractException(nameof(B3Propagator), e);
return context;
}
}
private static PropagationContext ExtractFromSingleHeader<T>(PropagationContext context, T carrier, Func<T, string, IEnumerable<string>> getter)
{
try
{
var header = getter(carrier, XB3Combined)?.FirstOrDefault();
if (string.IsNullOrWhiteSpace(header))
{
return context;
}
var parts = header.Split(XB3CombinedDelimiter);
if (parts.Length < 2 || parts.Length > 4)
{
return context;
}
var traceIdStr = parts[0];
if (string.IsNullOrWhiteSpace(traceIdStr))
{
return context;
}
if (traceIdStr.Length == 16)
{
// This is an 8-byte traceID.
traceIdStr = UpperTraceId + traceIdStr;
}
var traceId = ActivityTraceId.CreateFromString(traceIdStr.AsSpan());
var spanIdStr = parts[1];
if (string.IsNullOrWhiteSpace(spanIdStr))
{
return context;
}
var spanId = ActivitySpanId.CreateFromString(spanIdStr.AsSpan());
var traceOptions = ActivityTraceFlags.None;
if (parts.Length > 2)
{
var traceFlagsStr = parts[2];
if (SampledValues.Contains(traceFlagsStr)
|| FlagsValue.Equals(traceFlagsStr, StringComparison.Ordinal))
{
traceOptions |= ActivityTraceFlags.Recorded;
}
}
return new PropagationContext(
new ActivityContext(traceId, spanId, traceOptions, isRemote: true),
context.Baggage);
}
catch (Exception e)
{
OpenTelemetryApiEventSource.Log.ActivityContextExtractException(nameof(B3Propagator), e);
return context;
}
}
}
}

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
<TargetFrameworks>net462;netstandard2.0</TargetFrameworks>
<Description>OpenTelemetry Extensions Propagators</Description>
<PackageTags>$(PackageTags);distributed-tracing;AspNet;AspNetCore;B3</PackageTags>
<IncludeInstrumentationHelpers>true</IncludeInstrumentationHelpers>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(RepoRoot)\src\OpenTelemetry.Api\Internal\OpenTelemetryApiEventSource.cs" Link="Includes\OpenTelemetryApiEventSource.cs" />
</ItemGroup>
<!--Do not run ApiCompat for net462/net6.0 as this is newly added. There is no existing contract for net462 against which we could compare the implementation.
Remove this property once we have released a stable net462/net6.0 version.-->
<PropertyGroup Condition="'$(TargetFramework)' == 'net462' OR '$(TargetFramework)' == 'net6.0'">
<RunApiCompat>false</RunApiCompat>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Api\OpenTelemetry.Api.csproj" />
</ItemGroup>
<PropertyGroup>
<NoWarn>$(NoWarn),1591</NoWarn>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,399 @@
// <copyright file="B3PropagatorTest.cs" company="OpenTelemetry Authors">
// 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.
// </copyright>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using OpenTelemetry.Context.Propagation;
using Xunit;
using Xunit.Abstractions;
namespace OpenTelemetry.Extensions.Propagators.Tests
{
public class B3PropagatorTest
{
private const string TraceIdBase16 = "ff000000000000000000000000000041";
private const string TraceIdBase16EightBytes = "0000000000000041";
private const string SpanIdBase16 = "ff00000000000041";
private const string InvalidId = "abcdefghijklmnop";
private const string InvalidSizeId = "0123456789abcdef00";
private const ActivityTraceFlags TraceOptions = ActivityTraceFlags.Recorded;
private static readonly ActivityTraceId TraceId = ActivityTraceId.CreateFromString(TraceIdBase16.AsSpan());
private static readonly ActivityTraceId TraceIdEightBytes = ActivityTraceId.CreateFromString(("0000000000000000" + TraceIdBase16EightBytes).AsSpan());
private static readonly ActivitySpanId SpanId = ActivitySpanId.CreateFromString(SpanIdBase16.AsSpan());
private static readonly Action<IDictionary<string, string>, string, string> Setter = (d, k, v) => d[k] = v;
private static readonly Func<IDictionary<string, string>, string, IEnumerable<string>> Getter =
(d, k) =>
{
d.TryGetValue(k, out var v);
return new string[] { v };
};
private readonly B3Propagator b3propagator = new();
private readonly B3Propagator b3PropagatorSingleHeader = new(true);
private readonly ITestOutputHelper output;
public B3PropagatorTest(ITestOutputHelper output)
{
this.output = output;
}
[Fact]
public void Serialize_SampledContext()
{
var carrier = new Dictionary<string, string>();
this.b3propagator.Inject(new PropagationContext(new ActivityContext(TraceId, SpanId, TraceOptions), default), carrier, Setter);
this.ContainsExactly(carrier, new Dictionary<string, string> { { B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, SpanIdBase16 }, { B3Propagator.XB3Sampled, "1" } });
}
[Fact]
public void Serialize_NotSampledContext()
{
var carrier = new Dictionary<string, string>();
var context = new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None);
this.output.WriteLine(context.ToString());
this.b3propagator.Inject(new PropagationContext(context, default), carrier, Setter);
this.ContainsExactly(carrier, new Dictionary<string, string> { { B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, SpanIdBase16 } });
}
[Fact]
public void ParseMissingSampledAndMissingFlag()
{
var headersNotSampled = new Dictionary<string, string>
{
{ B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, SpanIdBase16 },
};
var spanContext = new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None, isRemote: true);
Assert.Equal(new PropagationContext(spanContext, default), this.b3propagator.Extract(default, headersNotSampled, Getter));
}
[Theory]
[InlineData("1")]
[InlineData("true")]
public void ParseSampled(string sampledValue)
{
var headersSampled = new Dictionary<string, string>
{
{ 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));
}
[Theory]
[InlineData("0")]
[InlineData("false")]
[InlineData("something_else")]
public void ParseNotSampled(string sampledValue)
{
var headersNotSampled = new Dictionary<string, string>
{
{ 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));
}
[Fact]
public void ParseFlag()
{
var headersFlagSampled = new Dictionary<string, string>
{
{ B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, SpanIdBase16 }, { B3Propagator.XB3Flags, "1" },
};
var activityContext = new ActivityContext(TraceId, SpanId, TraceOptions, isRemote: true);
Assert.Equal(new PropagationContext(activityContext, default), this.b3propagator.Extract(default, headersFlagSampled, Getter));
}
[Fact]
public void ParseZeroFlag()
{
var headersFlagNotSampled = new Dictionary<string, string>
{
{ B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, SpanIdBase16 }, { B3Propagator.XB3Flags, "0" },
};
var activityContext = new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None, isRemote: true);
Assert.Equal(new PropagationContext(activityContext, default), this.b3propagator.Extract(default, headersFlagNotSampled, Getter));
}
[Fact]
public void ParseEightBytesTraceId()
{
var headersEightBytes = new Dictionary<string, string>
{
{ B3Propagator.XB3TraceId, TraceIdBase16EightBytes },
{ B3Propagator.XB3SpanId, SpanIdBase16 },
{ B3Propagator.XB3Sampled, "1" },
};
var activityContext = new ActivityContext(TraceIdEightBytes, SpanId, TraceOptions, isRemote: true);
Assert.Equal(new PropagationContext(activityContext, default), this.b3propagator.Extract(default, headersEightBytes, Getter));
}
[Fact]
public void ParseEightBytesTraceId_NotSampledSpanContext()
{
var headersEightBytes = new Dictionary<string, string>
{
{ B3Propagator.XB3TraceId, TraceIdBase16EightBytes }, { B3Propagator.XB3SpanId, SpanIdBase16 },
};
var activityContext = new ActivityContext(TraceIdEightBytes, SpanId, ActivityTraceFlags.None, isRemote: true);
Assert.Equal(new PropagationContext(activityContext, default), this.b3propagator.Extract(default, headersEightBytes, Getter));
}
[Fact]
public void ParseInvalidTraceId()
{
var invalidHeaders = new Dictionary<string, string>
{
{ B3Propagator.XB3TraceId, InvalidId }, { B3Propagator.XB3SpanId, SpanIdBase16 },
};
Assert.Equal(default, this.b3propagator.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseInvalidTraceId_Size()
{
var invalidHeaders = new Dictionary<string, string>
{
{ B3Propagator.XB3TraceId, InvalidSizeId }, { B3Propagator.XB3SpanId, SpanIdBase16 },
};
Assert.Equal(default, this.b3propagator.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseMissingTraceId()
{
var invalidHeaders = new Dictionary<string, string> { { B3Propagator.XB3SpanId, SpanIdBase16 }, };
Assert.Equal(default, this.b3propagator.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseInvalidSpanId()
{
var invalidHeaders = new Dictionary<string, string>
{
{ B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, InvalidId },
};
Assert.Equal(default, this.b3propagator.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseInvalidSpanId_Size()
{
var invalidHeaders = new Dictionary<string, string>
{
{ B3Propagator.XB3TraceId, TraceIdBase16 }, { B3Propagator.XB3SpanId, InvalidSizeId },
};
Assert.Equal(default, this.b3propagator.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseMissingSpanId()
{
var invalidHeaders = new Dictionary<string, string> { { B3Propagator.XB3TraceId, TraceIdBase16 } };
Assert.Equal(default, this.b3propagator.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void Serialize_SampledContext_SingleHeader()
{
var carrier = new Dictionary<string, string>();
var activityContext = new ActivityContext(TraceId, SpanId, TraceOptions);
this.b3PropagatorSingleHeader.Inject(new PropagationContext(activityContext, default), carrier, Setter);
this.ContainsExactly(carrier, new Dictionary<string, string> { { B3Propagator.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}-1" } });
}
[Fact]
public void Serialize_NotSampledContext_SingleHeader()
{
var carrier = new Dictionary<string, string>();
var activityContext = new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None);
this.output.WriteLine(activityContext.ToString());
this.b3PropagatorSingleHeader.Inject(new PropagationContext(activityContext, default), carrier, Setter);
this.ContainsExactly(carrier, new Dictionary<string, string> { { B3Propagator.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}" } });
}
[Fact]
public void ParseMissingSampledAndMissingFlag_SingleHeader()
{
var headersNotSampled = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}" },
};
var activityContext = new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None, isRemote: true);
Assert.Equal(new PropagationContext(activityContext, default), this.b3PropagatorSingleHeader.Extract(default, headersNotSampled, Getter));
}
[Fact]
public void ParseSampled_SingleHeader()
{
var headersSampled = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}-1" },
};
Assert.Equal(
new PropagationContext(new ActivityContext(TraceId, SpanId, TraceOptions, isRemote: true), default),
this.b3PropagatorSingleHeader.Extract(default, headersSampled, Getter));
}
[Fact]
public void ParseZeroSampled_SingleHeader()
{
var headersNotSampled = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}-0" },
};
Assert.Equal(
new PropagationContext(new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None, isRemote: true), default),
this.b3PropagatorSingleHeader.Extract(default, headersNotSampled, Getter));
}
[Fact]
public void ParseFlag_SingleHeader()
{
var headersFlagSampled = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}-1" },
};
var activityContext = new ActivityContext(TraceId, SpanId, TraceOptions, isRemote: true);
Assert.Equal(new PropagationContext(activityContext, default), this.b3PropagatorSingleHeader.Extract(default, headersFlagSampled, Getter));
}
[Fact]
public void ParseZeroFlag_SingleHeader()
{
var headersFlagNotSampled = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{TraceIdBase16}-{SpanIdBase16}-0" },
};
var activityContext = new ActivityContext(TraceId, SpanId, ActivityTraceFlags.None, isRemote: true);
Assert.Equal(new PropagationContext(activityContext, default), this.b3PropagatorSingleHeader.Extract(default, headersFlagNotSampled, Getter));
}
[Fact]
public void ParseEightBytesTraceId_SingleHeader()
{
var headersEightBytes = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{TraceIdBase16EightBytes}-{SpanIdBase16}-1" },
};
var activityContext = new ActivityContext(TraceIdEightBytes, SpanId, TraceOptions, isRemote: true);
Assert.Equal(new PropagationContext(activityContext, default), this.b3PropagatorSingleHeader.Extract(default, headersEightBytes, Getter));
}
[Fact]
public void ParseEightBytesTraceId_NotSampledSpanContext_SingleHeader()
{
var headersEightBytes = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{TraceIdBase16EightBytes}-{SpanIdBase16}" },
};
var activityContext = new ActivityContext(TraceIdEightBytes, SpanId, ActivityTraceFlags.None, isRemote: true);
Assert.Equal(new PropagationContext(activityContext, default), this.b3PropagatorSingleHeader.Extract(default, headersEightBytes, Getter));
}
[Fact]
public void ParseInvalidTraceId_SingleHeader()
{
var invalidHeaders = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{InvalidId}-{SpanIdBase16}" },
};
Assert.Equal(default, this.b3PropagatorSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseInvalidTraceId_Size_SingleHeader()
{
var invalidHeaders = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{InvalidSizeId}-{SpanIdBase16}" },
};
Assert.Equal(default, this.b3PropagatorSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseMissingTraceId_SingleHeader()
{
var invalidHeaders = new Dictionary<string, string> { { B3Propagator.XB3Combined, $"-{SpanIdBase16}" } };
Assert.Equal(default, this.b3PropagatorSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseInvalidSpanId_SingleHeader()
{
var invalidHeaders = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{TraceIdBase16}-{InvalidId}" },
};
Assert.Equal(default, this.b3PropagatorSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseInvalidSpanId_Size_SingleHeader()
{
var invalidHeaders = new Dictionary<string, string>
{
{ B3Propagator.XB3Combined, $"{TraceIdBase16}-{InvalidSizeId}" },
};
Assert.Equal(default, this.b3PropagatorSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void ParseMissingSpanId_SingleHeader()
{
var invalidHeaders = new Dictionary<string, string> { { B3Propagator.XB3Combined, $"{TraceIdBase16}-" } };
Assert.Equal(default, this.b3PropagatorSingleHeader.Extract(default, invalidHeaders, Getter));
}
[Fact]
public void Fields_list()
{
ContainsExactly(
this.b3propagator.Fields,
new List<string> { B3Propagator.XB3TraceId, B3Propagator.XB3SpanId, B3Propagator.XB3ParentSpanId, B3Propagator.XB3Sampled, B3Propagator.XB3Flags });
}
private static void ContainsExactly(ISet<string> list, List<string> items)
{
Assert.Equal(items.Count, list.Count);
foreach (var item in items)
{
Assert.Contains(item, list);
}
}
private void ContainsExactly(IDictionary<string, string> dict, IDictionary<string, string> items)
{
foreach (var d in dict)
{
this.output.WriteLine(d.Key + "=" + d.Value);
}
Assert.Equal(items.Count, dict.Count);
foreach (var item in items)
{
Assert.Contains(item, dict);
}
}
}
}

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
<TargetFrameworks Condition="$(TARGET_FRAMEWORK) == ''">net6.0;netcoreapp3.1;net462</TargetFrameworks>
<TargetFrameworks Condition="$(TARGET_FRAMEWORK) != ''">$(TARGET_FRAMEWORK)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPkgVer)" />
<PackageReference Include="xunit" Version="$(XUnitPkgVer)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XUnitRunnerVisualStudioPkgVer)">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<DotNetCliToolReference Include="dotnet-xunit" Version="$(DotNetXUnitCliVer)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Extensions.Propagators\OpenTelemetry.Extensions.Propagators.csproj" />
</ItemGroup>
</Project>