[API Proposal]: AddHttpLatencyTelemetry for incoming HTTP request logs
- Dominant language
- C#
- Stars
- 3.2k
- Forks
- 894
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 23
Description
### Background and motivation
Server applications already collect a rich per-request latency breakdown through
the request latency telemetry services (`AddRequestLatencyTelemetry`,
`AddRequestCheckpoint`): named checkpoints marking stages of the pipeline,
measures, tags, and a total duration, all captured in the request's
`ILatencyContext`. Today that breakdown lives only in the latency exporters; it
is not attached to the request's own HTTP log entry.
`AddHttpLatencyTelemetry` closes that gap. It registers an `IHttpLogEnricher`
that reads the completed `ILatencyContext` for each incoming request and attaches
its latency breakdown to that request's HTTP log as a single `LatencyInfo` tag.
This lets an operator open one request log line and immediately see where the
time went - which checkpoints fired, the measured values, and the total duration -
without correlating across a separate latency signal.
Value:
- **Single-line diagnosis.** The latency breakdown travels with the request log,
so slow requests are explained in place rather than by joining two telemetry
streams on a request id.
- **Uses data already collected.** It consumes the existing `ILatencyContext`;
no new measurement cost, only projection of that data onto the log.
- **Completes the incoming/outgoing pair.** The outgoing-request counterpart,
`HttpClientLatencyTelemetryExtensions.AddHttpClientLatencyTelemetry`, already
exists for `HttpClient` calls. This is its incoming-request equivalent, so a
service can carry consistent latency enrichment on both sides.
The surface is intentionally minimal: one additive extension method on
`IServiceCollection`, no options type and no new public abstractions. Enrichment
targets and formatting are handled internally by the enricher, so there is no
configuration surface to lock down.
### API Proposal
```csharp
namespace Microsoft.Extensions.DependencyInjection;
///
/// Extensions for enriching incoming HTTP request logs with latency telemetry.
///
public static class HttpLatencyTelemetryServiceCollectionExtensions
{
///
/// Adds an enricher that appends latency information from the request's latency
/// context to incoming HTTP request logs.
///
/// The to add to.
/// The value of .
/// is .
public static IServiceCollection AddHttpLatencyTelemetry(this IServiceCollection services);
}
```
The enricher writes one tag per enriched request:
- Key: `LatencyInfo` (matching the outgoing-request enricher's tag key).
- Value: a compact, ordered projection of the `ILatencyContext` - data version,
originating client application name, then the request's tags, checkpoints
(with elapsed milliseconds), measures, and total duration.
### API Usage
```csharp
var builder = WebApplication.CreateBuilder(args);
// Collect the per-request latency breakdown.
builder.Services.AddRequestLatencyTelemetry();
builder.Services.AddRequestCheckpoint();
// Attach that breakdown to each incoming request's HTTP log.
builder.Services.AddHttpLatencyTelemetry();
var app = builder.Build();
app.UseRequestLatencyTelemetry();
```
A slow request's log line then carries a `LatencyInfo` tag describing where the
time was spent, so it can be diagnosed directly from the request log.
### Alternative Designs
_No response_
### Risks
The surface is a single additive extension method, so the commitment is small.
The main constraint is the `LatencyInfo` tag value format: once consumers parse
it, its layout is effectively part of the contract even though it is a string.
Contributor guide
Assessment
This issue has not been assessed yet.