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 all 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
77 changes: 77 additions & 0 deletions src/OpenTelemetry.Instrumentation.AspNetCore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,83 @@ the library you can do so as follows:
});
```

#### Enriching ASP.NET Core Request Metrics

> [!IMPORTANT]
> Only applicable for .NET 8 and newer.

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 the default HTTP metrics collected
by ASP.NET Core.

### Automatic Application to HTTP Metrics

The tags added via `IHttpMetricsTagsFeature` are automatically applied to **all**
the HTTP metrics provided by ASP.NET Core's OpenTelemetry instrumentation, such as:

* `http.server.request.duration`
* `http.server.request.count`
* `http.server.request.size`
* `http.server.response.size`

If you are enriching metrics using `IHttpMetricsTagsFeature`, the enrichment will
apply to **all** relevant HTTP metrics unless further filtering is done during
the metrics collection/export phase.

### Example: Enriching `http.server.request.duration` Metric

Here's an example of enriching the `http.server.request.duration` metric by
adding a custom tag:

```csharp
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using Microsoft.AspNetCore.Http.Features;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenTelemetry()
.WithMetrics(builder => builder
.AddAspNetCoreInstrumentation()
.AddConsoleExporter());

var app = builder.Build();

// Middleware to enrich the request metric with a custom tag
app.Use(async (context, next) =>
{
var tagsFeature = context.Features.Get<IHttpMetricsTagsFeature>();
if (tagsFeature != null)
{
string utmMediumKey = "utm_medium";

if (context.Request.Query.TryGetValue(utmMediumKey, out var source) && !StringValues.IsNullOrEmpty(source))
{
tagsFeature.Tags.Add(new KeyValuePair<string, object?>(utmMediumKey, source));
}
}

await next.Invoke();
});

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

app.Run();
```

In this example:

* Automatic Metric Enrichment: The `IHttpMetricsTagsFeature` enriches all relevant
HTTP metrics (like `http.server.request.duration`) by default. There is no
need to explicitly specify the metric you want to enrich.
* Context-Specific Tags: In the middleware, custom tags such as utm_medium are
added to the request's metrics context. These tags will automatically appear in
the exported data for any related metrics.
* Customizing Exported Metrics: To focus on enriching or exporting a specific
metric (e.g. `http.server.request.duration`), you can control this at the exporting
stage, either by filtering specific metrics in the exporter or by customizing
the telemetry pipeline configuration.

#### RecordException

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

#### Enriching HttpClient Metrics

> [!IMPORTANT]
> Only applicable for .NET 8 and newer.

Metrics enrichment in HttpClient allows adding custom tags to metrics.
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://example.com");

sealed class EnrichmentHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpMetricsEnrichmentContext.AddCallback(request, static context =>
{
if (context.Request is not null) // Ensure the request is available.
{
// Use request information to add custom tags
string? userAgent = context.Request.Headers.UserAgent.ToString();
context.AddCustomTag("user_agent", userAgent ?? "unknown");
}
});

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://example.com");
```

#### .NET Framework

##### Filter HttpWebRequest API
Expand Down