Observability (Micrometer / OpenTelemetry)
Since 5.6, HttpClient ships an optional module, httpclient5-observation, that plugs straight into
Micrometer (metrics + observations) and can bridge to OpenTelemetry (traces). The goal is simple:
give you drop-in visibility of latency, throughput, I/O, connection-pool health, DNS, and TLS—without
rewriting application code or coupling the core client to any monitoring stack.
What you get out of the box:
- Request latency timers and response counters for classic and async clients
- Request/response I/O byte counters (opt-in URI tagging to control cardinality)
- Connection pool gauges (leased / available / pending) for classic and async managers
- DNS resolution timers/counters (resolve + canonical lookups)
- TLS handshake timers/counters (ok / error / cancel outcomes)
- Micrometer Observation interceptors that you can bridge to OpenTelemetry for end-to-end traces
How it fits:
- Opt-in by design. Nothing changes unless you add Micrometer to the classpath and call the provided
enable(...)helpers. The observation module is separate; core HttpClient has no hard dependency. - Classic, Async, and Caching are all supported. For caching builders, interceptors are inserted after the caching stage so metrics reflect the effective exchange.
- Low friction. A single call wires timers/counters and, if you want them, pool gauges, DNS/TLS meters,
and observation spans. You keep full control via two small configs:
ObservingOptions– choose metric groups (BASIC, IO, CONN_POOL, TLS, DNS), tag level (LOWfor minimal,EXTENDEDfor richer tags), per-URI sampling, and a tag customizer hook.MetricConfig– set the metric name prefix (http.clientby default), SLO bucket(s), percentiles, optional per-URI I/O tagging, and common tags to stamp on every meter.
- Safe by default. Per-URI I/O tagging is off to avoid high cardinality. Turn it on only where you know it’s useful (e.g., controlled path templates).
- Thread-safe & lightweight. The helpers are stateless. Interceptors register meters lazily, and pool gauges bind once to the connection manager (no reflection).
- Your registry, your rules. Use any Micrometer registry (Prometheus, OTLP, Cloud vendor). If you also enable
ObservationRegistrywith Micrometer Tracing, you can export spans viamicrometer-tracing-bridge-otel.
Typical flow:
- Add
httpclient5-observationand whichever Micrometer bits you actually use (all Micrometer deps can stayoptional). - Build your client as usual; call
HttpClientObservationSupport.enable(...)on the builder (classic/async/caching variants provided). - (Optional) Bind pool gauges after you’ve attached a pooling connection manager.
- (Optional) Wrap your DNS resolver with
MeteredDnsResolverand your TLS strategy withMeteredTlsStrategyif you want those timing/outcome meters as well. - (Optional) Bridge the
ObservationRegistryto OpenTelemetry to get client spans alongside metrics.
Practical notes:
- Naming: all meters are prefixed by
MetricConfig.prefix(defaulthttp.client). Examples:http.client.request(timer),http.client.response(counter),http.client.inflight{kind=classic|async}(gauge),http.client.pool.*(gauges),http.client.dns.*,http.client.tls.*. - Tagging: minimal set is
methodandstatus.EXTENDEDaddsprotocolandtarget; DNS/TLS addhost/sni. You can appendcommonTagsglobally and mutate per-request tags with aTagCustomizer. - Overhead: the fast path short-circuits when
spanSamplingsays “skip” (no timer/counter work). Publishing percentiles and fine-grained SLOs costs more—configure only what you need. - Compatibility: works with existing client code; you instrument the builder, not call sites. Suitable for
libraries: you can expose an instrumented
CloseableHttpClient/CloseableHttpAsyncClientto callers without leaking Micrometer types into their APIs.
Nothing is enabled unless you add Micrometer and call the opt-in helpers.
Status: Introduced in 5.6 (
@since 5.6). Artifacts are optional; core modules do not depend on Micrometer/OTel.
Dependency
Maven
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5-observation</artifactId>
<version>5.6-alpha1</version>
</dependency>
## Dependency
**Maven**
```xml
<!-- Required: the optional observability module itself -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5-observation</artifactId>
<version>5.6-alpha1</version>
</dependency>
<!-- Optional: add only if you actually use Micrometer metrics / observations / Prometheus / tracing -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>${micrometer.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-observation</artifactId>
<version>${micrometer.version}</version>
<optional>true</optional>
</dependency>
<!-- Choose one or more registries you use (e.g., Prometheus) -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>${micrometer.version}</version>
<optional>true</optional>
</dependency>
<!-- Optional Micrometer→OpenTelemetry bridge for tracing spans -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
<version>${micrometer.tracing.version}</version>
<optional>true</optional>
</dependency>



