|
| 1 | +--- |
| 2 | +title: Monitor and analyze HTTP client performance |
| 3 | +description: Learn how to use the HttpClientLatency with dependency injection in your .NET workloads. |
| 4 | +author: IEvangelist |
| 5 | +ms.author: dapine |
| 6 | +ms.date: 09/29/2025 |
| 7 | +ai-usage: ai-assisted |
| 8 | +--- |
| 9 | + |
| 10 | +# HTTP client latency telemetry in .NET |
| 11 | + |
| 12 | +When you build applications that communicate over HTTP, it's important to observe request performance characteristics. |
| 13 | +The <xref:Microsoft.Extensions.DependencyInjection.HttpClientLatencyTelemetryExtensions.AddHttpClientLatencyTelemetry*> |
| 14 | +extension enables collection of detailed timing information for outgoing HTTP calls with no changes to calling code. |
| 15 | +It plugs into the existing `HttpClientFactory` pipeline to capture stage timings across the request lifecycle, record |
| 16 | +HTTP protocol details, measure garbage collection impact where the runtime exposes that data, and emit a uniform |
| 17 | +telemetry shape suitable for performance analysis and tuning.Enable them by calling `AddHttpClientLatencyTelemetry()` extension method. |
| 18 | +The built‑in handler creates an `ILatencyContext` per outbound request and populates measures by the time the inner |
| 19 | +pipeline completes. Consume them after `await base.SendAsync(...)` in a later delegating handler (added after telemetry) |
| 20 | +and export to your metrics backend. Example: |
| 21 | + |
| 22 | +Register extension method: |
| 23 | + |
| 24 | +:::code language="csharp" source="snippets/http/latency/RegisterHandler.cs" range="3-24" highlight="11"::: |
| 25 | + |
| 26 | +Access the context: |
| 27 | + |
| 28 | +:::code language="csharp" source="snippets/http/latency/HttpLatencyExportHandler.cs" range="4-23" highlight="12,15"::: |
| 29 | + |
| 30 | +### [.NET CLI](#tab/dotnet-cli) |
| 31 | + |
| 32 | +```dotnetcli |
| 33 | +dotnet add package Microsoft.Extensions.Http.Diagnostics --version 9.10.0 |
| 34 | +``` |
| 35 | + |
| 36 | +### [PackageReference](#tab/package-reference) |
| 37 | + |
| 38 | +```xml |
| 39 | +<PackageReference Include="Microsoft.Extensions.Http.Diagnostics" Version="9.10.0" /> |
| 40 | +``` |
| 41 | + |
| 42 | +--- |
| 43 | + |
| 44 | +For more information, see [dotnet package add](../tools/dotnet-package-add.md) or [Manage package dependencies in .NET applications](../tools/dependencies.md). |
| 45 | + |
| 46 | +### Register HTTP client latency telemetry |
| 47 | + |
| 48 | +To add HTTP client latency telemetry to your application, call the <xref:Microsoft.Extensions.DependencyInjection.HttpClientLatencyTelemetryExtensions.AddHttpClientLatencyTelemetry*> extension method when configuring your services: |
| 49 | + |
| 50 | +:::code language="csharp" source="snippets/http/latency/Program.cs" id="extensions" highlight="7"::: |
| 51 | + |
| 52 | +This registration adds a `DelegatingHandler` to all HTTP clients created through <xref:System.Net.Http.IHttpClientFactory>, collecting detailed latency information for each request. |
| 53 | + |
| 54 | +### Configure telemetry options |
| 55 | + |
| 56 | +You configure telemetry collection through the <xref:Microsoft.Extensions.Http.Latency.HttpClientLatencyTelemetryOptions> ([standard options pattern](https://learn.microsoft.com/dotnet/core/extensions/options)). |
| 57 | +You can supply values either with a delegate or by binding configuration (for example, `appsettings.json`). |
| 58 | +The options instance is resolved once per handler pipeline so changes apply to new clients/handlers. |
| 59 | + |
| 60 | +:::code language="csharp" source="snippets/http/latency/Program.cs" range="23-31" highlight="1-5,8,9"::: |
| 61 | + |
| 62 | +### Configuration options |
| 63 | + |
| 64 | +The <xref:Microsoft.Extensions.Http.Latency.HttpClientLatencyTelemetryOptions> class offers the following settings: |
| 65 | + |
| 66 | +| Option | Type | Default | Description | When to disable | |
| 67 | +|--------------------------------|---------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| |
| 68 | +| EnableDetailedLatencyBreakdown | Boolean | `true` | Enables fine-grained phase timing for each HttpClient request (for example, connection establishment, headers sent, first byte, completion) to produce a breakdown of total latency. Adds a small extra CPU/time measurement cost, no wire overhead. | Set to `false` only in very high-throughput scenarios where minimal overhead is required and total duration alone is sufficient. | |
| 69 | + |
| 70 | +### Collected telemetry data |
| 71 | + |
| 72 | +When HTTP client latency telemetry is enabled, it captures phase timestamps, selected measures (where supported), and protocol attributes used for performance analysis. |
| 73 | + |
| 74 | +#### Timing checkpoints |
| 75 | + |
| 76 | +Timestamps are recorded for key stages of the HTTP request lifecycle: |
| 77 | + |
| 78 | +| Phase | Start Event | End Event | Notes | |
| 79 | +|-------------------------|----------------------------|----------------------------|---------------------------------------------------------| |
| 80 | +| DNS resolution | Http.NameResolutionStart | Http.NameResolutionEnd | Host name lookup (may be cached and skipped). | |
| 81 | +| Socket connection | Http.SocketConnectStart | Http.SocketConnectEnd | CP (and TLS handshake if combined by handler). | |
| 82 | +| Connection establishment| | Http.ConnectionEstablished | Marks usable connection after handshake. | |
| 83 | +| Request headers | Http.RequestHeadersStart | Http.RequestHeadersEnd | Writing request headers to the wire/buffer. | |
| 84 | +| Request content | Http.RequestContentStart | Http.RequestContentEnd | Streaming or buffering request body. | |
| 85 | +| Response headers | Http.ResponseHeadersStart | Http.ResponseHeadersEnd | First byte to completion of header parsing. | |
| 86 | +| Response content | Http.ResponseContentStart | Http.ResponseContentEnd | Reading full response body (to completion or disposal). | |
| 87 | + |
| 88 | +#### Measures (platform dependent) |
| 89 | + |
| 90 | +Measures quantify latency contributors that raw phase checkpoints cannot (GC pause overlap, connection churn, other |
| 91 | +accumulated counts or durations). They are collected in an in‑memory latency context created when you call |
| 92 | +`AddHttpClientLatencyTelemetry()`. Nothing is emitted automatically: the context simply accumulates checkpoints, measures, |
| 93 | +and tags until the request completes. If you also enable HTTP client logging enrichment with `AddExtendedHttpClientLogging()`, |
| 94 | +the completed context is flattened into a single structured log field named `LatencyInfo` (version marker, server name if available, then tag, checkpoint, and measure name/value sequences). |
| 95 | + |
| 96 | +That log field is the only built‑in output artifact; no metrics or traces are produced unless you add your own exporter. |
| 97 | +To surface them as metrics, read the context after the request pipeline returns and record (for example) GC pause overlap |
| 98 | +to a histogram and connection initiations to a counter, optionally dimensioned by protocol version. |
| 99 | + |
| 100 | +| Name | Description | |
| 101 | +|--------------------------|-------------------------------------------------------------------------| |
| 102 | +| Http.GCPauseTime | Total GC pause duration overlapping the request. | |
| 103 | +| Http.ConnectionInitiated | Emitted when a new underlying connection (not pooled reuse) is created. | |
| 104 | + |
| 105 | +#### Tags |
| 106 | + |
| 107 | +Use tags to attach stable categorical dimensions to each request so you can segment, filter, and aggregate metrics |
| 108 | +and logs without reprocessing raw data. They are low‑cardinality classification labels (not timings) captured |
| 109 | +in the latency context and, if HTTP client log enrichment is enabled, serialized into a single LatencyInfo log field. |
| 110 | +Enable enrichment at application startup by adding the logging extension (for all clients or per client) along with |
| 111 | +latency telemetry, for example: |
| 112 | + |
| 113 | +:::code language="csharp" source="snippets/http/latency/Program.cs" range="36-39" highlight="2,3"::: |
| 114 | + |
| 115 | +After this, outbound requests logged through the structured logging pipeline will include the `LatencyInfo` property |
| 116 | +containing the flattened tags, checkpoints, and measures. No metrics or traces are emitted automatically for tags; |
| 117 | +export them yourself (e.g., turn tag values into metric dimensions or `Activity` tags) if you need them outside logs. |
| 118 | + |
| 119 | +| Tag | Description | |
| 120 | +|--------------|-----------------------------------------------------------------| |
| 121 | +| Http.Version | HTTP protocol version negotiated/used (for example, 1.1, 2, 3). | |
| 122 | + |
| 123 | +## Usage example |
| 124 | + |
| 125 | +These components enable tracking and reporting the latency of HTTP client request processing. |
| 126 | + |
| 127 | +You can register the services using the following methods: |
| 128 | + |
| 129 | +:::code language="csharp" source="snippets/http/latency/Program.cs" range="44-53" highlight="1,2,4-6, 8-10"::: |
| 130 | + |
| 131 | +For example: |
| 132 | + |
| 133 | +:::code language="csharp" source="snippets/http/latency/Program.cs" range="58-75" highlight="10,13,16"::: |
| 134 | + |
| 135 | +### Platform considerations |
| 136 | + |
| 137 | +HTTP client latency telemetry runs on all supported targets (.NET 9, .NET 8, .NET Standard 2.0, and .NET Framework 4.6.2). |
| 138 | +Core timing checkpoints are always collected. The GC pause metric (Http.GCPauseTime) is emitted only when running on .NET 8 or .NET 9. |
| 139 | +The implementation detects platform capabilities at run time and enables what is supported without additional configuration. |
0 commit comments