Skip to content

Commit f1f510b

Browse files
[Instrumentation.AspNet] Baggage is propagated before the Activity is created (#3820)
Co-authored-by: Rajkumar Rangaraj <rajrang@microsoft.com>
1 parent aa94c78 commit f1f510b

File tree

3 files changed

+35
-52
lines changed

3 files changed

+35
-52
lines changed

src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/ActivityHelper.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public static bool HasStarted(HttpContextBase context, out Activity? aspNetActiv
6060
Activity? activity = null;
6161
try
6262
{
63+
Baggage.Current = propagationContext.Baggage;
6364
activity = onRequestStartedCallback?.Invoke(context, propagationContext.ActivityContext);
6465
}
6566
catch (Exception callbackEx)
@@ -71,8 +72,6 @@ public static bool HasStarted(HttpContextBase context, out Activity? aspNetActiv
7172
{
7273
if (textMapPropagator is not TraceContextPropagator)
7374
{
74-
Baggage.Current = propagationContext.Baggage;
75-
7675
context.Items[ContextKey] = new ContextHolder(activity, RuntimeContext.GetValue(BaggageSlotName));
7776
}
7877
else

src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
* Propagate baggage before `Activity` is created.
6+
([#3820](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3820))
7+
58
## 1.15.0
69

710
Released 2026-Jan-21

test/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.Tests/ActivityHelperTest.cs

Lines changed: 31 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright The OpenTelemetry Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4-
using System.Collections;
5-
using System.Collections.Specialized;
64
using System.Diagnostics;
75
using System.Web;
86
using OpenTelemetry.Context.Propagation;
@@ -56,6 +54,16 @@ public void Has_Started_Returns_Correctly()
5654
Assert.Equal(activity, aspNetActivity);
5755
}
5856

57+
[Fact]
58+
public void Baggage_Is_Restored_Before_Starting_Activity()
59+
{
60+
this.EnableListener();
61+
var propagator = new MockTextMapPropagator();
62+
var context = HttpContextHelper.GetFakeHttpContextBase();
63+
using var activity = ActivityHelper.StartAspNetActivity(propagator, context, this.StartTestActivityWithBaggageAttribute);
64+
Assert.Equal(MockTextMapPropagator.BaggageValue, activity?.Tags.FirstOrDefault(kv => kv.Key == MockTextMapPropagator.BaggageKey).Value);
65+
}
66+
5967
[Fact]
6068
public async Task Can_Restore_Activity()
6169
{
@@ -507,72 +515,45 @@ private void EnableListener(Action<Activity>? onStarted = null, Action<Activity>
507515
return this.testActivitySource.StartActivity(ActivityKind.Server, activityContext);
508516
}
509517

510-
private class TestHttpRequest : HttpRequestBase
518+
private Activity? StartTestActivityWithBaggageAttribute(HttpContextBase httpContext, ActivityContext activityContext)
511519
{
512-
private readonly NameValueCollection headers = [];
513-
514-
public override NameValueCollection Headers => this.headers;
515-
516-
public override UnvalidatedRequestValuesBase Unvalidated => new TestUnvalidatedRequestValues(this.headers);
520+
var baggageValue = Baggage.Current.GetBaggage(MockTextMapPropagator.BaggageKey);
521+
var activity = this.testActivitySource.StartActivity(ActivityKind.Server, activityContext);
522+
activity?.AddTag(MockTextMapPropagator.BaggageKey, baggageValue);
523+
return activity;
517524
}
518525

519-
private class TestUnvalidatedRequestValues : UnvalidatedRequestValuesBase
520-
{
521-
public TestUnvalidatedRequestValues(NameValueCollection headers)
522-
{
523-
this.Headers = headers;
524-
}
525-
526-
public override NameValueCollection Headers { get; }
527-
}
528-
529-
private class TestHttpResponse : HttpResponseBase
530-
{
531-
}
532-
533-
private class TestHttpServerUtility : HttpServerUtilityBase
526+
private class NoopTextMapPropagator : TextMapPropagator
534527
{
535-
private readonly HttpContextBase context;
528+
public override ISet<string>? Fields => null;
536529

537-
public TestHttpServerUtility(HttpContextBase context)
530+
public override PropagationContext Extract<T>(PropagationContext context, T carrier, Func<T, string, IEnumerable<string>?> getter)
538531
{
539-
this.context = context;
532+
return default;
540533
}
541534

542-
public override Exception GetLastError()
535+
public override void Inject<T>(PropagationContext context, T carrier, Action<T, string, string> setter)
543536
{
544-
return this.context.Error;
545537
}
546538
}
547539

548-
private class TestHttpContext : HttpContextBase
540+
private class MockTextMapPropagator : TextMapPropagator
549541
{
550-
private readonly Hashtable items;
551-
552-
public TestHttpContext(Exception? error = null)
553-
{
554-
this.Server = new TestHttpServerUtility(this);
555-
this.items = [];
556-
this.Error = error;
557-
}
558-
559-
public override HttpRequestBase Request { get; } = new TestHttpRequest();
560-
561-
/// <inheritdoc />
562-
public override IDictionary Items => this.items;
563-
564-
public override Exception? Error { get; }
542+
internal const string BaggageKey = "TestKey1";
543+
internal const string BaggageValue = "TestValue1";
565544

566-
public override HttpServerUtilityBase Server { get; }
567-
}
568-
569-
private class NoopTextMapPropagator : TextMapPropagator
570-
{
571545
public override ISet<string>? Fields => null;
572546

573547
public override PropagationContext Extract<T>(PropagationContext context, T carrier, Func<T, string, IEnumerable<string>?> getter)
574548
{
575-
return default;
549+
var baggage = Baggage.Create(new Dictionary<string, string>
550+
{
551+
{ BaggageKey, BaggageValue },
552+
});
553+
554+
var activityContext = new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded);
555+
556+
return new PropagationContext(activityContext, baggage);
576557
}
577558

578559
public override void Inject<T>(PropagationContext context, T carrier, Action<T, string, string> setter)

0 commit comments

Comments
 (0)