Skip to content

Commit ecdc518

Browse files
joegoldman2amcaseynoahfalk
authored
Set the baggage even when the trace id is not successfully extracted (#55341)
* Set the baggage even when the trace id is not successfully extracted * Make comment more explicit. Co-authored-by: Noah Falk <noahfalk@users.noreply.github.com> --------- Co-authored-by: joegoldman2 <147369450+joegoldman@users.noreply.github.com> Co-authored-by: Andrew Casey <amcasey@users.noreply.github.com> Co-authored-by: Noah Falk <noahfalk@users.noreply.github.com>
1 parent 4b9bf25 commit ecdc518

File tree

2 files changed

+85
-51
lines changed

2 files changed

+85
-51
lines changed

src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -430,28 +430,33 @@ private void RecordRequestStartMetrics(HttpContext httpContext)
430430
}
431431
}
432432

433+
// The trace id was successfully extracted, so we can set the trace state
434+
// https://www.w3.org/TR/trace-context/#tracestate-header
433435
if (!string.IsNullOrEmpty(requestId))
434436
{
435437
if (!string.IsNullOrEmpty(traceState))
436438
{
437439
activity.TraceStateString = traceState;
438440
}
439-
var baggage = _propagator.ExtractBaggage(headers, static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
440-
{
441-
fieldValues = default;
442-
var headers = (IHeaderDictionary)carrier!;
443-
fieldValue = headers[fieldName];
444-
});
441+
}
445442

446-
// AddBaggage adds items at the beginning of the list, so we need to add them in reverse to keep the same order as the client
447-
// By contract, the propagator has already reversed the order of items so we need not reverse it again
448-
// Order could be important if baggage has two items with the same key (that is allowed by the contract)
449-
if (baggage is not null)
443+
// Baggage can be used regardless of whether a distributed trace id was present on the inbound request.
444+
// https://www.w3.org/TR/baggage/#abstract
445+
var baggage = _propagator.ExtractBaggage(headers, static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
446+
{
447+
fieldValues = default;
448+
var headers = (IHeaderDictionary)carrier!;
449+
fieldValue = headers[fieldName];
450+
});
451+
452+
// AddBaggage adds items at the beginning of the list, so we need to add them in reverse to keep the same order as the client
453+
// By contract, the propagator has already reversed the order of items so we need not reverse it again
454+
// Order could be important if baggage has two items with the same key (that is allowed by the contract)
455+
if (baggage is not null)
456+
{
457+
foreach (var baggageItem in baggage)
450458
{
451-
foreach (var baggageItem in baggage)
452-
{
453-
activity.AddBaggage(baggageItem.Key, baggageItem.Value);
454-
}
459+
activity.AddBaggage(baggageItem.Key, baggageItem.Value);
455460
}
456461
}
457462

src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -504,10 +504,10 @@ public void ActivityParentIdAndBaggageReadFromHeaders()
504504
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
505505
{
506506
Headers = new HeaderDictionary()
507-
{
508-
{"Request-Id", "ParentId1"},
509-
{"baggage", "Key1=value1, Key2=value2"}
510-
}
507+
{
508+
{"Request-Id", "ParentId1"},
509+
{"baggage", "Key1=value1, Key2=value2"}
510+
}
511511
});
512512
hostingApplication.CreateContext(features);
513513
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
@@ -517,7 +517,7 @@ public void ActivityParentIdAndBaggageReadFromHeaders()
517517
}
518518

519519
[Fact]
520-
public void ActivityBaggageReadFromLegacyHeaders()
520+
public void BaggageReadFromHeadersWithoutRequestId()
521521
{
522522
var diagnosticListener = new DiagnosticListener("DummySource");
523523
var hostingApplication = CreateApplication(out var features, diagnosticListener: diagnosticListener);
@@ -535,10 +535,39 @@ public void ActivityBaggageReadFromLegacyHeaders()
535535
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
536536
{
537537
Headers = new HeaderDictionary()
538+
{
539+
{"baggage", "Key1=value1, Key2=value2"}
540+
}
541+
});
542+
hostingApplication.CreateContext(features);
543+
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
544+
Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key1" && pair.Value == "value1");
545+
Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key2" && pair.Value == "value2");
546+
}
547+
548+
[Fact]
549+
public void ActivityBaggageReadFromLegacyHeaders()
550+
{
551+
var diagnosticListener = new DiagnosticListener("DummySource");
552+
var hostingApplication = CreateApplication(out var features, diagnosticListener: diagnosticListener);
553+
554+
diagnosticListener.Subscribe(new CallbackDiagnosticListener(pair => { }),
555+
s =>
556+
{
557+
if (s.StartsWith("Microsoft.AspNetCore.Hosting.HttpRequestIn", StringComparison.Ordinal))
538558
{
539-
{"Request-Id", "ParentId1"},
540-
{"Correlation-Context", "Key1=value1, Key2=value2"}
559+
return true;
541560
}
561+
return false;
562+
});
563+
564+
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
565+
{
566+
Headers = new HeaderDictionary()
567+
{
568+
{"Request-Id", "ParentId1"},
569+
{"Correlation-Context", "Key1=value1, Key2=value2"}
570+
}
542571
});
543572
hostingApplication.CreateContext(features);
544573
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
@@ -565,11 +594,11 @@ public void ActivityBaggagePrefersW3CBaggageHeaderName()
565594
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
566595
{
567596
Headers = new HeaderDictionary()
568-
{
569-
{"Request-Id", "ParentId1"},
570-
{"Correlation-Context", "Key1=value1, Key2=value2"},
571-
{"baggage", "Key1=value3, Key2=value4"}
572-
}
597+
{
598+
{"Request-Id", "ParentId1"},
599+
{"Correlation-Context", "Key1=value1, Key2=value2"},
600+
{"baggage", "Key1=value3, Key2=value4"}
601+
}
573602
});
574603
hostingApplication.CreateContext(features);
575604
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
@@ -596,20 +625,20 @@ public void ActivityBaggagePreservesItemsOrder()
596625
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
597626
{
598627
Headers = new HeaderDictionary()
599-
{
600-
{"Request-Id", "ParentId1"},
601-
{"baggage", "Key1=value1, Key2=value2, Key1=value3"} // duplicated keys allowed by the contract
602-
}
628+
{
629+
{"Request-Id", "ParentId1"},
630+
{"baggage", "Key1=value1, Key2=value2, Key1=value3"} // duplicated keys allowed by the contract
631+
}
603632
});
604633
hostingApplication.CreateContext(features);
605634
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
606635

607636
var expectedBaggage = new[]
608637
{
609-
KeyValuePair.Create("Key1","value1"),
610-
KeyValuePair.Create("Key2","value2"),
611-
KeyValuePair.Create("Key1","value3")
612-
};
638+
KeyValuePair.Create("Key1","value1"),
639+
KeyValuePair.Create("Key2","value2"),
640+
KeyValuePair.Create("Key1","value3")
641+
};
613642

614643
Assert.Equal(expectedBaggage, Activity.Current.Baggage.ToArray());
615644
}
@@ -633,10 +662,10 @@ public void ActivityBaggageValuesAreUrlDecodedFromHeaders()
633662
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
634663
{
635664
Headers = new HeaderDictionary()
636-
{
637-
{"Request-Id", "ParentId1"},
638-
{"baggage", "Key1=value1%2F1"}
639-
}
665+
{
666+
{"Request-Id", "ParentId1"},
667+
{"baggage", "Key1=value1%2F1"}
668+
}
640669
});
641670
hostingApplication.CreateContext(features);
642671
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
@@ -662,11 +691,11 @@ public void ActivityTraceParentAndTraceStateFromHeaders()
662691
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
663692
{
664693
Headers = new HeaderDictionary()
665-
{
666-
{"traceparent", "00-0123456789abcdef0123456789abcdef-0123456789abcdef-01"},
667-
{"tracestate", "TraceState1"},
668-
{"baggage", "Key1=value1, Key2=value2"}
669-
}
694+
{
695+
{"traceparent", "00-0123456789abcdef0123456789abcdef-0123456789abcdef-01"},
696+
{"tracestate", "TraceState1"},
697+
{"baggage", "Key1=value1, Key2=value2"}
698+
}
670699
});
671700
hostingApplication.CreateContext(features);
672701
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
@@ -704,9 +733,9 @@ public void SamplersReceiveCorrectParentAndTraceIds()
704733
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
705734
{
706735
Headers = new HeaderDictionary()
707-
{
708-
{"traceparent", "00-35aae61e3e99044eb5ea5007f2cd159b-40a8bd87c078cb4c-00"},
709-
}
736+
{
737+
{"traceparent", "00-35aae61e3e99044eb5ea5007f2cd159b-40a8bd87c078cb4c-00"},
738+
}
710739
});
711740

712741
hostingApplication.CreateContext(features);
@@ -772,11 +801,11 @@ public void ActivityListenersAreCalled()
772801
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
773802
{
774803
Headers = new HeaderDictionary()
775-
{
776-
{"traceparent", "00-0123456789abcdef0123456789abcdef-0123456789abcdef-01"},
777-
{"tracestate", "TraceState1"},
778-
{"baggage", "Key1=value1, Key2=value2"}
779-
}
804+
{
805+
{"traceparent", "00-0123456789abcdef0123456789abcdef-0123456789abcdef-01"},
806+
{"tracestate", "TraceState1"},
807+
{"baggage", "Key1=value1, Key2=value2"}
808+
}
780809
});
781810

782811
hostingApplication.CreateContext(features);

0 commit comments

Comments
 (0)