Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Instrumentation.AspNetCore, Instrumentation.HttpClient] Add Enrichment instructions #2059

Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/OpenTelemetry.Instrumentation.AspNetCore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,52 @@ the library you can do so as follows:
});
```

#### Enriching ASP.NET Core Request Metrics

ASP.NET Core supports enriching request metrics using `IHttpMetricsTagsFeature`.
ysolomchenko marked this conversation as resolved.
Show resolved Hide resolved
This feature allows you to add custom tags to metrics like `http.server.request.duration`,
ysolomchenko marked this conversation as resolved.
Show resolved Hide resolved
which records the duration of HTTP requests on the server.

Here's an example of enriching the `http.server.request.duration` metric:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where do user specify that they intend to enrich http.server.request.duration metric, and nothing else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 99a4211

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am still confused. Where does user specify that they intend to enrich "http.server.request.duration" metric, and nothing else?
The example just shows how to get IHttpMetricsTagsFeature and add tags to it. But don't see any place where user selects which metric is this applied to.


```csharp
using Microsoft.AspNetCore.Http.Features;

var builder = WebApplication.CreateBuilder();
var app = builder.Build();

app.Use(async (context, next) =>
{
var tagsFeature = context.Features.Get<IHttpMetricsTagsFeature>();
if (tagsFeature != null)
{
var source = context.Request.Query["utm_medium"].ToString() switch
ysolomchenko marked this conversation as resolved.
Show resolved Hide resolved
{
"" => "none",
"social" => "social",
"email" => "email",
"organic" => "organic",
_ => "other"
};
tagsFeature.Tags.Add(new KeyValuePair<string, object?>("mkt_medium", source));
}

await next.Invoke();
});

app.MapGet("/", () => "Hello World!");

app.Run();
```

In this example:

* Middleware is added to enrich the ASP.NET Core request metric.
* `IHttpMetricsTagsFeature` is obtained from the `HttpContext`.
This feature is only available if someone is listening to the metric.
* A custom tag `mkt_medium` is added to the `http.server.request.duration` metric.
The value of this tag is determined based on the `utm_medium` query string parameter.

#### RecordException

This instrumentation automatically sets Activity Status to Error if an unhandled
Expand Down
60 changes: 60 additions & 0 deletions src/OpenTelemetry.Instrumentation.Http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,66 @@ var tracerProvider = Sdk.CreateTracerProviderBuilder()
.Build();
```

#### Enriching HttpClient Metrics

Metrics enrichment in HttpClient allows adding custom tags to metrics, such as
ysolomchenko marked this conversation as resolved.
Show resolved Hide resolved
`http.client.request.duration`. This is especially useful for categorizing
metrics in dashboards or alerts.

Using `HttpMetricsEnrichmentContext` for Enrichment
To enrich metrics, you can register callbacks with `HttpMetricsEnrichmentContext`.
This requires setting up a custom `DelegatingHandler` that intercepts requests
and adds custom tags before they are sent to the server.

Here's how you can implement a custom `DelegatingHandler` to enrich metrics:

```csharp
using System.Net.Http.Metrics;

using HttpClient client = new(new EnrichmentHandler() { InnerHandler = new HttpClientHandler() });

await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=A");
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=B");

sealed class EnrichmentHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpMetricsEnrichmentContext.AddCallback(request, static context =>
{
if (context.Response is not null) // Response is null when an exception occurs.
{
// Use any information available on the request or the response to emit custom tags.
string? value = context.Response.Headers.GetValues("Enrichment-Value").FirstOrDefault();
ysolomchenko marked this conversation as resolved.
Show resolved Hide resolved
if (value != null)
{
context.AddCustomTag("enrichment_value", value);
}
}
});
return base.SendAsync(request, cancellationToken);
}
}
```

If you're working with IHttpClientFactory, you can use AddHttpMessageHandler
to register the EnrichmentHandler:

```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Net.Http.Metrics;

ServiceCollection services = new();
services.AddHttpClient(Options.DefaultName).AddHttpMessageHandler(() => new EnrichmentHandler());

ServiceProvider serviceProvider = services.BuildServiceProvider();
HttpClient client = serviceProvider.GetRequiredService<HttpClient>();

await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=A");
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=B");
```

#### .NET Framework

##### Filter HttpWebRequest API
Expand Down