Roger Johansson
Roger Johansson

Reputation: 23214

OpenTelemetry .NET HttpClient not propagating TraceId

I am trying to get Tracing using OpenTelemetry to work with HttpClient in an integration test for an Asp.NET API.

Tracing works for everything else, we get traces from the API controllers and all other instrumented libraries.

Configuration looks like this:

webApplicationBuilder.Services.AddOpenTelemetryTracing(b =>
    b.SetResourceBuilder(resourceBuilder)
        .AddHttpClientInstrumentation()
        .AddAspNetCoreInstrumentation()
        .AddProtoActorInstrumentation()
        .AddRedisInstrumentation()
        .AddOtlpExporter(options =>
        {
            ConfigureOpenTelemetry(webApplicationBuilder, options);
        })
);

But when calling the API using HttpClient. the current TraceId is not propagated. The integration test uses a MyAppFactory : WebApplicationFactory<Program> for the test. And the HttpClient is constructed in the tests using the factory.CreateClient() of the MyAppFactory.

If I check the Activity.Current.TraceId inside my integration test. I get one value. Then directly after, when I call the API using the HttpClient, the API controller reports a different TraceId. There are also no w3c trace context headers in the Request inside the controller method.

What am I missing here?

Upvotes: 3

Views: 3382

Answers (1)

X-Cubed
X-Cubed

Reputation: 1899

I had a look into this and discovered that SocketsHttpHandler has a code path to initialize a DiagnosticsHandler that emits the HTTP request events, which other tools like OpenTelemetry listen for to trace requests.

However, as the HttpClient used with WebApplicationFactory doesn't need to send network requests (as the test application is loaded within the same process), it has a custom ClientHandler that doesn't care about diagnostic events.

This sounds like an oversight in either WebApplicationFactory or OpenTelemetry, but either way it doesn't seem to work.

I think the workaround would be to pass a custom handler into Factory.CreateClient, and have that handler inject the traceparent HTTP header manually based on Activity.Current, following the behaviour of the code in TraceContextPropagator.cs as a template.

Upvotes: 3

Related Questions