Skip to content

Commit 0c87ab6

Browse files
committed
Fix span parenting for isolated Azure Functions with ASP.NET Core integration
When HTTP proxying is enabled (ASP.NET Core integration), the host makes an HTTP call to the worker process. The HTTP client instrumentation automatically propagates trace context in HTTP headers. Previously, we were also injecting the Azure Functions host span context into the gRPC message, causing worker spans to be incorrectly parented to the root host span instead of the HTTP client span. Fix: Skip gRPC context injection when HTTP proxying is enabled, allowing the HTTP client instrumentation to handle context propagation naturally. This ensures worker spans are properly parented to the HTTP call span, creating the correct span hierarchy: - Root: azure_functions.invoke (host) - http.request: GET localhost:port (host -> worker) - azure_functions.invoke (worker) - (worker child spans) Fixes APMSVLS-58
1 parent 466dddb commit 0c87ab6

File tree

1 file changed

+22
-10
lines changed

1 file changed

+22
-10
lines changed

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/GrpcMessageConversionExtensionsToRpcHttpIntegration.cs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ internal static TReturn OnAsyncMethodEnd<TTarget, TReturn>(TTarget nullInstance,
4949
}
5050

5151
var tracer = Tracer.Instance;
52-
if (!tracer.Settings.IsIntegrationEnabled(AzureFunctionsCommon.IntegrationId)
53-
|| tracer.ActiveScope is not Scope { Span: { OperationName: AzureFunctionsCommon.OperationName } span })
52+
if (!tracer.Settings.IsIntegrationEnabled(AzureFunctionsCommon.IntegrationId))
5453
{
5554
return returnValue;
5655
}
@@ -76,19 +75,32 @@ internal static TReturn OnAsyncMethodEnd<TTarget, TReturn>(TTarget nullInstance,
7675

7776
var isHttpProxying = !string.IsNullOrEmpty(capabilities.GetCapabilityState("HttpUri"));
7877
var requiresRouteParameters = !string.IsNullOrEmpty(capabilities.GetCapabilityState("RequiresRouteParameters"));
79-
var useNullableHeaders = !string.IsNullOrEmpty(capabilities.GetCapabilityState("UseNullableValueDictionaryForHttp"));
8078

81-
// When proxying, this method returns a singleton value that we must not update, so we create a new one
82-
// If we're not proxying, we can safely inject the context into the provided gRPC request
83-
var typedData = isHttpProxying && !requiresRouteParameters
84-
? TypedDataHelper<TReturn>.CreateTypedData()
85-
: returnValue.DuckCast<ITypedData>();
79+
// When HTTP proxying is enabled (ASP.NET Core integration), the host will make an actual HTTP call
80+
// to the worker process. The HTTP client instrumentation will automatically create a span for this call
81+
// and propagate context via HTTP headers. We should NOT inject context into the gRPC message in this case,
82+
// as it would cause worker spans to be incorrectly parented to the Azure Functions host span instead of
83+
// the HTTP client span. See APMSVLS-58 and docs/development/AzureFunctions.md for details.
84+
if (isHttpProxying && !requiresRouteParameters)
85+
{
86+
// Let HTTP client instrumentation handle context propagation
87+
return returnValue;
88+
}
89+
90+
// For non-HTTP-proxying scenarios (e.g., timer triggers, non-ASP.NET Core HTTP triggers),
91+
// we need to inject context into the gRPC message
92+
if (tracer.ActiveScope is not Scope { Span: var span })
93+
{
94+
return returnValue;
95+
}
96+
97+
var useNullableHeaders = !string.IsNullOrEmpty(capabilities.GetCapabilityState("UseNullableValueDictionaryForHttp"));
98+
var typedData = returnValue.DuckCast<ITypedData>();
8699

87100
var context = new PropagationContext(span.Context, Baggage.Current);
88101
tracer.TracerManager.SpanContextPropagator.Inject(context, new RpcHttpHeadersCollection<TTarget>(typedData.Http, useNullableHeaders));
89102

90-
// Get the "real" value back out, whether it's the one we were provided or the new one we created
91-
return (TReturn)typedData.Instance!;
103+
return returnValue;
92104
}
93105
}
94106
#endif

0 commit comments

Comments
 (0)