Extract HTTP client experimental metrics to a separate class (#8769)

This commit is contained in:
Mateusz Rzeszutek 2023-07-18 17:34:39 +02:00 committed by GitHub
parent 62ca215297
commit 59e2da5aa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 825 additions and 267 deletions

View File

@ -0,0 +1,96 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.instrumenter.http;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMessageBodySizeUtil.getHttpRequestBodySize;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMessageBodySizeUtil.getHttpResponseBodySize;
import static io.opentelemetry.instrumentation.api.instrumenter.http.TemporaryMetricsView.applyClientDurationAndSizeView;
import static java.util.logging.Level.FINE;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
import io.opentelemetry.instrumentation.api.instrumenter.OperationListener;
import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics;
import java.util.logging.Logger;
/**
* {@link OperationListener} which keeps track of <a
* href="https://github.com/open-telemetry/semantic-conventions/blob/main/specification/metrics/semantic_conventions/http-metrics.md#http-client">non-stable
* HTTP client metrics</a>: <a
* href="https://github.com/open-telemetry/semantic-conventions/blob/main/specification/metrics/semantic_conventions/http-metrics.md#metric-httpclientrequestsize">the
* request size </a> and the <a
* href="https://github.com/open-telemetry/semantic-conventions/blob/main/specification/metrics/semantic_conventions/http-metrics.md#metric-httpclientresponsesize">
* the response size</a>.
*/
public final class HttpClientExperimentalMetrics implements OperationListener {
private static final ContextKey<Attributes> HTTP_CLIENT_REQUEST_METRICS_START_ATTRIBUTES =
ContextKey.named("http-client-experimental-metrics-start-attributes");
private static final Logger logger =
Logger.getLogger(HttpClientExperimentalMetrics.class.getName());
/**
* Returns a {@link OperationMetrics} which can be used to enable recording of {@link
* HttpClientExperimentalMetrics} on an {@link
* io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder}.
*/
public static OperationMetrics get() {
return HttpClientExperimentalMetrics::new;
}
private final LongHistogram requestSize;
private final LongHistogram responseSize;
private HttpClientExperimentalMetrics(Meter meter) {
requestSize =
meter
.histogramBuilder("http.client.request.size")
.setUnit("By")
.setDescription("The size of HTTP request messages")
.ofLongs()
.build();
responseSize =
meter
.histogramBuilder("http.client.response.size")
.setUnit("By")
.setDescription("The size of HTTP response messages")
.ofLongs()
.build();
}
@Override
public Context onStart(Context context, Attributes startAttributes, long startNanos) {
return context.with(HTTP_CLIENT_REQUEST_METRICS_START_ATTRIBUTES, startAttributes);
}
@Override
public void onEnd(Context context, Attributes endAttributes, long endNanos) {
Attributes startAttributes = context.get(HTTP_CLIENT_REQUEST_METRICS_START_ATTRIBUTES);
if (startAttributes == null) {
logger.log(
FINE,
"No state present when ending context {0}. Cannot record HTTP request metrics.",
context);
return;
}
Attributes sizeAttributes = applyClientDurationAndSizeView(startAttributes, endAttributes);
Long requestBodySize = getHttpRequestBodySize(endAttributes, startAttributes);
if (requestBodySize != null) {
requestSize.record(requestBodySize, sizeAttributes, context);
}
Long responseBodySize = getHttpResponseBodySize(endAttributes, startAttributes);
if (responseBodySize != null) {
responseSize.record(responseBodySize, sizeAttributes, context);
}
}
}

View File

@ -5,8 +5,6 @@
package io.opentelemetry.instrumentation.api.instrumenter.http;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMessageBodySizeUtil.getHttpRequestBodySize;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMessageBodySizeUtil.getHttpResponseBodySize;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMetricsUtil.createDurationHistogram;
import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpMetricsUtil.nanosToUnit;
import static io.opentelemetry.instrumentation.api.instrumenter.http.TemporaryMetricsView.applyClientDurationAndSizeView;
@ -15,7 +13,6 @@ import static java.util.logging.Level.FINE;
import com.google.auto.value.AutoValue;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
@ -31,7 +28,7 @@ import java.util.logging.Logger;
public final class HttpClientMetrics implements OperationListener {
private static final ContextKey<State> HTTP_CLIENT_REQUEST_METRICS_STATE =
ContextKey.named("http-client-request-metrics-state");
ContextKey.named("http-client-metrics-state");
private static final Logger logger = Logger.getLogger(HttpClientMetrics.class.getName());
@ -45,27 +42,11 @@ public final class HttpClientMetrics implements OperationListener {
}
private final DoubleHistogram duration;
private final LongHistogram requestSize;
private final LongHistogram responseSize;
private HttpClientMetrics(Meter meter) {
duration =
createDurationHistogram(
meter, "http.client.duration", "The duration of the outbound HTTP request");
requestSize =
meter
.histogramBuilder("http.client.request.size")
.setUnit("By")
.setDescription("The size of HTTP request messages")
.ofLongs()
.build();
responseSize =
meter
.histogramBuilder("http.client.response.size")
.setUnit("By")
.setDescription("The size of HTTP response messages")
.ofLongs()
.build();
}
@Override
@ -90,16 +71,6 @@ public final class HttpClientMetrics implements OperationListener {
applyClientDurationAndSizeView(state.startAttributes(), endAttributes);
duration.record(
nanosToUnit(endNanos - state.startTimeNanos()), durationAndSizeAttributes, context);
Long requestBodySize = getHttpRequestBodySize(endAttributes, state.startAttributes());
if (requestBodySize != null) {
requestSize.record(requestBodySize, durationAndSizeAttributes, context);
}
Long responseBodySize = getHttpResponseBodySize(endAttributes, state.startAttributes());
if (responseBodySize != null) {
responseSize.record(responseBodySize, durationAndSizeAttributes, context);
}
}
@AutoValue

View File

@ -0,0 +1,150 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.instrumenter.http;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.OperationListener;
import io.opentelemetry.instrumentation.api.instrumenter.net.internal.NetAttributes;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
class HttpClientExperimentalMetricsTest {
@Test
void collectsMetrics() {
InMemoryMetricReader metricReader = InMemoryMetricReader.create();
SdkMeterProvider meterProvider =
SdkMeterProvider.builder().registerMetricReader(metricReader).build();
OperationListener listener =
HttpClientExperimentalMetrics.get().create(meterProvider.get("test"));
Attributes requestAttributes =
Attributes.builder()
.put("http.method", "GET")
.put("http.url", "https://localhost:1234/")
.put("http.target", "/")
.put("http.scheme", "https")
.put("net.peer.name", "localhost")
.put("net.peer.port", 1234)
.put("http.request_content_length", 100)
.build();
Attributes responseAttributes =
Attributes.builder()
.put("http.status_code", 200)
.put("http.response_content_length", 200)
.put(NetAttributes.NET_PROTOCOL_NAME, "http")
.put(NetAttributes.NET_PROTOCOL_VERSION, "2.0")
.put("net.sock.peer.addr", "1.2.3.4")
.put("net.sock.peer.name", "somehost20")
.put("net.sock.peer.port", 8080)
.build();
Context parent =
Context.root()
.with(
Span.wrap(
SpanContext.create(
"ff01020304050600ff0a0b0c0d0e0f00",
"090a0b0c0d0e0f00",
TraceFlags.getSampled(),
TraceState.getDefault())));
Context context1 = listener.onStart(parent, requestAttributes, nanos(100));
assertThat(metricReader.collectAllMetrics()).isEmpty();
Context context2 = listener.onStart(Context.root(), requestAttributes, nanos(150));
assertThat(metricReader.collectAllMetrics()).isEmpty();
listener.onEnd(context1, responseAttributes, nanos(250));
assertThat(metricReader.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(100 /* bytes */)
.hasAttributesSatisfying(
equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200),
equalTo(NetAttributes.NET_PROTOCOL_NAME, "http"),
equalTo(NetAttributes.NET_PROTOCOL_VERSION, "2.0"),
equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"),
equalTo(SemanticAttributes.NET_PEER_PORT, 1234),
equalTo(
SemanticAttributes.NET_SOCK_PEER_ADDR, "1.2.3.4"))
.hasExemplarsSatisfying(
exemplar ->
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00")))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(200 /* bytes */)
.hasAttributesSatisfying(
equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200),
equalTo(NetAttributes.NET_PROTOCOL_NAME, "http"),
equalTo(NetAttributes.NET_PROTOCOL_VERSION, "2.0"),
equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"),
equalTo(SemanticAttributes.NET_PEER_PORT, 1234),
equalTo(
SemanticAttributes.NET_SOCK_PEER_ADDR, "1.2.3.4"))
.hasExemplarsSatisfying(
exemplar ->
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00")))));
listener.onEnd(context2, responseAttributes, nanos(300));
assertThat(metricReader.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(200 /* bytes */))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(400 /* bytes */))));
}
private static long nanos(int millis) {
return TimeUnit.MILLISECONDS.toNanos(millis);
}
}

View File

@ -106,55 +106,7 @@ class HttpClientMetricsTest {
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00"))
.hasBucketBoundaries(DEFAULT_BUCKETS))),
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(100 /* bytes */)
.hasAttributesSatisfying(
equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200),
equalTo(NetAttributes.NET_PROTOCOL_NAME, "http"),
equalTo(NetAttributes.NET_PROTOCOL_VERSION, "2.0"),
equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"),
equalTo(SemanticAttributes.NET_PEER_PORT, 1234),
equalTo(
SemanticAttributes.NET_SOCK_PEER_ADDR, "1.2.3.4"))
.hasExemplarsSatisfying(
exemplar ->
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00")))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(200 /* bytes */)
.hasAttributesSatisfying(
equalTo(SemanticAttributes.HTTP_METHOD, "GET"),
equalTo(SemanticAttributes.HTTP_STATUS_CODE, 200),
equalTo(NetAttributes.NET_PROTOCOL_NAME, "http"),
equalTo(NetAttributes.NET_PROTOCOL_VERSION, "2.0"),
equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"),
equalTo(SemanticAttributes.NET_PEER_PORT, 1234),
equalTo(
SemanticAttributes.NET_SOCK_PEER_ADDR, "1.2.3.4"))
.hasExemplarsSatisfying(
exemplar ->
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00")))));
.hasBucketBoundaries(DEFAULT_BUCKETS))));
listener.onEnd(context2, responseAttributes, nanos(300));
@ -165,19 +117,8 @@ class HttpClientMetricsTest {
.hasName("http.client.duration")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(300 /* millis */))),
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(200 /* bytes */))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(400 /* bytes */))));
histogram.hasPointsSatisfying(
point -> point.hasSum(300 /* millis */))));
}
private static long nanos(int millis) {

View File

@ -0,0 +1,155 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.instrumenter.http;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.OperationListener;
import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes;
import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
class HttpClientExperimentalMetricsStableSemconvTest {
@Test
void collectsMetrics() {
InMemoryMetricReader metricReader = InMemoryMetricReader.create();
SdkMeterProvider meterProvider =
SdkMeterProvider.builder().registerMetricReader(metricReader).build();
OperationListener listener =
HttpClientExperimentalMetrics.get().create(meterProvider.get("test"));
Attributes requestAttributes =
Attributes.builder()
.put(HttpAttributes.HTTP_REQUEST_METHOD, "GET")
.put(UrlAttributes.URL_FULL, "https://localhost:1234/")
.put(UrlAttributes.URL_SCHEME, "https")
.put(UrlAttributes.URL_PATH, "/")
.put(UrlAttributes.URL_QUERY, "q=a")
.put(NetworkAttributes.SERVER_ADDRESS, "localhost")
.put(NetworkAttributes.SERVER_PORT, 1234)
.build();
Attributes responseAttributes =
Attributes.builder()
.put(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 200)
.put(HttpAttributes.HTTP_REQUEST_BODY_SIZE, 100)
.put(HttpAttributes.HTTP_RESPONSE_BODY_SIZE, 200)
.put(NetworkAttributes.NETWORK_PROTOCOL_NAME, "http")
.put(NetworkAttributes.NETWORK_PROTOCOL_VERSION, "2.0")
.put(NetworkAttributes.SERVER_SOCKET_ADDRESS, "1.2.3.4")
.put(NetworkAttributes.SERVER_SOCKET_DOMAIN, "somehost20")
.put(NetworkAttributes.SERVER_SOCKET_PORT, 8080)
.build();
Context parent =
Context.root()
.with(
Span.wrap(
SpanContext.create(
"ff01020304050600ff0a0b0c0d0e0f00",
"090a0b0c0d0e0f00",
TraceFlags.getSampled(),
TraceState.getDefault())));
Context context1 = listener.onStart(parent, requestAttributes, nanos(100));
assertThat(metricReader.collectAllMetrics()).isEmpty();
Context context2 = listener.onStart(Context.root(), requestAttributes, nanos(150));
assertThat(metricReader.collectAllMetrics()).isEmpty();
listener.onEnd(context1, responseAttributes, nanos(250));
assertThat(metricReader.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(100 /* bytes */)
.hasAttributesSatisfying(
equalTo(HttpAttributes.HTTP_REQUEST_METHOD, "GET"),
equalTo(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 200),
equalTo(
NetworkAttributes.NETWORK_PROTOCOL_NAME, "http"),
equalTo(
NetworkAttributes.NETWORK_PROTOCOL_VERSION, "2.0"),
equalTo(NetworkAttributes.SERVER_ADDRESS, "localhost"),
equalTo(NetworkAttributes.SERVER_PORT, 1234),
equalTo(
NetworkAttributes.SERVER_SOCKET_ADDRESS, "1.2.3.4"))
.hasExemplarsSatisfying(
exemplar ->
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00")))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(200 /* bytes */)
.hasAttributesSatisfying(
equalTo(HttpAttributes.HTTP_REQUEST_METHOD, "GET"),
equalTo(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 200),
equalTo(
NetworkAttributes.NETWORK_PROTOCOL_NAME, "http"),
equalTo(
NetworkAttributes.NETWORK_PROTOCOL_VERSION, "2.0"),
equalTo(NetworkAttributes.SERVER_ADDRESS, "localhost"),
equalTo(NetworkAttributes.SERVER_PORT, 1234),
equalTo(
NetworkAttributes.SERVER_SOCKET_ADDRESS, "1.2.3.4"))
.hasExemplarsSatisfying(
exemplar ->
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00")))));
listener.onEnd(context2, responseAttributes, nanos(300));
assertThat(metricReader.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(200 /* bytes */))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(400 /* bytes */))));
}
private static long nanos(int millis) {
return TimeUnit.MILLISECONDS.toNanos(millis);
}
}

View File

@ -106,59 +106,7 @@ class HttpClientMetricsStableSemconvTest {
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00"))
.hasBucketBoundaries(DURATION_BUCKETS))),
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(100 /* bytes */)
.hasAttributesSatisfying(
equalTo(HttpAttributes.HTTP_REQUEST_METHOD, "GET"),
equalTo(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 200),
equalTo(
NetworkAttributes.NETWORK_PROTOCOL_NAME, "http"),
equalTo(
NetworkAttributes.NETWORK_PROTOCOL_VERSION, "2.0"),
equalTo(NetworkAttributes.SERVER_ADDRESS, "localhost"),
equalTo(NetworkAttributes.SERVER_PORT, 1234),
equalTo(
NetworkAttributes.SERVER_SOCKET_ADDRESS, "1.2.3.4"))
.hasExemplarsSatisfying(
exemplar ->
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00")))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasUnit("By")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(200 /* bytes */)
.hasAttributesSatisfying(
equalTo(HttpAttributes.HTTP_REQUEST_METHOD, "GET"),
equalTo(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 200),
equalTo(
NetworkAttributes.NETWORK_PROTOCOL_NAME, "http"),
equalTo(
NetworkAttributes.NETWORK_PROTOCOL_VERSION, "2.0"),
equalTo(NetworkAttributes.SERVER_ADDRESS, "localhost"),
equalTo(NetworkAttributes.SERVER_PORT, 1234),
equalTo(
NetworkAttributes.SERVER_SOCKET_ADDRESS, "1.2.3.4"))
.hasExemplarsSatisfying(
exemplar ->
exemplar
.hasTraceId("ff01020304050600ff0a0b0c0d0e0f00")
.hasSpanId("090a0b0c0d0e0f00")))));
.hasBucketBoundaries(DURATION_BUCKETS))));
listener.onEnd(context2, responseAttributes, nanos(300));
@ -170,19 +118,7 @@ class HttpClientMetricsStableSemconvTest {
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point -> point.hasSum(0.3 /* seconds */))),
metric ->
assertThat(metric)
.hasName("http.client.request.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(200 /* bytes */))),
metric ->
assertThat(metric)
.hasName("http.client.response.size")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(point -> point.hasSum(400 /* bytes */))));
point -> point.hasSum(0.3 /* seconds */))));
}
private static long nanos(int millis) {

View File

@ -9,8 +9,10 @@ import akka.http.scaladsl.model.HttpRequest;
import akka.http.scaladsl.model.HttpResponse;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -27,7 +29,7 @@ public class AkkaHttpClientSingletons {
SETTER = new HttpHeaderSetter(GlobalOpenTelemetry.getPropagators());
AkkaHttpClientAttributesGetter httpAttributesGetter = new AkkaHttpClientAttributesGetter();
AkkaHttpNetAttributesGetter netAttributesGetter = new AkkaHttpNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<HttpRequest, HttpResponse> builder =
Instrumenter.<HttpRequest, HttpResponse>builder(
GlobalOpenTelemetry.get(),
AkkaHttpUtil.instrumentationName(),
@ -42,8 +44,11 @@ public class AkkaHttpClientSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildInstrumenter(SpanKindExtractor.alwaysClient());
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildInstrumenter(SpanKindExtractor.alwaysClient());
}
public static Instrumenter<HttpRequest, HttpResponse> instrumenter() {

View File

@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -26,7 +28,7 @@ public final class ApacheHttpAsyncClientSingletons {
ApacheHttpAsyncClientNetAttributesGetter netAttributesGetter =
new ApacheHttpAsyncClientNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<ApacheHttpClientRequest, HttpResponse> builder =
Instrumenter.<ApacheHttpClientRequest, HttpResponse>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -41,8 +43,11 @@ public final class ApacheHttpAsyncClientSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
public static Instrumenter<ApacheHttpClientRequest, HttpResponse> instrumenter() {

View File

@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v2_0;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -26,7 +28,7 @@ public final class ApacheHttpClientSingletons {
ApacheHttpClientNetAttributesGetter netAttributesGetter =
new ApacheHttpClientNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<HttpMethod, HttpMethod> builder =
Instrumenter.<HttpMethod, HttpMethod>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -41,8 +43,11 @@ public final class ApacheHttpClientSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
public static Instrumenter<HttpMethod, HttpMethod> instrumenter() {

View File

@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -26,7 +28,7 @@ public final class ApacheHttpClientSingletons {
ApacheHttpClientNetAttributesGetter netAttributesGetter =
new ApacheHttpClientNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<ApacheHttpClientRequest, HttpResponse> builder =
Instrumenter.<ApacheHttpClientRequest, HttpResponse>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -41,8 +43,11 @@ public final class ApacheHttpClientSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
public static Instrumenter<ApacheHttpClientRequest, HttpResponse> instrumenter() {

View File

@ -9,9 +9,11 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
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.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractorBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -34,6 +36,7 @@ public final class ApacheHttpClientTelemetryBuilder {
HttpClientAttributesExtractor.builder(
ApacheHttpClientHttpAttributesGetter.INSTANCE,
new ApacheHttpClientNetAttributesGetter());
private boolean emitExperimentalHttpClientMetrics = false;
ApacheHttpClientTelemetryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
@ -92,6 +95,19 @@ public final class ApacheHttpClientTelemetryBuilder {
return this;
}
/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics
* are to be emitted.
*/
@CanIgnoreReturnValue
public ApacheHttpClientTelemetryBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
return this;
}
/**
* Returns a new {@link ApacheHttpClientTelemetry} configured with this {@link
* ApacheHttpClientTelemetryBuilder}.
@ -100,7 +116,7 @@ public final class ApacheHttpClientTelemetryBuilder {
ApacheHttpClientHttpAttributesGetter httpAttributesGetter =
ApacheHttpClientHttpAttributesGetter.INSTANCE;
Instrumenter<ApacheHttpClientRequest, HttpResponse> instrumenter =
InstrumenterBuilder<ApacheHttpClientRequest, HttpResponse> builder =
Instrumenter.<ApacheHttpClientRequest, HttpResponse>builder(
openTelemetry,
INSTRUMENTATION_NAME,
@ -108,7 +124,13 @@ public final class ApacheHttpClientTelemetryBuilder {
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
.addAttributesExtractors(additionalExtractors)
.addOperationMetrics(HttpClientMetrics.get())
.addOperationMetrics(HttpClientMetrics.get());
if (emitExperimentalHttpClientMetrics) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
Instrumenter<ApacheHttpClientRequest, HttpResponse> instrumenter =
builder
// We manually inject because we need to inject internal requests for redirects.
.buildInstrumenter(SpanKindExtractor.alwaysClient());

View File

@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v5_0;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -27,7 +29,7 @@ public final class ApacheHttpClientSingletons {
ApacheHttpClientNetAttributesGetter netAttributesGetter =
new ApacheHttpClientNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<HttpRequest, HttpResponse> builder =
Instrumenter.<HttpRequest, HttpResponse>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -42,8 +44,11 @@ public final class ApacheHttpClientSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
public static Instrumenter<HttpRequest, HttpResponse> instrumenter() {

View File

@ -31,6 +31,8 @@ public final class ArmeriaSingletons {
PeerServiceAttributesExtractor.create(
new ArmeriaNetClientAttributesGetter(),
CommonConfig.get().getPeerServiceMapping()))
.setEmitExperimentalHttpClientMetrics(
CommonConfig.get().shouldEmitExperimentalHttpClientMetrics())
.build();
CLIENT_DECORATOR = telemetry.newClientDecorator();

View File

@ -17,6 +17,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractorBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteHolder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
@ -39,6 +40,7 @@ public final class ArmeriaTelemetryBuilder {
private final OpenTelemetry openTelemetry;
@Nullable private String peerService;
private boolean emitExperimentalHttpClientMetrics = false;
private final List<AttributesExtractor<? super RequestContext, ? super RequestLog>>
additionalExtractors = new ArrayList<>();
@ -168,6 +170,19 @@ public final class ArmeriaTelemetryBuilder {
return this;
}
/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics
* are to be emitted.
*/
@CanIgnoreReturnValue
public ArmeriaTelemetryBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
return this;
}
public ArmeriaTelemetry build() {
ArmeriaHttpClientAttributesGetter clientAttributesGetter =
ArmeriaHttpClientAttributesGetter.INSTANCE;
@ -207,6 +222,9 @@ public final class ArmeriaTelemetryBuilder {
clientInstrumenterBuilder.addAttributesExtractor(
AttributesExtractor.constant(SemanticAttributes.PEER_SERVICE, peerService));
}
if (emitExperimentalHttpClientMetrics) {
clientInstrumenterBuilder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
return new ArmeriaTelemetry(
clientInstrumenterBuilder.buildClientInstrumenter(ClientRequestContextSetter.INSTANCE),

View File

@ -9,7 +9,9 @@ import com.ning.http.client.Request;
import com.ning.http.client.Response;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -27,7 +29,7 @@ public final class AsyncHttpClientSingletons {
AsyncHttpClientNetAttributesGetter netAttributesGetter =
new AsyncHttpClientNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<Request, Response> builder =
Instrumenter.<Request, Response>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -42,8 +44,11 @@ public final class AsyncHttpClientSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
public static Instrumenter<Request, Response> instrumenter() {

View File

@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.asynchttpclient.v2_0;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -26,7 +28,7 @@ public final class AsyncHttpClientSingletons {
AsyncHttpClientNetAttributesGetter netAttributeGetter =
new AsyncHttpClientNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<RequestContext, Response> builder =
Instrumenter.<RequestContext, Response>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -42,8 +44,11 @@ public final class AsyncHttpClientSingletons {
PeerServiceAttributesExtractor.create(
netAttributeGetter, CommonConfig.get().getPeerServiceMapping()))
.addAttributesExtractor(new AsyncHttpClientAdditionalAttributesExtractor())
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
public static Instrumenter<RequestContext, Response> instrumenter() {

View File

@ -9,7 +9,9 @@ import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -27,7 +29,7 @@ public class GoogleHttpClientSingletons {
GoogleHttpClientNetAttributesGetter netAttributesGetter =
new GoogleHttpClientNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<HttpRequest, HttpResponse> builder =
Instrumenter.<HttpRequest, HttpResponse>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -42,8 +44,11 @@ public class GoogleHttpClientSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
public static Instrumenter<HttpRequest, HttpResponse> instrumenter() {

View File

@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.httpurlconnection;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -23,7 +25,7 @@ public final class HttpUrlConnectionSingletons {
HttpUrlHttpAttributesGetter httpAttributesGetter = new HttpUrlHttpAttributesGetter();
HttpUrlNetAttributesGetter netAttributesGetter = new HttpUrlNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<HttpURLConnection, Integer> builder =
Instrumenter.<HttpURLConnection, Integer>builder(
GlobalOpenTelemetry.get(),
"io.opentelemetry.http-url-connection",
@ -42,8 +44,11 @@ public final class HttpUrlConnectionSingletons {
.addContextCustomizer(
(context, httpRequestPacket, startAttributes) ->
GetOutputStreamContext.init(context))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(RequestPropertySetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(RequestPropertySetter.INSTANCE);
}
public static Instrumenter<HttpURLConnection, Integer> instrumenter() {

View File

@ -35,7 +35,8 @@ public class JavaHttpClientSingletons {
CommonConfig.get().getKnownHttpRequestMethods(),
singletonList(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping())));
netAttributesGetter, CommonConfig.get().getPeerServiceMapping())),
CommonConfig.get().shouldEmitExperimentalHttpClientMetrics());
}
public static Instrumenter<HttpRequest, HttpResponse<?>> instrumenter() {

View File

@ -31,6 +31,7 @@ public final class JavaHttpClientTelemetryBuilder {
private List<String> capturedRequestHeaders = emptyList();
private List<String> capturedResponseHeaders = emptyList();
@Nullable private Set<String> knownMethods = null;
private boolean emitExperimentalHttpClientMetrics = false;
JavaHttpClientTelemetryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
@ -88,6 +89,19 @@ public final class JavaHttpClientTelemetryBuilder {
return this;
}
/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics
* are to be emitted.
*/
@CanIgnoreReturnValue
public JavaHttpClientTelemetryBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
return this;
}
public JavaHttpClientTelemetry build() {
Instrumenter<HttpRequest, HttpResponse<?>> instrumenter =
JavaHttpClientInstrumenterFactory.createInstrumenter(
@ -95,7 +109,8 @@ public final class JavaHttpClientTelemetryBuilder {
capturedRequestHeaders,
capturedResponseHeaders,
knownMethods,
additionalExtractors);
additionalExtractors,
emitExperimentalHttpClientMetrics);
return new JavaHttpClientTelemetry(
instrumenter, new HttpHeadersSetter(openTelemetry.getPropagators()));

View File

@ -8,9 +8,11 @@ package io.opentelemetry.instrumentation.httpclient.internal;
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.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractorBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -32,8 +34,9 @@ public final class JavaHttpClientInstrumenterFactory {
List<String> capturedRequestHeaders,
List<String> capturedResponseHeaders,
@Nullable Set<String> knownMethods,
List<AttributesExtractor<? super HttpRequest, ? super HttpResponse<?>>>
additionalExtractors) {
List<AttributesExtractor<? super HttpRequest, ? super HttpResponse<?>>> additionalExtractors,
boolean emitExperimentalHttpClientMetrics) {
JavaHttpClientAttributesGetter httpAttributesGetter = JavaHttpClientAttributesGetter.INSTANCE;
HttpClientAttributesExtractorBuilder<HttpRequest, HttpResponse<?>>
@ -46,13 +49,19 @@ public final class JavaHttpClientInstrumenterFactory {
httpAttributesExtractorBuilder.setKnownMethods(knownMethods);
}
return Instrumenter.<HttpRequest, HttpResponse<?>>builder(
openTelemetry, INSTRUMENTATION_NAME, HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
.addAttributesExtractors(additionalExtractors)
.addOperationMetrics(HttpClientMetrics.get())
.buildInstrumenter(SpanKindExtractor.alwaysClient());
InstrumenterBuilder<HttpRequest, HttpResponse<?>> builder =
Instrumenter.<HttpRequest, HttpResponse<?>>builder(
openTelemetry,
INSTRUMENTATION_NAME,
HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
.addAttributesExtractors(additionalExtractors)
.addOperationMetrics(HttpClientMetrics.get());
if (emitExperimentalHttpClientMetrics) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
return builder.buildInstrumenter(SpanKindExtractor.alwaysClient());
}
private JavaHttpClientInstrumenterFactory() {}

View File

@ -9,7 +9,9 @@ import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientResponse;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -25,7 +27,7 @@ public class JaxRsClientSingletons {
JaxRsClientHttpAttributesGetter httpAttributesGetter = new JaxRsClientHttpAttributesGetter();
JaxRsClientNetAttributesGetter netAttributesGetter = new JaxRsClientNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<ClientRequest, ClientResponse> builder =
Instrumenter.<ClientRequest, ClientResponse>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -40,8 +42,11 @@ public class JaxRsClientSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(ClientRequestHeaderSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(ClientRequestHeaderSetter.INSTANCE);
}
public static Instrumenter<ClientRequest, ClientResponse> instrumenter() {

View File

@ -25,6 +25,8 @@ public class JettyHttpClientSingletons {
.setCapturedRequestHeaders(CommonConfig.get().getClientRequestHeaders())
.setCapturedResponseHeaders(CommonConfig.get().getClientResponseHeaders())
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.setEmitExperimentalHttpClientMetrics(
CommonConfig.get().shouldEmitExperimentalHttpClientMetrics())
.build();
public static Instrumenter<Request, Response> instrumenter() {

View File

@ -93,6 +93,19 @@ public final class JettyClientTelemetryBuilder {
return this;
}
/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics
* are to be emitted.
*/
@CanIgnoreReturnValue
public JettyClientTelemetryBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
instrumenterBuilder.setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientMetrics);
return this;
}
/**
* Returns a new {@link JettyClientTelemetry} with the settings of this {@link
* JettyClientTelemetryBuilder}.

View File

@ -9,8 +9,10 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
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.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractorBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -36,6 +38,7 @@ public final class JettyClientInstrumenterBuilder {
httpAttributesExtractorBuilder =
HttpClientAttributesExtractor.builder(
JettyClientHttpAttributesGetter.INSTANCE, new JettyHttpClientNetAttributesGetter());
private boolean emitExperimentalHttpClientMetrics = false;
public JettyClientInstrumenterBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
@ -66,17 +69,29 @@ public final class JettyClientInstrumenterBuilder {
return this;
}
@CanIgnoreReturnValue
public JettyClientInstrumenterBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
return this;
}
public Instrumenter<Request, Response> build() {
JettyClientHttpAttributesGetter httpAttributesGetter = JettyClientHttpAttributesGetter.INSTANCE;
return Instrumenter.<Request, Response>builder(
this.openTelemetry,
INSTRUMENTATION_NAME,
HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
.addAttributesExtractors(additionalExtractors)
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
InstrumenterBuilder<Request, Response> builder =
Instrumenter.<Request, Response>builder(
this.openTelemetry,
INSTRUMENTATION_NAME,
HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
.addAttributesExtractors(additionalExtractors)
.addOperationMetrics(HttpClientMetrics.get());
if (emitExperimentalHttpClientMetrics) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
return builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
}

View File

@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.joddhttp.v4_2;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -25,7 +27,7 @@ public final class JoddHttpSingletons {
JoddHttpHttpAttributesGetter httpAttributesGetter = new JoddHttpHttpAttributesGetter();
JoddHttpNetAttributesGetter netAttributesGetter = new JoddHttpNetAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<HttpRequest, HttpResponse> builder =
Instrumenter.<HttpRequest, HttpResponse>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -40,8 +42,11 @@ public final class JoddHttpSingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
public static Instrumenter<HttpRequest, HttpResponse> instrumenter() {

View File

@ -6,12 +6,13 @@
package io.opentelemetry.instrumentation.ktor.v2_0.client
import io.ktor.client.request.*
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.*
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.SpanKindExtractor.alwaysClient
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor
@ -25,6 +26,7 @@ class KtorClientTracingBuilder {
KtorHttpClientAttributesGetter,
KtorNetClientAttributesGetter,
)
private var emitExperimentalHttpClientMetrics = false
fun setOpenTelemetry(openTelemetry: OpenTelemetry) {
this.openTelemetry = openTelemetry
@ -55,6 +57,17 @@ class KtorClientTracingBuilder {
additionalExtractors += extractors
}
/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics `true` if the experimental HTTP client metrics are to be emitted.
*/
fun setEmitExperimentalHttpClientMetrics(
emitExperimentalHttpClientMetrics: Boolean
) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics
}
internal fun build(): KtorClientTracing {
val initializedOpenTelemetry = openTelemetry
?: throw IllegalArgumentException("OpenTelemetry must be set")
@ -64,12 +77,16 @@ class KtorClientTracingBuilder {
INSTRUMENTATION_NAME,
HttpSpanNameExtractor.create(KtorHttpClientAttributesGetter),
)
val instrumenter = instrumenterBuilder
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(KtorHttpClientAttributesGetter))
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
.addAttributesExtractors(additionalExtractors)
.addOperationMetrics(HttpClientMetrics.get())
if (emitExperimentalHttpClientMetrics) {
instrumenterBuilder.addOperationMetrics(HttpClientExperimentalMetrics.get())
}
val instrumenter = instrumenterBuilder
.buildInstrumenter(alwaysClient())
return KtorClientTracing(

View File

@ -7,8 +7,10 @@ package io.opentelemetry.javaagent.instrumentation.netty.v3_8.client;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -31,7 +33,7 @@ public final class NettyClientSingletons {
NettyHttpClientAttributesGetter httpAttributesGetter = new NettyHttpClientAttributesGetter();
NettyNetClientAttributesGetter netAttributesGetter = new NettyNetClientAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<HttpRequestAndChannel, HttpResponse> builder =
Instrumenter.<HttpRequestAndChannel, HttpResponse>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -48,8 +50,11 @@ public final class NettyClientSingletons {
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.addContextCustomizer(
(context, requestAndChannel, startAttributes) -> NettyErrorHolder.init(context))
.buildClientInstrumenter(HttpRequestHeadersSetter.INSTANCE);
(context, requestAndChannel, startAttributes) -> NettyErrorHolder.init(context));
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildClientInstrumenter(HttpRequestHeadersSetter.INSTANCE);
NettyConnectNetAttributesGetter nettyConnectAttributesGetter =
new NettyConnectNetAttributesGetter();

View File

@ -14,6 +14,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractorBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -37,18 +38,21 @@ public final class NettyClientInstrumenterFactory {
private final boolean connectionTelemetryEnabled;
private final boolean sslTelemetryEnabled;
private final Map<String, String> peerServiceMapping;
private final boolean emitExperimentalHttpClientMetrics;
public NettyClientInstrumenterFactory(
OpenTelemetry openTelemetry,
String instrumentationName,
boolean connectionTelemetryEnabled,
boolean sslTelemetryEnabled,
Map<String, String> peerServiceMapping) {
Map<String, String> peerServiceMapping,
boolean emitExperimentalHttpClientMetrics) {
this.openTelemetry = openTelemetry;
this.instrumentationName = instrumentationName;
this.connectionTelemetryEnabled = connectionTelemetryEnabled;
this.sslTelemetryEnabled = sslTelemetryEnabled;
this.peerServiceMapping = peerServiceMapping;
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
}
public Instrumenter<HttpRequestAndChannel, HttpResponse> createHttpInstrumenter(
@ -68,15 +72,21 @@ public final class NettyClientInstrumenterFactory {
extractorBuilder.setKnownMethods(knownMethods);
}
return Instrumenter.<HttpRequestAndChannel, HttpResponse>builder(
openTelemetry, instrumentationName, HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(extractorBuilder.build())
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(netAttributesGetter, peerServiceMapping))
.addAttributesExtractors(additionalHttpAttributeExtractors)
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpRequestHeadersSetter.INSTANCE);
InstrumenterBuilder<HttpRequestAndChannel, HttpResponse> builder =
Instrumenter.<HttpRequestAndChannel, HttpResponse>builder(
openTelemetry,
instrumentationName,
HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(extractorBuilder.build())
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(netAttributesGetter, peerServiceMapping))
.addAttributesExtractors(additionalHttpAttributeExtractors)
.addOperationMetrics(HttpClientMetrics.get());
if (emitExperimentalHttpClientMetrics) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
return builder.buildClientInstrumenter(HttpRequestHeadersSetter.INSTANCE);
}
public NettyConnectionInstrumenter createConnectionInstrumenter() {

View File

@ -45,7 +45,8 @@ public final class NettyClientSingletons {
"io.opentelemetry.netty-4.0",
connectionTelemetryEnabled,
sslTelemetryEnabled,
CommonConfig.get().getPeerServiceMapping());
CommonConfig.get().getPeerServiceMapping(),
CommonConfig.get().shouldEmitExperimentalHttpClientMetrics());
INSTRUMENTER =
factory.createHttpInstrumenter(
CommonConfig.get().getClientRequestHeaders(),

View File

@ -45,7 +45,8 @@ public final class NettyClientSingletons {
"io.opentelemetry.netty-4.1",
connectionTelemetryEnabled,
sslTelemetryEnabled,
CommonConfig.get().getPeerServiceMapping());
CommonConfig.get().getPeerServiceMapping(),
CommonConfig.get().shouldEmitExperimentalHttpClientMetrics());
INSTRUMENTER =
factory.createHttpInstrumenter(
CommonConfig.get().getClientRequestHeaders(),

View File

@ -26,6 +26,7 @@ public final class NettyClientTelemetryBuilder {
private Set<String> knownMethods = null;
private final List<AttributesExtractor<HttpRequestAndChannel, HttpResponse>>
additionalAttributesExtractors = new ArrayList<>();
private boolean emitExperimentalHttpClientMetrics = false;
NettyClientTelemetryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
@ -85,11 +86,29 @@ public final class NettyClientTelemetryBuilder {
return this;
}
/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics
* are to be emitted.
*/
@CanIgnoreReturnValue
public NettyClientTelemetryBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
return this;
}
/** Returns a new {@link NettyClientTelemetry} with the given configuration. */
public NettyClientTelemetry build() {
return new NettyClientTelemetry(
new NettyClientInstrumenterFactory(
openTelemetry, "io.opentelemetry.netty-4.1", false, false, Collections.emptyMap())
openTelemetry,
"io.opentelemetry.netty-4.1",
false,
false,
Collections.emptyMap(),
emitExperimentalHttpClientMetrics)
.createHttpInstrumenter(
capturedRequestHeaders,
capturedResponseHeaders,

View File

@ -13,7 +13,9 @@ import com.squareup.okhttp.Response;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -32,7 +34,7 @@ public final class OkHttp2Singletons {
OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
INSTRUMENTER =
InstrumenterBuilder<Request, Response> builder =
Instrumenter.<Request, Response>builder(
openTelemetry,
INSTRUMENTATION_NAME,
@ -47,8 +49,11 @@ public final class OkHttp2Singletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildInstrumenter(alwaysClient());
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER = builder.buildInstrumenter(alwaysClient());
TRACING_INTERCEPTOR = new TracingInterceptor(INSTRUMENTER, openTelemetry.getPropagators());
}

View File

@ -29,7 +29,8 @@ public final class OkHttp3Singletons {
CommonConfig.get().getClientRequestHeaders(),
CommonConfig.get().getClientResponseHeaders(),
CommonConfig.get().getKnownHttpRequestMethods(),
emptyList());
emptyList(),
CommonConfig.get().shouldEmitExperimentalHttpClientMetrics());
public static final Interceptor CONTEXT_INTERCEPTOR =
chain -> {

View File

@ -28,6 +28,7 @@ public final class OkHttpTelemetryBuilder {
private List<String> capturedRequestHeaders = emptyList();
private List<String> capturedResponseHeaders = emptyList();
@Nullable private Set<String> knownMethods = null;
private boolean emitExperimentalHttpClientMetrics = false;
OkHttpTelemetryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
@ -85,6 +86,19 @@ public final class OkHttpTelemetryBuilder {
return this;
}
/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics
* are to be emitted.
*/
@CanIgnoreReturnValue
public OkHttpTelemetryBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
return this;
}
/**
* Returns a new {@link OkHttpTelemetry} with the settings of this {@link OkHttpTelemetryBuilder}.
*/
@ -95,7 +109,8 @@ public final class OkHttpTelemetryBuilder {
capturedRequestHeaders,
capturedResponseHeaders,
knownMethods,
additionalExtractors),
additionalExtractors,
emitExperimentalHttpClientMetrics),
openTelemetry.getPropagators());
}
}

View File

@ -10,8 +10,10 @@ 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.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractorBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -34,7 +36,8 @@ public final class OkHttpInstrumenterFactory {
List<String> capturedRequestHeaders,
List<String> capturedResponseHeaders,
@Nullable Set<String> knownMethods,
List<AttributesExtractor<Request, Response>> additionalAttributesExtractors) {
List<AttributesExtractor<Request, Response>> additionalAttributesExtractors,
boolean emitExperimentalHttpClientMetrics) {
OkHttpAttributesGetter httpAttributesGetter = OkHttpAttributesGetter.INSTANCE;
OkHttpNetAttributesGetter netAttributesGetter = OkHttpNetAttributesGetter.INSTANCE;
@ -47,13 +50,20 @@ public final class OkHttpInstrumenterFactory {
extractorBuilder.setKnownMethods(knownMethods);
}
return Instrumenter.<Request, Response>builder(
openTelemetry, INSTRUMENTATION_NAME, HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(extractorBuilder.build())
.addAttributesExtractors(additionalAttributesExtractors)
.addOperationMetrics(HttpClientMetrics.get())
.buildInstrumenter(alwaysClient());
InstrumenterBuilder<Request, Response> builder =
Instrumenter.<Request, Response>builder(
openTelemetry,
INSTRUMENTATION_NAME,
HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(extractorBuilder.build())
.addAttributesExtractors(additionalAttributesExtractors)
.addOperationMetrics(HttpClientMetrics.get());
if (emitExperimentalHttpClientMetrics) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
return builder.buildInstrumenter(alwaysClient());
}
private OkHttpInstrumenterFactory() {}

View File

@ -7,7 +7,9 @@ package io.opentelemetry.javaagent.instrumentation.playws;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -22,22 +24,26 @@ public final class PlayWsClientInstrumenterFactory {
PlayWsClientHttpAttributesGetter httpAttributesGetter = new PlayWsClientHttpAttributesGetter();
PlayWsClientNetAttributesGetter netAttributesGetter = new PlayWsClientNetAttributesGetter();
return Instrumenter.<Request, Response>builder(
GlobalOpenTelemetry.get(),
instrumentationName,
HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(
HttpClientAttributesExtractor.builder(httpAttributesGetter, netAttributesGetter)
.setCapturedRequestHeaders(CommonConfig.get().getClientRequestHeaders())
.setCapturedResponseHeaders(CommonConfig.get().getClientResponseHeaders())
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.build())
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
InstrumenterBuilder<Request, Response> builder =
Instrumenter.<Request, Response>builder(
GlobalOpenTelemetry.get(),
instrumentationName,
HttpSpanNameExtractor.create(httpAttributesGetter))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
.addAttributesExtractor(
HttpClientAttributesExtractor.builder(httpAttributesGetter, netAttributesGetter)
.setCapturedRequestHeaders(CommonConfig.get().getClientRequestHeaders())
.setCapturedResponseHeaders(CommonConfig.get().getClientResponseHeaders())
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.build())
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
return builder.buildClientInstrumenter(HttpHeaderSetter.INSTANCE);
}
private PlayWsClientInstrumenterFactory() {}

View File

@ -7,8 +7,10 @@ package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -46,7 +48,7 @@ public final class ReactorNettySingletons {
ReactorNettyNetClientAttributesGetter netAttributesGetter =
new ReactorNettyNetClientAttributesGetter();
INSTRUMENTER =
InstrumenterBuilder<HttpClientConfig, HttpClientResponse> builder =
Instrumenter.<HttpClientConfig, HttpClientResponse>builder(
GlobalOpenTelemetry.get(),
INSTRUMENTATION_NAME,
@ -61,7 +63,12 @@ public final class ReactorNettySingletons {
.addAttributesExtractor(
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get())
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
INSTRUMENTER =
builder
// headers are injected in ResponseReceiverInstrumenter
.buildInstrumenter(SpanKindExtractor.alwaysClient());
@ -71,7 +78,8 @@ public final class ReactorNettySingletons {
INSTRUMENTATION_NAME,
connectionTelemetryEnabled,
false,
CommonConfig.get().getPeerServiceMapping());
CommonConfig.get().getPeerServiceMapping(),
CommonConfig.get().shouldEmitExperimentalHttpClientMetrics());
CONNECTION_INSTRUMENTER = instrumenterFactory.createConnectionInstrumenter();
}

View File

@ -9,8 +9,10 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
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.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractorBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -31,6 +33,7 @@ public final class SpringWebTelemetryBuilder {
httpAttributesExtractorBuilder =
HttpClientAttributesExtractor.builder(
SpringWebHttpAttributesGetter.INSTANCE, new SpringWebNetAttributesGetter());
private boolean emitExperimentalHttpClientMetrics = false;
SpringWebTelemetryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
@ -88,6 +91,19 @@ public final class SpringWebTelemetryBuilder {
return this;
}
/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics
* are to be emitted.
*/
@CanIgnoreReturnValue
public SpringWebTelemetryBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
return this;
}
/**
* Returns a new {@link SpringWebTelemetry} with the settings of this {@link
* SpringWebTelemetryBuilder}.
@ -95,7 +111,7 @@ public final class SpringWebTelemetryBuilder {
public SpringWebTelemetry build() {
SpringWebHttpAttributesGetter httpAttributeGetter = SpringWebHttpAttributesGetter.INSTANCE;
Instrumenter<HttpRequest, ClientHttpResponse> instrumenter =
InstrumenterBuilder<HttpRequest, ClientHttpResponse> builder =
Instrumenter.<HttpRequest, ClientHttpResponse>builder(
openTelemetry,
INSTRUMENTATION_NAME,
@ -103,9 +119,13 @@ public final class SpringWebTelemetryBuilder {
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributeGetter))
.addAttributesExtractor(httpAttributesExtractorBuilder.build())
.addAttributesExtractors(additionalExtractors)
.addOperationMetrics(HttpClientMetrics.get())
.buildClientInstrumenter(HttpRequestSetter.INSTANCE);
.addOperationMetrics(HttpClientMetrics.get());
if (emitExperimentalHttpClientMetrics) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
Instrumenter<HttpRequest, ClientHttpResponse> instrumenter =
builder.buildClientInstrumenter(HttpRequestSetter.INSTANCE);
return new SpringWebTelemetry(instrumenter);
}
}

View File

@ -24,6 +24,7 @@ public final class WebClientHelper {
new SpringWebfluxTelemetryClientBuilder(GlobalOpenTelemetry.get())
.setCapturedClientRequestHeaders(CommonConfig.get().getClientRequestHeaders())
.setCapturedClientResponseHeaders(CommonConfig.get().getClientResponseHeaders())
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
.addClientAttributesExtractor(
PeerServiceAttributesExtractor.create(
new WebClientNetAttributesGetter(), CommonConfig.get().getPeerServiceMapping()))
@ -31,6 +32,8 @@ public final class WebClientHelper {
InstrumentationConfig.get()
.getBoolean(
"otel.instrumentation.spring-webflux.experimental-span-attributes", false))
.setEmitExperimentalHttpClientMetrics(
CommonConfig.get().shouldEmitExperimentalHttpClientMetrics())
.build();
public static void addFilter(List<ExchangeFilterFunction> exchangeFilterFunctions) {

View File

@ -150,6 +150,19 @@ public final class SpringWebfluxTelemetryBuilder {
return this;
}
/**
* Configures the instrumentation to emit experimental HTTP client metrics.
*
* @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics
* are to be emitted.
*/
@CanIgnoreReturnValue
public SpringWebfluxTelemetryBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
clientBuilder.setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientMetrics);
return this;
}
/**
* Returns a new {@link SpringWebfluxTelemetry} with the settings of this {@link
* SpringWebfluxTelemetryBuilder}.

View File

@ -14,6 +14,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractorBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -42,6 +43,7 @@ public final class SpringWebfluxTelemetryClientBuilder {
WebClientHttpAttributesGetter.INSTANCE, new WebClientNetAttributesGetter());
private boolean captureExperimentalSpanAttributes = false;
private boolean emitExperimentalHttpClientMetrics = false;
public SpringWebfluxTelemetryClientBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
@ -100,6 +102,13 @@ public final class SpringWebfluxTelemetryClientBuilder {
return this;
}
@CanIgnoreReturnValue
public SpringWebfluxTelemetryClientBuilder setEmitExperimentalHttpClientMetrics(
boolean emitExperimentalHttpClientMetrics) {
this.emitExperimentalHttpClientMetrics = emitExperimentalHttpClientMetrics;
return this;
}
/**
* Returns a new {@link SpringWebfluxTelemetry} with the settings of this {@link
* SpringWebfluxTelemetryClientBuilder}.
@ -121,6 +130,9 @@ public final class SpringWebfluxTelemetryClientBuilder {
if (captureExperimentalSpanAttributes) {
clientBuilder.addAttributesExtractor(new WebClientExperimentalAttributesExtractor());
}
if (emitExperimentalHttpClientMetrics) {
clientBuilder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
// headers are injected elsewhere; ClientRequest is immutable
return clientBuilder.buildInstrumenter(alwaysClient());

View File

@ -9,6 +9,7 @@ import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientExperimentalMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
@ -41,6 +42,9 @@ public final class VertxClientInstrumenterFactory {
PeerServiceAttributesExtractor.create(
netAttributesGetter, CommonConfig.get().getPeerServiceMapping()))
.addOperationMetrics(HttpClientMetrics.get());
if (CommonConfig.get().shouldEmitExperimentalHttpClientMetrics()) {
builder.addOperationMetrics(HttpClientExperimentalMetrics.get());
}
return builder.buildClientInstrumenter(new HttpRequestHeaderSetter());
}

View File

@ -33,6 +33,7 @@ public final class CommonConfig {
private final List<String> serverResponseHeaders;
private final Set<String> knownHttpRequestMethods;
private final boolean statementSanitizationEnabled;
private final boolean emitExperimentalHttpClientMetrics;
CommonConfig(InstrumentationConfig config) {
peerServiceMapping =
@ -66,6 +67,8 @@ public final class CommonConfig {
new ArrayList<>(HttpConstants.KNOWN_METHODS)));
statementSanitizationEnabled =
config.getBoolean("otel.instrumentation.common.db-statement-sanitizer.enabled", true);
emitExperimentalHttpClientMetrics =
config.getBoolean("otel.instrumentation.http.client.emit-experimental-metrics", false);
}
public Map<String, String> getPeerServiceMapping() {
@ -95,4 +98,8 @@ public final class CommonConfig {
public boolean isStatementSanitizationEnabled() {
return statementSanitizationEnabled;
}
public boolean shouldEmitExperimentalHttpClientMetrics() {
return emitExperimentalHttpClientMetrics;
}
}