This version is still in development and is not considered stable yet. For the latest stable version, please use Micrometer 1.17.1!

Java HttpClient instrumentation

Since Java 11, an HttpClient is provided as part of the JDK. See this introduction to it. Micrometer provides instrumentation of this via a micrometer-java11 module. This module requires Java 11 or later.

Installing

It is recommended to use the BOM provided by Micrometer (or your framework if any), you can see how to configure it here. The examples below assume you are using a BOM.

Gradle

After the BOM is configured, add the following dependency:

implementation 'io.micrometer:micrometer-java11'
The version is not needed for this dependency since it is defined by the BOM.

Maven

After the BOM is configured, add the following dependency:

<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-java11</artifactId>
</dependency>
The version is not needed for this dependency since it is defined by the BOM.

Usage

Create an HttpClient as you normally would. For example:

HttpClient httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(2)).build();

You can instrument this HttpClient as follows with an ObservationRegistry:

HttpClient observedClient = MicrometerHttpClient.instrumentationBuilder(httpClient, meterRegistry)
    .observationRegistry(observationRegistry)
    .build();

When using an ObservationRegistry, you can customize the tags produced by the instrumentation with an HttpClientObservationConvention. Extend DefaultHttpClientObservationConvention and add to its low-cardinality key values to retain the default tags. For example, the following convention adds the request host as a low-cardinality clientName tag. Only use the request host as a low-cardinality tag when the client calls a bounded set of hosts.

static class ClientNameObservationConvention extends DefaultHttpClientObservationConvention {

    @Override
    public KeyValues getLowCardinalityKeyValues(HttpClientContext context) {
        HttpRequest.Builder requestBuilder = context.getCarrier();
        if (requestBuilder == null) {
            return super.getLowCardinalityKeyValues(context);
        }
        String host = requestBuilder.build().uri().getHost();
        return super.getLowCardinalityKeyValues(context).and("clientName", host != null ? host : "UNKNOWN");
    }

}

Pass the custom convention to the instrumentation builder together with the ObservationRegistry. The following example creates a registry and registers a DefaultMeterObservationHandler to record metrics. If your framework already provides an ObservationRegistry configured to record metrics, you can use that registry instead.

ObservationRegistry observationRegistry = ObservationRegistry.create();
observationRegistry.observationConfig().observationHandler(new DefaultMeterObservationHandler(meterRegistry));

HttpClient observedClient = MicrometerHttpClient.instrumentationBuilder(httpClient, meterRegistry)
    .observationRegistry(observationRegistry)
    .customObservationConvention(new ClientNameObservationConvention())
    .build();

Alternatively, if you are not using an ObservationRegistry, you can instrument with only a MeterRegistry as follows:

HttpClient observedClient = MicrometerHttpClient.instrumentationBuilder(httpClient, meterRegistry).build();