Telemetry - use the request path for name of trace
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
Why is this important to you?
A change will enable a more useful experience when viewing telemetry.
@samsp-msft does this look like the intended experience here? cc: @antonfirsov
cc @JamesNK
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.
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.
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();
});
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
Did anyone find a workaround how to override the span name to include the full request path ? It'll improve visibility in the dashboard.
it's much bigger issue in metrics, because there's no parameter with a real path
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