From 04c070ccc1cb7f4e09593df4f44adf5e7556c09f Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Fri, 16 Jul 2021 18:22:35 +0900 Subject: [PATCH] Add HTTPClientMetrics (#3598) * Add HTTPClientMetrics * Update instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetrics.java Co-authored-by: Trask Stalnaker Co-authored-by: Trask Stalnaker --- .../instrumenter/http/HttpClientMetrics.java | 119 ++++++++++++++++++ .../http/HttpClientMetricsTest.java | 93 ++++++++++++++ .../ApacheHttpAsyncClientSingletons.java | 2 + .../v2_0/ApacheHttpClientSingletons.java | 2 + .../v4_0/ApacheHttpClientSingletons.java | 2 + .../v5_0/ApacheHttpClientSingletons.java | 2 + .../armeria/v1_3/ArmeriaTracingBuilder.java | 2 + .../v2_0/AsyncHttpClientSingletons.java | 2 + .../JettyClientInstrumenterBuilder.java | 2 + .../okhttp/v3_0/OkHttpTracingBuilder.java | 2 + 10 files changed, 228 insertions(+) create mode 100644 instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetrics.java create mode 100644 instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetricsTest.java diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetrics.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetrics.java new file mode 100644 index 0000000000..df83f717d3 --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetrics.java @@ -0,0 +1,119 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.instrumenter.http; + +import com.google.auto.value.AutoValue; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleValueRecorder; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.common.Labels; +import io.opentelemetry.api.metrics.common.LabelsBuilder; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextKey; +import io.opentelemetry.instrumentation.api.annotations.UnstableApi; +import io.opentelemetry.instrumentation.api.instrumenter.RequestListener; +import io.opentelemetry.instrumentation.api.instrumenter.RequestMetrics; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * {@link RequestListener} which keeps track of HTTP + * client metrics. + * + *

To use this class, you may need to add the {@code opentelemetry-api-metrics} artifact to your + * dependencies. + */ +@UnstableApi +public final class HttpClientMetrics implements RequestListener { + + private static final double NANOS_PER_MS = TimeUnit.MILLISECONDS.toNanos(1); + + private static final ContextKey HTTP_CLIENT_REQUEST_METRICS_STATE = + ContextKey.named("http-client-request-metrics-state"); + + private static final Logger logger = LoggerFactory.getLogger(HttpClientMetrics.class); + + /** + * Returns a {@link RequestMetrics} which can be used to enable recording of {@link + * HttpClientMetrics} on an {@link + * io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder}. + */ + @UnstableApi + public static RequestMetrics get() { + return HttpClientMetrics::new; + } + + private final DoubleValueRecorder duration; + + private HttpClientMetrics(Meter meter) { + duration = + meter + .doubleValueRecorderBuilder("http.client.duration") + .setUnit("milliseconds") + .setDescription("The duration of the outbound HTTP request") + .build(); + } + + @Override + public Context start(Context context, Attributes requestAttributes) { + long startTimeNanos = System.nanoTime(); + Labels durationLabels = durationLabels(requestAttributes); + + return context.with( + HTTP_CLIENT_REQUEST_METRICS_STATE, + new AutoValue_HttpClientMetrics_State(durationLabels, startTimeNanos)); + } + + @Override + public void end(Context context, Attributes responseAttributes) { + State state = context.get(HTTP_CLIENT_REQUEST_METRICS_STATE); + if (state == null) { + logger.debug( + "No state present when ending context {}. Cannot record HTTP request metrics.", context); + return; + } + duration.record( + (System.nanoTime() - state.startTimeNanos()) / NANOS_PER_MS, state.durationLabels()); + } + + private static Labels durationLabels(Attributes attributes) { + LabelsBuilder labels = Labels.builder(); + attributes.forEach( + (key, value) -> { + switch (key.getKey()) { + case "http.method": + case "http.host": + case "http.scheme": + case "http.flavor": + case "http.server_name": + case "net.host.name": + if (value instanceof String) { + labels.put(key.getKey(), (String) value); + } + break; + case "http.status_code": + case "net.host.port": + if (value instanceof Long) { + labels.put(key.getKey(), Long.toString((long) value)); + } + break; + default: + // fall through + } + }); + return labels.build(); + } + + @AutoValue + abstract static class State { + + abstract Labels durationLabels(); + + abstract long startTimeNanos(); + } +} diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetricsTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetricsTest.java new file mode 100644 index 0000000000..db01c19e97 --- /dev/null +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetricsTest.java @@ -0,0 +1,93 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.instrumenter.http; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.instrumenter.RequestListener; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.data.DoubleSummaryPointData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import java.util.Collection; +import org.junit.jupiter.api.Test; + +class HttpClientMetricsTest { + + @Test + void collectsMetrics() { + SdkMeterProvider meterProvider = SdkMeterProvider.builder().build(); + + RequestListener listener = HttpClientMetrics.get().create(meterProvider.get("test")); + + Attributes requestAttributes = + Attributes.builder() + .put("http.method", "GET") + .put("http.host", "host") + .put("http.scheme", "https") + .put("net.host.name", "localhost") + .put("net.host.port", 1234) + .put("rpc.service", "unused") + .put("rpc.method", "unused") + .build(); + + // Currently ignored. + Attributes responseAttributes = + Attributes.builder() + .put("http.flavor", "2.0") + .put("http.server_name", "server") + .put("http.status_code", 200) + .build(); + + Context context1 = listener.start(Context.current(), requestAttributes); + + Collection metrics = meterProvider.collectAllMetrics(); + assertThat(metrics).isEmpty(); + + Context context2 = listener.start(Context.current(), requestAttributes); + + metrics = meterProvider.collectAllMetrics(); + assertThat(metrics).isEmpty(); + + listener.end(context1, responseAttributes); + + metrics = meterProvider.collectAllMetrics(); + assertThat(metrics).hasSize(1); + assertThat(metrics) + .anySatisfy( + metric -> { + assertThat(metric.getName()).isEqualTo("http.client.duration"); + assertThat(metric.getDoubleSummaryData().getPoints()).hasSize(1); + DoubleSummaryPointData data = + metric.getDoubleSummaryData().getPoints().stream().findFirst().get(); + assertThat(data.getAttributes().asMap()) + .containsOnly( + entry(stringKey("http.host"), "host"), + entry(stringKey("http.method"), "GET"), + entry(stringKey("http.scheme"), "https"), + entry(stringKey("net.host.name"), "localhost"), + entry(stringKey("net.host.port"), "1234")); + assertThat(data.getPercentileValues()).isNotEmpty(); + }); + + listener.end(context2, responseAttributes); + + metrics = meterProvider.collectAllMetrics(); + assertThat(metrics).hasSize(1); + assertThat(metrics) + .anySatisfy( + metric -> { + assertThat(metric.getName()).isEqualTo("http.client.duration"); + assertThat(metric.getDoubleSummaryData().getPoints()).hasSize(1); + DoubleSummaryPointData data = + metric.getDoubleSummaryData().getPoints().stream().findFirst().get(); + assertThat(data.getPercentileValues()).isNotEmpty(); + }); + } +} diff --git a/instrumentation/apache-httpasyncclient-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientSingletons.java b/instrumentation/apache-httpasyncclient-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientSingletons.java index 99153044ec..a2f74bdd40 100644 --- a/instrumentation/apache-httpasyncclient-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientSingletons.java +++ b/instrumentation/apache-httpasyncclient-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientSingletons.java @@ -10,6 +10,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import io.opentelemetry.javaagent.instrumentation.api.instrumenter.PeerServiceAttributesExtractor; @@ -37,6 +38,7 @@ public final class ApacheHttpAsyncClientSingletons { .addAttributesExtractor(httpAttributesExtractor) .addAttributesExtractor(netAttributesExtractor) .addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor)) + .addRequestMetrics(HttpClientMetrics.get()) .newClientInstrumenter(new HttpHeaderSetter()); } diff --git a/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientSingletons.java b/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientSingletons.java index 847abf2726..b206be6795 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientSingletons.java +++ b/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientSingletons.java @@ -10,6 +10,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import io.opentelemetry.javaagent.instrumentation.api.instrumenter.PeerServiceAttributesExtractor; @@ -37,6 +38,7 @@ public final class ApacheHttpClientSingletons { .addAttributesExtractor(httpAttributesExtractor) .addAttributesExtractor(netAttributesExtractor) .addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor)) + .addRequestMetrics(HttpClientMetrics.get()) .newClientInstrumenter(new HttpHeaderSetter()); } diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientSingletons.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientSingletons.java index 95fca2cc9f..9b784a70c5 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientSingletons.java +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientSingletons.java @@ -10,6 +10,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import io.opentelemetry.javaagent.instrumentation.api.instrumenter.PeerServiceAttributesExtractor; @@ -37,6 +38,7 @@ public final class ApacheHttpClientSingletons { .addAttributesExtractor(httpAttributesExtractor) .addAttributesExtractor(netAttributesExtractor) .addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor)) + .addRequestMetrics(HttpClientMetrics.get()) .newClientInstrumenter(new HttpHeaderSetter()); } diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v5_0/ApacheHttpClientSingletons.java b/instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v5_0/ApacheHttpClientSingletons.java index 5ac88456c3..b7012b3aaa 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v5_0/ApacheHttpClientSingletons.java +++ b/instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v5_0/ApacheHttpClientSingletons.java @@ -10,6 +10,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import io.opentelemetry.javaagent.instrumentation.api.instrumenter.PeerServiceAttributesExtractor; @@ -38,6 +39,7 @@ public final class ApacheHttpClientSingletons { .addAttributesExtractor(httpAttributesExtractor) .addAttributesExtractor(netAttributesExtractor) .addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor)) + .addRequestMetrics(HttpClientMetrics.get()) .newClientInstrumenter(new HttpHeaderSetter()); } diff --git a/instrumentation/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTracingBuilder.java b/instrumentation/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTracingBuilder.java index df1efc4ba5..881f9a0441 100644 --- a/instrumentation/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTracingBuilder.java +++ b/instrumentation/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTracingBuilder.java @@ -15,6 +15,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; @@ -84,6 +85,7 @@ public final class ArmeriaTracingBuilder { .addAttributesExtractor(netAttributesExtractor) .addAttributesExtractors(additionalExtractors)); + clientInstrumenterBuilder.addRequestMetrics(HttpClientMetrics.get()); serverInstrumenterBuilder.addRequestMetrics(HttpServerMetrics.get()); return new ArmeriaTracing( diff --git a/instrumentation/async-http-client/async-http-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/v2_0/AsyncHttpClientSingletons.java b/instrumentation/async-http-client/async-http-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/v2_0/AsyncHttpClientSingletons.java index ef5737b531..3a62bdb530 100644 --- a/instrumentation/async-http-client/async-http-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/v2_0/AsyncHttpClientSingletons.java +++ b/instrumentation/async-http-client/async-http-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/asynchttpclient/v2_0/AsyncHttpClientSingletons.java @@ -10,6 +10,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import io.opentelemetry.javaagent.instrumentation.api.instrumenter.PeerServiceAttributesExtractor; @@ -38,6 +39,7 @@ public final class AsyncHttpClientSingletons { .addAttributesExtractor(httpAttributesExtractor) .addAttributesExtractor(netAttributesExtractor) .addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor)) + .addRequestMetrics(HttpClientMetrics.get()) .newClientInstrumenter(new HttpHeaderSetter()); } diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientInstrumenterBuilder.java b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientInstrumenterBuilder.java index 5ca1c4e953..e23ea7d266 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientInstrumenterBuilder.java +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientInstrumenterBuilder.java @@ -11,6 +11,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import java.util.ArrayList; @@ -54,6 +55,7 @@ public final class JettyClientInstrumenterBuilder { .addAttributesExtractor(httpAttributesExtractor) .addAttributesExtractor(netAttributesExtractor) .addAttributesExtractors(additionalExtractors) + .addRequestMetrics(HttpClientMetrics.get()) .newClientInstrumenter(new HttpHeaderSetter()); return instrumenter; } diff --git a/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/OkHttpTracingBuilder.java b/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/OkHttpTracingBuilder.java index 35b54b7465..4a88d511cb 100644 --- a/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/OkHttpTracingBuilder.java +++ b/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/OkHttpTracingBuilder.java @@ -10,6 +10,7 @@ import static io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtracto import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import io.opentelemetry.instrumentation.okhttp.v3_0.internal.OkHttpNetAttributesExtractor; @@ -54,6 +55,7 @@ public final class OkHttpTracingBuilder { .addAttributesExtractor(httpAttributesExtractor) .addAttributesExtractor(netAttributesExtractor) .addAttributesExtractors(additionalExtractors) + .addRequestMetrics(HttpClientMetrics.get()) .newInstrumenter(alwaysClient()); return new OkHttpTracing(instrumenter, openTelemetry.getPropagators()); }