Skip to content

Commit 0fd9575

Browse files
Initialize Activity with parent ID (#41568)
Initialize Activity with parent ID in Hosting.
1 parent c481a38 commit 0fd9575

File tree

2 files changed

+80
-10
lines changed

2 files changed

+80
-10
lines changed

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

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -310,17 +310,8 @@ private static void RecordRequestStartEventLog(HttpContext httpContext)
310310
[MethodImpl(MethodImplOptions.NoInlining)]
311311
private Activity? StartActivity(HttpContext httpContext, bool loggingEnabled, bool diagnosticListenerActivityCreationEnabled, out bool hasDiagnosticListener)
312312
{
313-
var activity = _activitySource.CreateActivity(ActivityName, ActivityKind.Server);
314-
if (activity is null && (loggingEnabled || diagnosticListenerActivityCreationEnabled))
315-
{
316-
activity = new Activity(ActivityName);
317-
}
318313
hasDiagnosticListener = false;
319314

320-
if (activity is null)
321-
{
322-
return null;
323-
}
324315
var headers = httpContext.Request.Headers;
325316
_propagator.ExtractTraceIdAndState(headers,
326317
static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
@@ -332,9 +323,44 @@ private static void RecordRequestStartEventLog(HttpContext httpContext)
332323
out var requestId,
333324
out var traceState);
334325

326+
Activity? activity = null;
327+
if (_activitySource.HasListeners())
328+
{
329+
if (ActivityContext.TryParse(requestId, traceState, true, out ActivityContext context))
330+
{
331+
// The requestId used W3C ID format. Unfortunately the ActivitySource.CreateActivity overload that
332+
// takes a string ID sets ActivityContext.IsRemote = false when it parses the string internally.
333+
// We work around that by using the ActivityContext ID overload and setting ActivityContext.IsRemote
334+
// to true after parsing it.
335+
activity = _activitySource.CreateActivity(ActivityName, ActivityKind.Server, context);
336+
}
337+
else
338+
{
339+
// Pass in the ID we got from the headers if there was one.
340+
activity = _activitySource.CreateActivity(ActivityName, ActivityKind.Server, string.IsNullOrEmpty(requestId) ? null! : requestId);
341+
}
342+
}
343+
344+
if (activity is null)
345+
{
346+
// CreateActivity didn't create an Activity (this is an optimization for the
347+
// case when there are no listeners). Let's create it here if needed.
348+
if (loggingEnabled || diagnosticListenerActivityCreationEnabled)
349+
{
350+
activity = new Activity(ActivityName);
351+
if (!string.IsNullOrEmpty(requestId))
352+
{
353+
activity.SetParentId(requestId);
354+
}
355+
}
356+
else
357+
{
358+
return null;
359+
}
360+
}
361+
335362
if (!string.IsNullOrEmpty(requestId))
336363
{
337-
activity.SetParentId(requestId);
338364
if (!string.IsNullOrEmpty(traceState))
339365
{
340366
activity.TraceStateString = traceState;

src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,50 @@ public void ActivityTraceParentAndTraceStateFromHeaders()
458458
Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key2" && pair.Value == "value2");
459459
}
460460

461+
[Fact]
462+
public void SamplersReceiveCorrectParentAndTraceIds()
463+
{
464+
var testSource = new ActivitySource(Path.GetRandomFileName());
465+
var hostingApplication = CreateApplication(out var features, activitySource: testSource);
466+
var parentId = "";
467+
var parentSpanId = "";
468+
var traceId = "";
469+
using var listener = new ActivityListener
470+
{
471+
ShouldListenTo = activitySource => ReferenceEquals(activitySource, testSource),
472+
Sample = (ref ActivityCreationOptions<ActivityContext> options) => ComputeActivitySamplingResult(ref options),
473+
ActivityStarted = activity =>
474+
{
475+
parentId = activity.ParentId;
476+
parentSpanId = activity.ParentSpanId.ToHexString();
477+
traceId = activity.TraceId.ToHexString();
478+
}
479+
};
480+
481+
ActivitySource.AddActivityListener(listener);
482+
483+
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
484+
{
485+
Headers = new HeaderDictionary()
486+
{
487+
{"traceparent", "00-35aae61e3e99044eb5ea5007f2cd159b-40a8bd87c078cb4c-00"},
488+
}
489+
});
490+
491+
hostingApplication.CreateContext(features);
492+
Assert.Equal("00-35aae61e3e99044eb5ea5007f2cd159b-40a8bd87c078cb4c-00", parentId);
493+
Assert.Equal("40a8bd87c078cb4c", parentSpanId);
494+
Assert.Equal("35aae61e3e99044eb5ea5007f2cd159b", traceId);
495+
496+
static ActivitySamplingResult ComputeActivitySamplingResult(ref ActivityCreationOptions<ActivityContext> options)
497+
{
498+
Assert.Equal("35aae61e3e99044eb5ea5007f2cd159b", options.TraceId.ToHexString());
499+
Assert.Equal("40a8bd87c078cb4c", options.Parent.SpanId.ToHexString());
500+
501+
return ActivitySamplingResult.AllDataAndRecorded;
502+
}
503+
}
504+
461505
[Fact]
462506
public void ActivityOnImportHookIsCalled()
463507
{

0 commit comments

Comments
 (0)