rursprung opened a new pull request, #906:
URL: https://github.com/apache/httpcomponents-client/pull/906
(full disclosure: AI-generated, reviewed by me)
### What
Adds request and response body size metrics to `httpclient5-observation`
for classic and async clients:
| Meter | Type | Unit |
|---|---|---|
| `<prefix>.request.body.size` | `DistributionSummary` | bytes |
| `<prefix>.response.body.size` | `DistributionSummary` | bytes |
Enable with the new `ObservingOptions.MetricSet.BODY_SIZE`:
```java
ObservingOptions opts = ObservingOptions.builder()
.metrics(EnumSet.of(MetricSet.BASIC, MetricSet.BODY_SIZE))
.build();
HttpClientObservationSupport.enable(builder, obsReg, meterReg, opts);
```
All four `enable(...)` variants (classic, async, caching classic, caching
async) install the new `BodySizeExec` / `AsyncBodySizeExec` interceptors.
The interceptors are public, so they can also be added by hand.
### Why
Many libraries are built on HttpClient 5 and leave metrics to the user
(for example `opensearch-java`). Users want to know how big their payloads
are, for example large OpenSearch `_bulk` requests. The existing `IO`
counters only give a total.
Background:
* micrometer-metrics/micrometer#880 asks for HTTP request/response size
metrics. The Micrometer team said
([comment](https://github.com/micrometer-metrics/micrometer/issues/880#issuecomment-1625381050))
that it must be done per HTTP library: `Content-Length` is missing for
chunked bodies, and compression makes the body size differ from the bytes
on the network.
* micrometer-metrics/micrometer#7158 deprecates Micrometer's own hc5 binder
(since 1.17.0) in favor of `httpclient5-observation`. New HttpClient 5
instrumentation features therefore belong here.
### Design
* **Additive and opt-in.** The `IO` counters keep their names, types and
tags. Changing them to `DistributionSummary` would break dashboards and
alerts, and Micrometer does not allow two meter types with the same name.
So the new meters have new names and a new `MetricSet`.
`ObservingOptions.DEFAULT` (BASIC only) is unchanged. Note:
`ObservingOptions.allMetricSets()` now includes `BODY_SIZE`, so users of
that helper get the new meters after upgrading. japicmp reports the enum
change as compatible.
* **Names.** `<prefix>.request.body.size` / `<prefix>.response.body.size`
follow the module's `<prefix>.*` scheme. With the default prefix
`http.client` they are exactly the OpenTelemetry semantic convention
names `http.client.request.body.size` / `http.client.response.body.size`
(Prometheus: `http_client_request_body_size_bytes`). The older
Micrometer proposal `http.client.request.size` was not used because it
does not say "body" and does not match OTel.
* **Type.** `DistributionSummary` with base unit `bytes`, so users get
count, total, max, and (via `MetricConfig.percentiles` or a `MeterFilter`)
percentiles or histograms.
* **Tags.** Same low-cardinality tags as the request timer: `method`,
`status` (`599` if no response was received), and with
`TagLevel.EXTENDED` also `protocol` and `target`. `MetricConfig.commonTags`
and `ObservingOptions.tagCustomizer` apply. The `perUriIo` flag is not
used, because it is documented for the IO counters and would add a
high-cardinality `uri` tag.
* **Source of the size.**
* Classic: `HttpEntity#getContentLength()` of the request and response
entities.
* Async: `AsyncEntityProducer#getContentLength()` for the request,
`EntityDetails#getContentLength()` for the response.
* **No overhead on the data path.** Entities and data streams are never
wrapped, counted or buffered. The interceptors read one `long` per message
and record at most two values per exchange. `spanSampling` is honored.
When neither size is known, no tags are built and nothing is recorded.
* **Failures.** If no response is received (for example connection refused),
the request size is recorded with `status=599`, consistent with the timer.
HTTP error responses (4xx/5xx) are recorded with their status.
### Limitations
* **Unknown length is not recorded.** Bodies sent or received with
`Transfer-Encoding: chunked` (or any entity with `getContentLength() ==
-1`)
are skipped. This also applies to responses that the client decompresses
transparently: the decompressing wrappers report `-1`.
* **Uncompressed body sizes, not wire bytes.** The value is the body size as
the client sees it: before any `Content-Encoding` is applied to the
request, and after transparent decompression of the response. It does not
include headers or transfer framing, and it is not the number of bytes on
the network. For wire-level traffic, other tools (for example connection
level byte counts) are needed.
* The value is the declared length. If a response is aborted mid-body, the
declared length is still recorded.
### Possible follow-up (out of scope)
Count bytes for chunked or unknown-length bodies by wrapping request and
response entities (classic) and data producers/consumers (async). This adds
per-chunk overhead and more complex lifecycle handling (partial reads,
aborted streams, reuse of repeatable entities), so it should be a separate,
explicitly opt-in feature.
### Tests
* `BodySizeExecTest` (classic) and `AsyncBodySizeExecTest` (async):
known length, chunked/unknown length, no entity (`GET` / `204`), `GET`
with response body, error response (`500`), no response (connection
refused → `status=599`), extended and common tags, `spanSampling`
skip, and default options not installing the meters.
* `./mvnw -pl httpclient5-observation verify` passes: tests, checkstyle,
japicmp (against 5.6), Javadoc (`doclint all`) and apache-rat.
### Docs
* Javadoc on `BodySizeExec`, `AsyncBodySizeExec`,
`ObservingOptions.MetricSet.BODY_SIZE` and `HttpClientObservationSupport`
explains what is and is not measured. All new public API has
`@since 5.7`.
* The module guide (`observation.md`) lives in
`apache/httpcomponents-website`
and has no 5.7.x version yet. A follow-up website PR is proposed below.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]