ASP.NET & ASP.NET Core: Clear baggage when root activity is complete (#2284)
* Clear baggage when root activity is complete. * Test fixes. * Code review. * A couple improvements found reviewing baggage code.
This commit is contained in:
parent
5eed27ab5b
commit
69c6bf2de9
|
|
@ -29,7 +29,7 @@ namespace OpenTelemetry
|
|||
/// </remarks>
|
||||
public readonly struct Baggage : IEquatable<Baggage>
|
||||
{
|
||||
private static readonly RuntimeContextSlot<Baggage> RuntimeContextSlot = RuntimeContext.RegisterSlot<Baggage>("otel.baggage");
|
||||
private static readonly RuntimeContextSlot<BaggageHolder> RuntimeContextSlot = RuntimeContext.RegisterSlot<BaggageHolder>("otel.baggage");
|
||||
private static readonly Dictionary<string, string> EmptyBaggage = new Dictionary<string, string>();
|
||||
|
||||
private readonly Dictionary<string, string> baggage;
|
||||
|
|
@ -48,8 +48,19 @@ namespace OpenTelemetry
|
|||
/// </summary>
|
||||
public static Baggage Current
|
||||
{
|
||||
get => RuntimeContextSlot.Get();
|
||||
set => RuntimeContextSlot.Set(value);
|
||||
get => RuntimeContextSlot.Get()?.Baggage ?? default;
|
||||
set
|
||||
{
|
||||
var baggageHolder = RuntimeContextSlot.Get();
|
||||
if (baggageHolder == null)
|
||||
{
|
||||
RuntimeContextSlot.Set(new BaggageHolder { Baggage = value });
|
||||
}
|
||||
else
|
||||
{
|
||||
baggageHolder.Baggage = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -83,7 +94,7 @@ namespace OpenTelemetry
|
|||
return default;
|
||||
}
|
||||
|
||||
Dictionary<string, string> baggageCopy = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
Dictionary<string, string> baggageCopy = new Dictionary<string, string>(baggageItems.Count, StringComparer.OrdinalIgnoreCase);
|
||||
foreach (KeyValuePair<string, string> baggageItem in baggageItems)
|
||||
{
|
||||
if (string.IsNullOrEmpty(baggageItem.Value))
|
||||
|
|
@ -222,7 +233,7 @@ namespace OpenTelemetry
|
|||
/// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns>
|
||||
public Baggage SetBaggage(IEnumerable<KeyValuePair<string, string>> baggageItems)
|
||||
{
|
||||
if ((baggageItems?.Count() ?? 0) <= 0)
|
||||
if (baggageItems?.Any() != true)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
|
@ -305,5 +316,10 @@ namespace OpenTelemetry
|
|||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
private class BaggageHolder
|
||||
{
|
||||
public Baggage Baggage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ namespace OpenTelemetry.Instrumentation.AspNet
|
|||
{
|
||||
context.Items[ActivityKey] = activity;
|
||||
|
||||
if (propagationContext.Baggage != default)
|
||||
if (!(textMapPropagator is TraceContextPropagator))
|
||||
{
|
||||
// todo: RestoreActivityIfNeeded below compensates for
|
||||
// AsyncLocal Activity.Current being lost. Baggage
|
||||
|
|
@ -116,11 +116,12 @@ namespace OpenTelemetry.Instrumentation.AspNet
|
|||
/// <summary>
|
||||
/// Stops the activity and notifies listeners about it.
|
||||
/// </summary>
|
||||
/// <param name="textMapPropagator"><see cref="TextMapPropagator"/>.</param>
|
||||
/// <param name="aspNetActivity"><see cref="Activity"/>.</param>
|
||||
/// <param name="context"><see cref="HttpContext"/>.</param>
|
||||
/// <param name="onRequestStoppedCallback">Callback action.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StopAspNetActivity(Activity aspNetActivity, HttpContext context, Action<Activity, HttpContext> onRequestStoppedCallback)
|
||||
public static void StopAspNetActivity(TextMapPropagator textMapPropagator, Activity aspNetActivity, HttpContext context, Action<Activity, HttpContext> onRequestStoppedCallback)
|
||||
{
|
||||
Debug.Assert(context != null, "Context is null.");
|
||||
|
||||
|
|
@ -152,6 +153,11 @@ namespace OpenTelemetry.Instrumentation.AspNet
|
|||
|
||||
AspNetTelemetryEventSource.Log.ActivityStopped(currentActivity);
|
||||
|
||||
if (!(textMapPropagator is TraceContextPropagator))
|
||||
{
|
||||
Baggage.Current = default;
|
||||
}
|
||||
|
||||
if (currentActivity != aspNetActivity)
|
||||
{
|
||||
Activity.Current = currentActivity;
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ namespace OpenTelemetry.Instrumentation.AspNet
|
|||
|
||||
if (trackActivity)
|
||||
{
|
||||
ActivityHelper.StopAspNetActivity(aspNetActivity, context, Options.OnRequestStoppedCallback);
|
||||
ActivityHelper.StopAspNetActivity(Options.TextMapPropagator, aspNetActivity, context, Options.OnRequestStoppedCallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,13 +25,9 @@ namespace OpenTelemetry.Instrumentation.AspNetCore
|
|||
{
|
||||
private readonly DiagnosticSourceSubscriber diagnosticSourceSubscriber;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AspNetCoreInstrumentation"/> class.
|
||||
/// </summary>
|
||||
/// <param name="options">Configuration options for ASP.NET Core instrumentation.</param>
|
||||
public AspNetCoreInstrumentation(AspNetCoreInstrumentationOptions options)
|
||||
public AspNetCoreInstrumentation(HttpInListener httpInListener)
|
||||
{
|
||||
this.diagnosticSourceSubscriber = new DiagnosticSourceSubscriber(new HttpInListener("Microsoft.AspNetCore", options), null);
|
||||
this.diagnosticSourceSubscriber = new DiagnosticSourceSubscriber(httpInListener, null);
|
||||
this.diagnosticSourceSubscriber.Subscribe();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,11 +19,15 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
#if !NETSTANDARD2_0
|
||||
using System.Runtime.CompilerServices;
|
||||
#endif
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using OpenTelemetry.Context.Propagation;
|
||||
#if !NETSTANDARD2_0
|
||||
using OpenTelemetry.Instrumentation.GrpcNetClient;
|
||||
#endif
|
||||
using OpenTelemetry.Trace;
|
||||
|
||||
namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
||||
|
|
@ -35,6 +39,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
|||
internal static readonly string ActivitySourceName = AssemblyName.Name;
|
||||
internal static readonly Version Version = AssemblyName.Version;
|
||||
internal static readonly ActivitySource ActivitySource = new ActivitySource(ActivitySourceName, Version.ToString());
|
||||
private const string DiagnosticSourceName = "Microsoft.AspNetCore";
|
||||
private const string UnknownHostName = "UNKNOWN-HOST";
|
||||
private static readonly Func<HttpRequest, string, IEnumerable<string>> HttpRequestHeaderValuesGetter = (request, name) => request.Headers[name];
|
||||
private readonly PropertyFetcher<HttpContext> startContextFetcher = new PropertyFetcher<HttpContext>("HttpContext");
|
||||
|
|
@ -45,8 +50,8 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
|||
private readonly PropertyFetcher<string> beforeActionTemplateFetcher = new PropertyFetcher<string>("Template");
|
||||
private readonly AspNetCoreInstrumentationOptions options;
|
||||
|
||||
public HttpInListener(string name, AspNetCoreInstrumentationOptions options)
|
||||
: base(name)
|
||||
public HttpInListener(AspNetCoreInstrumentationOptions options)
|
||||
: base(DiagnosticSourceName)
|
||||
{
|
||||
this.options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
|
@ -103,10 +108,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
|||
activity = newOne;
|
||||
}
|
||||
|
||||
if (ctx.Baggage != default)
|
||||
{
|
||||
Baggage.Current = ctx.Baggage;
|
||||
}
|
||||
Baggage.Current = ctx.Baggage;
|
||||
}
|
||||
|
||||
// enrich Activity from payload only if sampling decision
|
||||
|
|
@ -184,17 +186,14 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
|||
|
||||
activity.SetTag(SemanticConventions.AttributeHttpStatusCode, response.StatusCode);
|
||||
|
||||
#if NETSTANDARD2_1 || NETCOREAPP3_1 || NET5_0
|
||||
#if !NETSTANDARD2_0
|
||||
if (this.options.EnableGrpcAspNetCoreSupport && TryGetGrpcMethod(activity, out var grpcMethod))
|
||||
{
|
||||
AddGrpcAttributes(activity, grpcMethod, context);
|
||||
}
|
||||
else
|
||||
else if (activity.GetStatus().StatusCode == StatusCode.Unset)
|
||||
{
|
||||
if (activity.GetStatus().StatusCode == StatusCode.Unset)
|
||||
{
|
||||
activity.SetStatus(SpanHelper.ResolveSpanStatusForHttpStatusCode(response.StatusCode));
|
||||
}
|
||||
activity.SetStatus(SpanHelper.ResolveSpanStatusForHttpStatusCode(response.StatusCode));
|
||||
}
|
||||
#else
|
||||
if (activity.GetStatus().StatusCode == StatusCode.Unset)
|
||||
|
|
@ -231,6 +230,12 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
|||
// the one created by the instrumentation.
|
||||
// And retrieve it here, and set it to Current.
|
||||
}
|
||||
|
||||
var textMapPropagator = Propagators.DefaultTextMapPropagator;
|
||||
if (!(textMapPropagator is TraceContextPropagator))
|
||||
{
|
||||
Baggage.Current = default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnCustom(string name, Activity activity, object payload)
|
||||
|
|
@ -325,7 +330,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
|||
return builder.ToString();
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_1 || NETCOREAPP3_1 || NET5_0
|
||||
#if !NETSTANDARD2_0
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool TryGetGrpcMethod(Activity activity, out string grpcMethod)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,13 +51,24 @@ namespace OpenTelemetry.Trace
|
|||
return AddAspNetCoreInstrumentation(builder, new AspNetCoreInstrumentationOptions(), configureAspNetCoreInstrumentationOptions);
|
||||
}
|
||||
|
||||
private static TracerProviderBuilder AddAspNetCoreInstrumentation(TracerProviderBuilder builder, AspNetCoreInstrumentationOptions options, Action<AspNetCoreInstrumentationOptions> configure = null)
|
||||
internal static TracerProviderBuilder AddAspNetCoreInstrumentation(
|
||||
this TracerProviderBuilder builder,
|
||||
AspNetCoreInstrumentation instrumentation)
|
||||
{
|
||||
configure?.Invoke(options);
|
||||
var instrumentation = new AspNetCoreInstrumentation(options);
|
||||
builder.AddSource(HttpInListener.ActivitySourceName);
|
||||
builder.AddLegacySource(HttpInListener.ActivityOperationName); // for the activities created by AspNetCore
|
||||
return builder.AddInstrumentation(() => instrumentation);
|
||||
}
|
||||
|
||||
private static TracerProviderBuilder AddAspNetCoreInstrumentation(
|
||||
TracerProviderBuilder builder,
|
||||
AspNetCoreInstrumentationOptions options,
|
||||
Action<AspNetCoreInstrumentationOptions> configure = null)
|
||||
{
|
||||
configure?.Invoke(options);
|
||||
return AddAspNetCoreInstrumentation(
|
||||
builder,
|
||||
new AspNetCoreInstrumentation(new HttpInListener(options)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,15 +32,11 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
private const string TraceParentHeaderName = "traceparent";
|
||||
private const string TraceStateHeaderName = "tracestate";
|
||||
private const string BaggageHeaderName = "baggage";
|
||||
private const string BaggageInHeader = "TestKey1=123,TestKey2=456,TestKey1=789";
|
||||
private const string TestActivityName = "Activity.Test";
|
||||
private readonly string baggageInHeader;
|
||||
private readonly TextMapPropagator noopTextMapPropagator = new NoopTextMapPropagator();
|
||||
private ActivityListener activitySourceListener;
|
||||
|
||||
public ActivityHelperTest()
|
||||
{
|
||||
this.baggageInHeader = "TestKey1=123,TestKey2=456,TestKey1=789";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.activitySourceListener?.Dispose();
|
||||
|
|
@ -78,7 +74,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
{
|
||||
this.EnableListener();
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
rootActivity.AddTag("k1", "v1");
|
||||
rootActivity.AddTag("k2", "v2");
|
||||
|
||||
|
|
@ -99,13 +95,13 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
Assert.Equal(TelemetryHttpModule.AspNetActivityName, Activity.Current.OperationName);
|
||||
});
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
rootActivity.AddTag("k1", "v1");
|
||||
rootActivity.AddTag("k2", "v2");
|
||||
|
||||
Activity.Current = null;
|
||||
|
||||
ActivityHelper.StopAspNetActivity(rootActivity, context, null);
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, rootActivity, context, null);
|
||||
Assert.True(rootActivity.Duration != TimeSpan.Zero);
|
||||
Assert.Null(Activity.Current);
|
||||
Assert.Null(context.Items[ActivityHelper.ActivityKey]);
|
||||
|
|
@ -142,7 +138,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
rootActivity.Start();
|
||||
context.Items[ActivityHelper.ActivityKey] = rootActivity;
|
||||
Thread.Sleep(100);
|
||||
ActivityHelper.StopAspNetActivity(rootActivity, context, null);
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, rootActivity, context, null);
|
||||
|
||||
Assert.True(rootActivity.Duration != TimeSpan.Zero);
|
||||
Assert.Null(rootActivity.Parent);
|
||||
|
|
@ -158,7 +154,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
context.Items[ActivityHelper.ActivityKey] = rootActivity;
|
||||
Thread.Sleep(100);
|
||||
this.EnableListener();
|
||||
ActivityHelper.StopAspNetActivity(rootActivity, context, null);
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, rootActivity, context, null);
|
||||
|
||||
Assert.True(rootActivity.Duration != TimeSpan.Zero);
|
||||
Assert.Null(rootActivity.Parent);
|
||||
|
|
@ -170,12 +166,12 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
{
|
||||
this.EnableListener();
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
|
||||
var child = new Activity("child").Start();
|
||||
new Activity("grandchild").Start();
|
||||
|
||||
ActivityHelper.StopAspNetActivity(rootActivity, context, null);
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, rootActivity, context, null);
|
||||
|
||||
Assert.True(rootActivity.Duration != TimeSpan.Zero);
|
||||
Assert.True(child.Duration == TimeSpan.Zero);
|
||||
|
|
@ -188,10 +184,10 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
{
|
||||
this.EnableListener();
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
var child = new Activity("child").Start();
|
||||
|
||||
ActivityHelper.StopAspNetActivity(rootActivity, context, null);
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, rootActivity, context, null);
|
||||
|
||||
Assert.True(child.Duration == TimeSpan.Zero);
|
||||
Assert.NotNull(Activity.Current);
|
||||
|
|
@ -204,7 +200,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
{
|
||||
this.EnableListener();
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
var root = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var root = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
new Activity("child").Start();
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
|
|
@ -223,7 +219,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
// do not affect 'parent' context in which Task.Run is called.
|
||||
// But 'child' Activity is stopped, thus consequent calls to Stop will
|
||||
// not update Current
|
||||
ActivityHelper.StopAspNetActivity(root, context, null);
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, root, context, null);
|
||||
Assert.True(root.Duration != TimeSpan.Zero);
|
||||
Assert.Null(context.Items[ActivityHelper.ActivityKey]);
|
||||
Assert.Null(Activity.Current);
|
||||
|
|
@ -234,7 +230,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
{
|
||||
this.EnableListener();
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
var root = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var root = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
|
|
@ -242,7 +238,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
}
|
||||
|
||||
// can stop any activity regardless of the stack depth
|
||||
ActivityHelper.StopAspNetActivity(root, context, null);
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, root, context, null);
|
||||
|
||||
Assert.True(root.Duration != TimeSpan.Zero);
|
||||
Assert.Null(context.Items[ActivityHelper.ActivityKey]);
|
||||
|
|
@ -253,12 +249,12 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
public void Should_Not_Create_RootActivity_If_AspNetListener_Not_Enabled()
|
||||
{
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
|
||||
Assert.Null(rootActivity);
|
||||
Assert.Equal(ActivityHelper.StartedButNotSampledObj, context.Items[ActivityHelper.ActivityKey]);
|
||||
|
||||
ActivityHelper.StopAspNetActivity(rootActivity, context, null);
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, rootActivity, context, null);
|
||||
Assert.Null(context.Items[ActivityHelper.ActivityKey]);
|
||||
}
|
||||
|
||||
|
|
@ -267,12 +263,12 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
{
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
this.EnableListener(onSample: (context) => ActivitySamplingResult.None);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
|
||||
Assert.Null(rootActivity);
|
||||
Assert.Equal(ActivityHelper.StartedButNotSampledObj, context.Items[ActivityHelper.ActivityKey]);
|
||||
|
||||
ActivityHelper.StopAspNetActivity(rootActivity, context, null);
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, rootActivity, context, null);
|
||||
Assert.Null(context.Items[ActivityHelper.ActivityKey]);
|
||||
}
|
||||
|
||||
|
|
@ -334,7 +330,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
var requestHeaders = new Dictionary<string, string>
|
||||
{
|
||||
{ TraceParentHeaderName, "00-0123456789abcdef0123456789abcdef-0123456789abcdef-00" },
|
||||
{ BaggageHeaderName, this.baggageInHeader },
|
||||
{ BaggageHeaderName, BaggageInHeader },
|
||||
};
|
||||
|
||||
var context = HttpContextHelper.GetFakeHttpContext(headers: requestHeaders);
|
||||
|
|
@ -353,6 +349,10 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
Assert.Equal(2, Baggage.Current.Count);
|
||||
Assert.Equal("789", Baggage.Current.GetBaggage("TestKey1"));
|
||||
Assert.Equal("456", Baggage.Current.GetBaggage("TestKey2"));
|
||||
|
||||
ActivityHelper.StopAspNetActivity(this.noopTextMapPropagator, rootActivity, context, null);
|
||||
|
||||
Assert.Equal(0, Baggage.Current.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -365,7 +365,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
};
|
||||
|
||||
var context = HttpContextHelper.GetFakeHttpContext(headers: requestHeaders);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
|
||||
Assert.NotNull(rootActivity);
|
||||
Assert.Null(rootActivity.ParentId);
|
||||
|
|
@ -377,7 +377,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
{
|
||||
this.EnableListener();
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
|
||||
Assert.NotNull(rootActivity);
|
||||
Assert.True(!string.IsNullOrEmpty(rootActivity.Id));
|
||||
|
|
@ -388,7 +388,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
{
|
||||
this.EnableListener();
|
||||
var context = HttpContextHelper.GetFakeHttpContext();
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(new NoopTextMapPropagator(), context, null);
|
||||
var rootActivity = ActivityHelper.StartAspNetActivity(this.noopTextMapPropagator, context, null);
|
||||
|
||||
Assert.NotNull(rootActivity);
|
||||
Assert.Same(rootActivity, context.Items[ActivityHelper.ActivityKey]);
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
ActivityHelper.WriteActivityException(activity, HttpContext.Current, new InvalidOperationException(), TelemetryHttpModule.Options.OnExceptionCallback);
|
||||
}
|
||||
|
||||
ActivityHelper.StopAspNetActivity(activity, HttpContext.Current, TelemetryHttpModule.Options.OnRequestStoppedCallback);
|
||||
ActivityHelper.StopAspNetActivity(Propagators.DefaultTextMapPropagator, activity, HttpContext.Current, TelemetryHttpModule.Options.OnRequestStoppedCallback);
|
||||
}
|
||||
|
||||
if (HttpContext.Current.Request.Path == filter || filter == "{ThrowException}")
|
||||
|
|
@ -281,7 +281,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
.AddProcessor(activityProcessor.Object).Build())
|
||||
{
|
||||
var activity = ActivityHelper.StartAspNetActivity(Propagators.DefaultTextMapPropagator, HttpContext.Current, TelemetryHttpModule.Options.OnRequestStartedCallback);
|
||||
ActivityHelper.StopAspNetActivity(activity, HttpContext.Current, TelemetryHttpModule.Options.OnRequestStoppedCallback);
|
||||
ActivityHelper.StopAspNetActivity(Propagators.DefaultTextMapPropagator, activity, HttpContext.Current, TelemetryHttpModule.Options.OnRequestStoppedCallback);
|
||||
}
|
||||
|
||||
Assert.True(isPropagatorCalled);
|
||||
|
|
@ -324,7 +324,7 @@ namespace OpenTelemetry.Instrumentation.AspNet.Tests
|
|||
.AddProcessor(activityProcessor.Object).Build())
|
||||
{
|
||||
var activity = ActivityHelper.StartAspNetActivity(Propagators.DefaultTextMapPropagator, HttpContext.Current, TelemetryHttpModule.Options.OnRequestStartedCallback);
|
||||
ActivityHelper.StopAspNetActivity(activity, HttpContext.Current, TelemetryHttpModule.Options.OnRequestStoppedCallback);
|
||||
ActivityHelper.StopAspNetActivity(Propagators.DefaultTextMapPropagator, activity, HttpContext.Current, TelemetryHttpModule.Options.OnRequestStoppedCallback);
|
||||
}
|
||||
|
||||
Assert.True(isFilterCalled);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ using Xunit;
|
|||
namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
|
||||
{
|
||||
// See https://github.com/aspnet/Docs/tree/master/aspnetcore/test/integration-tests/samples/2.x/IntegrationTestsSample
|
||||
public class BasicTests
|
||||
public sealed class BasicTests
|
||||
: IClassFixture<WebApplicationFactory<Startup>>, IDisposable
|
||||
{
|
||||
private readonly WebApplicationFactory<Startup> factory;
|
||||
|
|
@ -508,6 +508,55 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BaggageClearedWhenActivityStopped()
|
||||
{
|
||||
int? baggageCountAfterStart = null;
|
||||
int? baggageCountAfterStop = null;
|
||||
using EventWaitHandle stopSignal = new EventWaitHandle(false, EventResetMode.ManualReset);
|
||||
|
||||
void ConfigureTestServices(IServiceCollection services)
|
||||
{
|
||||
this.openTelemetrySdk = Sdk.CreateTracerProviderBuilder()
|
||||
.AddAspNetCoreInstrumentation(new AspNetCoreInstrumentation(
|
||||
new TestHttpInListener(new AspNetCoreInstrumentationOptions())
|
||||
{
|
||||
OnStartActivityCallback = (activity, payload) =>
|
||||
{
|
||||
baggageCountAfterStart = Baggage.Current.Count;
|
||||
},
|
||||
OnStopActivityCallback = (activity, payload) =>
|
||||
{
|
||||
baggageCountAfterStop = Baggage.Current.Count;
|
||||
stopSignal.Set();
|
||||
},
|
||||
}))
|
||||
.Build();
|
||||
}
|
||||
|
||||
// Arrange
|
||||
using (var client = this.factory
|
||||
.WithWebHostBuilder(builder =>
|
||||
builder.ConfigureTestServices(ConfigureTestServices))
|
||||
.CreateClient())
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, "/api/values");
|
||||
|
||||
request.Headers.TryAddWithoutValidation("baggage", "TestKey1=123,TestKey2=456");
|
||||
|
||||
// Act
|
||||
using var response = await client.SendAsync(request);
|
||||
}
|
||||
|
||||
stopSignal.WaitOne(5000);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(baggageCountAfterStart);
|
||||
Assert.Equal(2, baggageCountAfterStart);
|
||||
Assert.NotNull(baggageCountAfterStop);
|
||||
Assert.Equal(0, baggageCountAfterStop);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SamplingDecision.Drop, false, false)]
|
||||
[InlineData(SamplingDecision.RecordOnly, true, true)]
|
||||
|
|
@ -622,7 +671,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
|
|||
|
||||
private class TestSampler : Sampler
|
||||
{
|
||||
private SamplingDecision samplingDecision;
|
||||
private readonly SamplingDecision samplingDecision;
|
||||
|
||||
public TestSampler(SamplingDecision samplingDecision)
|
||||
{
|
||||
|
|
@ -634,5 +683,31 @@ namespace OpenTelemetry.Instrumentation.AspNetCore.Tests
|
|||
return new SamplingResult(this.samplingDecision);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestHttpInListener : HttpInListener
|
||||
{
|
||||
public Action<Activity, object> OnStartActivityCallback;
|
||||
|
||||
public Action<Activity, object> OnStopActivityCallback;
|
||||
|
||||
public TestHttpInListener(AspNetCoreInstrumentationOptions options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnStartActivity(Activity activity, object payload)
|
||||
{
|
||||
base.OnStartActivity(activity, payload);
|
||||
|
||||
this.OnStartActivityCallback?.Invoke(activity, payload);
|
||||
}
|
||||
|
||||
public override void OnStopActivity(Activity activity, object payload)
|
||||
{
|
||||
base.OnStopActivity(activity, payload);
|
||||
|
||||
this.OnStopActivityCallback?.Invoke(activity, payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Tests
|
||||
|
|
@ -269,5 +271,32 @@ namespace OpenTelemetry.Tests
|
|||
|
||||
Assert.Equal(expectedBaggage.GetHashCode(), baggage.GetHashCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AsyncLocalTests()
|
||||
{
|
||||
Baggage.SetBaggage("key1", "value1");
|
||||
|
||||
await InnerTask().ConfigureAwait(false);
|
||||
|
||||
Baggage.SetBaggage("key4", "value4");
|
||||
|
||||
Assert.Equal(4, Baggage.Current.Count);
|
||||
Assert.Equal("value1", Baggage.GetBaggage("key1"));
|
||||
Assert.Equal("value2", Baggage.GetBaggage("key2"));
|
||||
Assert.Equal("value3", Baggage.GetBaggage("key3"));
|
||||
Assert.Equal("value4", Baggage.GetBaggage("key4"));
|
||||
|
||||
static async Task InnerTask()
|
||||
{
|
||||
Baggage.SetBaggage("key2", "value2");
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
Baggage.SetBaggage("key3", "value3");
|
||||
|
||||
// key2 & key3 changes don't flow backward automatically
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue