reverse-proxy icon indicating copy to clipboard operation
reverse-proxy copied to clipboard

Telemetry - use the request path for name of trace

Open steverash opened this issue 1 year ago • 8 comments

What should we add or change to make your life better?

When using Yarp and OpenTelemetry with the Aspire dashboard, all requests show in the dashboard with the route match path as the display name. This means that you have to drill into each one to find the request you are looking for. It would be better if they showed the original request path.

Example

Image

Why is this important to you?

A change will enable a more useful experience when viewing telemetry.

steverash avatar Nov 28 '24 10:11 steverash

@samsp-msft does this look like the intended experience here? cc: @antonfirsov

MihaZupan avatar Dec 03 '24 12:12 MihaZupan

cc @JamesNK

davidfowl avatar Dec 10 '24 15:12 davidfowl

A trace shows the matched route so it's working as intended. But that doesn't create a good experience in this situation.

YARP could improve this by getting the request activity and change the name to the request path. You can use the IHttpActivityFeature which is available from the HttpContext. The feature will be set and an activity available if tracing is enabled.

JamesNK avatar Dec 11 '24 02:12 JamesNK

But presumably we wouldn't want to do so in YARP for all the same reasons we aren't doing it in ASP.NET to begin with? Though it is currently more likely to be a worse experience in YARP since the route is often a broad catch-all.

MihaZupan avatar Dec 14 '24 14:12 MihaZupan

I don't think changing the default to the full path would be the right answer, there's potentially an infinite amount of different paths that could match a route. It would be useful if we had a snippet in the docs showing how one can customize this though, e.g. to use route IDs or path instead. Here: https://microsoft.github.io/reverse-proxy/articles/distributed-tracing.html

Presumably it should be as simple as this (untested)

app.Use((context, next) =>
{
    if (context.Features.Get<IHttpActivityFeature>()?.Activity is { } activity)
    {
        activity.DisplayName = $"{context.Request.Method} {context.GetReverseProxyFeature().Route.Config.RouteId} {context.Request.Path}";
    }

    return next();
});

MihaZupan avatar Jan 14 '25 17:01 MihaZupan

I've given the suggestion above a try. I added the app.Use directly before the app.Run call.

However setting the DisplayName seems to have no effect on the dashboard activity name.

To prove whether it was having any effect - I added a tag alongside the setting of the DisplayName - which does seem to come through.

So this code

app.Use((context, next) =>
{
    if (context.Features.Get<IHttpActivityFeature>()?.Activity is { } activity)
    {
        activity.DisplayName = $"{context.Request.Method} {context.Request.Path}";
        activity.AddTag("display.name", $"{context.Request.Method} {context.Request.Path}");
    }
    return next();
});

Gives this in the dashboard Image

steverash avatar Jan 15 '25 10:01 steverash

Did anyone find a workaround how to override the span name to include the full request path ? It'll improve visibility in the dashboard.

mcrio avatar Feb 26 '25 13:02 mcrio

it's much bigger issue in metrics, because there's no parameter with a real path

m0a0k0s avatar Oct 20 '25 15:10 m0a0k0s

This workaround seems to work:

builder
    .Services.AddOpenTelemetry()
    .WithTracing(t =>
    {
        // ...
        t.AddAspNetCoreInstrumentation(a =>
        {
            a.EnrichWithHttpResponse = (activity, response) =>
            {
                var request = response.HttpContext.Request;
                activity.DisplayName = $"{request.Method} {request.Path}";
            };
        });
    });

This too, feels horrible though:

var listener = new ActivityListener
{
    ShouldListenTo = activitySource => activitySource.Name == "Microsoft.AspNetCore",
    ActivityStopped = activity =>
    {
        if (activity.OperationName == "Microsoft.AspNetCore.Hosting.HttpRequestIn")
        {
            activity.DisplayName = $"{activity.GetTagItem("http.request.method")} {activity.GetTagItem("url.path")}";
        }
    },
};

ActivitySource.AddActivityListener(listener);

Check https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/main/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs#L270

cezn avatar Dec 13 '25 13:12 cezn