diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt index c09bab2b8f36..6133992666dd 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt @@ -1,2 +1,23 @@ Comparing source compatibility of opentelemetry-instrumentation-api-2.11.0-SNAPSHOT.jar against opentelemetry-instrumentation-api-2.10.0.jar -No changes. \ No newline at end of file ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + GENERIC TEMPLATES: +++ REQUEST:java.lang.Object, +++ RESPONSE:java.lang.Object + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder addAttributesExtractor(io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.Object build() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder setCapturedRequestHeaders(java.util.List) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder setCapturedResponseHeaders(java.util.List) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder setKnownMethods(java.util.Set) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder setSpanNameExtractor(java.util.function.Function,io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor>) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder setStatusExtractor(java.util.function.Function,io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor>) ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + GENERIC TEMPLATES: +++ REQUEST:java.lang.Object, +++ RESPONSE:java.lang.Object + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder addAttributesExtractor(io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.Object build() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder setCapturedRequestHeaders(java.util.List) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder setCapturedResponseHeaders(java.util.List) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder setKnownMethods(java.util.Set) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder setSpanNameExtractor(java.util.function.Function,io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor>) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder setStatusExtractor(java.util.function.Function,io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor>) diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java index d2ef015383d9..28015cc841a2 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java @@ -50,9 +50,7 @@ public final class DefaultHttpClientInstrumenterBuilder { private final List> additionalExtractors = new ArrayList<>(); - private Function< - SpanStatusExtractor, - ? extends SpanStatusExtractor> + private Function, SpanStatusExtractor> statusExtractorTransformer = Function.identity(); private final HttpClientAttributesExtractorBuilder httpAttributesExtractorBuilder; @@ -60,7 +58,7 @@ public final class DefaultHttpClientInstrumenterBuilder { private final HttpSpanNameExtractorBuilder httpSpanNameExtractorBuilder; @Nullable private final TextMapSetter headerSetter; - private Function, ? extends SpanNameExtractor> + private Function, ? extends SpanNameExtractor> spanNameExtractorTransformer = Function.identity(); private boolean emitExperimentalHttpClientMetrics = false; private Consumer> builderCustomizer = b -> {}; @@ -103,7 +101,7 @@ public static DefaultHttpClientInstrumenterBuilder addAttributeExtractor( + public DefaultHttpClientInstrumenterBuilder addAttributesExtractor( AttributesExtractor attributesExtractor) { additionalExtractors.add(attributesExtractor); return this; @@ -111,9 +109,7 @@ public DefaultHttpClientInstrumenterBuilder addAttributeExtra @CanIgnoreReturnValue public DefaultHttpClientInstrumenterBuilder setStatusExtractor( - Function< - SpanStatusExtractor, - ? extends SpanStatusExtractor> + Function, SpanStatusExtractor> statusExtractor) { this.statusExtractorTransformer = statusExtractor; return this; @@ -180,7 +176,7 @@ public DefaultHttpClientInstrumenterBuilder setKnownMethods( /** Sets custom {@link SpanNameExtractor} via transform function. */ @CanIgnoreReturnValue public DefaultHttpClientInstrumenterBuilder setSpanNameExtractor( - Function, ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { this.spanNameExtractorTransformer = spanNameExtractorTransformer; return this; @@ -190,7 +186,7 @@ public DefaultHttpClientInstrumenterBuilder setSpanNameExtrac @CanIgnoreReturnValue public DefaultHttpClientInstrumenterBuilder setPeerServiceResolver( PeerServiceResolver peerServiceResolver) { - return addAttributeExtractor( + return addAttributesExtractor( HttpClientPeerServiceAttributesExtractor.create(attributesGetter, peerServiceResolver)); } @@ -198,7 +194,7 @@ public DefaultHttpClientInstrumenterBuilder setPeerServiceRes @CanIgnoreReturnValue public DefaultHttpClientInstrumenterBuilder setPeerService( String peerService) { - return addAttributeExtractor(AttributesExtractor.constant(PEER_SERVICE, peerService)); + return addAttributesExtractor(AttributesExtractor.constant(PEER_SERVICE, peerService)); } @CanIgnoreReturnValue diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpServerInstrumenterBuilder.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpServerInstrumenterBuilder.java index caee6c007da7..0353041dac2e 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpServerInstrumenterBuilder.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpServerInstrumenterBuilder.java @@ -46,16 +46,14 @@ public final class DefaultHttpServerInstrumenterBuilder { private final List> additionalExtractors = new ArrayList<>(); - private Function< - SpanStatusExtractor, - ? extends SpanStatusExtractor> + private Function, SpanStatusExtractor> statusExtractorTransformer = Function.identity(); private final HttpServerAttributesExtractorBuilder httpAttributesExtractorBuilder; private final HttpSpanNameExtractorBuilder httpSpanNameExtractorBuilder; @Nullable private final TextMapGetter headerGetter; - private Function, ? extends SpanNameExtractor> + private Function, SpanNameExtractor> spanNameExtractorTransformer = Function.identity(); private final HttpServerRouteBuilder httpServerRouteBuilder; private final HttpServerAttributesGetter attributesGetter; @@ -109,9 +107,7 @@ public DefaultHttpServerInstrumenterBuilder addAttributesExtr @CanIgnoreReturnValue public DefaultHttpServerInstrumenterBuilder setStatusExtractor( - Function< - SpanStatusExtractor, - ? extends SpanStatusExtractor> + Function, SpanStatusExtractor> statusExtractor) { this.statusExtractorTransformer = statusExtractor; return this; @@ -179,7 +175,7 @@ public DefaultHttpServerInstrumenterBuilder setKnownMethods( /** Sets custom {@link SpanNameExtractor} via transform function. */ @CanIgnoreReturnValue public DefaultHttpServerInstrumenterBuilder setSpanNameExtractor( - Function, ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { this.spanNameExtractorTransformer = spanNameExtractorTransformer; return this; diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientTelemetryBuilder.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientTelemetryBuilder.java new file mode 100644 index 000000000000..991e1ebe2656 --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientTelemetryBuilder.java @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.semconv.http; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +public interface HttpClientTelemetryBuilder { + + @CanIgnoreReturnValue + HttpClientTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor); + + @CanIgnoreReturnValue + HttpClientTelemetryBuilder setCapturedRequestHeaders( + List requestHeaders); + + @CanIgnoreReturnValue + HttpClientTelemetryBuilder setCapturedResponseHeaders( + List responseHeaders); + + @CanIgnoreReturnValue + HttpClientTelemetryBuilder setKnownMethods(Set knownMethods); + + @CanIgnoreReturnValue + HttpClientTelemetryBuilder setSpanNameExtractor( + Function, SpanNameExtractor> + spanNameExtractorTransformer); + + @CanIgnoreReturnValue + HttpClientTelemetryBuilder setStatusExtractor( + Function, SpanStatusExtractor> + statusExtractorTransformer); + + Object build(); +} diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpServerTelemetryBuilder.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpServerTelemetryBuilder.java new file mode 100644 index 000000000000..23cc2a8ac9c6 --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpServerTelemetryBuilder.java @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.semconv.http; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +public interface HttpServerTelemetryBuilder { + + @CanIgnoreReturnValue + HttpServerTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor); + + @CanIgnoreReturnValue + HttpServerTelemetryBuilder setCapturedRequestHeaders( + List requestHeaders); + + @CanIgnoreReturnValue + HttpServerTelemetryBuilder setCapturedResponseHeaders( + List responseHeaders); + + @CanIgnoreReturnValue + HttpServerTelemetryBuilder setKnownMethods(Set knownMethods); + + @CanIgnoreReturnValue + HttpServerTelemetryBuilder setSpanNameExtractor( + Function, SpanNameExtractor> + spanNameExtractorTransformer); + + @CanIgnoreReturnValue + HttpServerTelemetryBuilder setStatusExtractor( + Function, SpanStatusExtractor> + statusExtractorTransformer); + + Object build(); +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.3/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v4_3/ApacheHttpClientTelemetryBuilder.java b/instrumentation/apache-httpclient/apache-httpclient-4.3/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v4_3/ApacheHttpClientTelemetryBuilder.java index 1d0d497317b9..0e70d276cab5 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.3/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v4_3/ApacheHttpClientTelemetryBuilder.java +++ b/instrumentation/apache-httpclient/apache-httpclient-4.3/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v4_3/ApacheHttpClientTelemetryBuilder.java @@ -7,17 +7,21 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.apachehttpclient.v4_3.internal.Experimental; import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; import java.util.List; import java.util.Set; import java.util.function.Function; import org.apache.http.HttpResponse; /** A builder for {@link ApacheHttpClientTelemetry}. */ -public final class ApacheHttpClientTelemetryBuilder { +public final class ApacheHttpClientTelemetryBuilder + implements HttpClientTelemetryBuilder { private static final String INSTRUMENTATION_NAME = "io.opentelemetry.apache-httpclient-4.3"; private final DefaultHttpClientInstrumenterBuilder builder; @@ -33,12 +37,27 @@ public final class ApacheHttpClientTelemetryBuilder { /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. The {@link AttributesExtractor} will be executed after all default extractors. + * + * @deprecated Use {@link #addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public ApacheHttpClientTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { - builder.addAttributeExtractor(attributesExtractor); + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. The {@link AttributesExtractor} will be executed after all default extractors. + */ + @Override + @CanIgnoreReturnValue + public ApacheHttpClientTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); return this; } @@ -47,6 +66,7 @@ public ApacheHttpClientTelemetryBuilder addAttributeExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public ApacheHttpClientTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -58,6 +78,7 @@ public ApacheHttpClientTelemetryBuilder setCapturedRequestHeaders(List r * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public ApacheHttpClientTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -77,6 +98,7 @@ public ApacheHttpClientTelemetryBuilder setCapturedResponseHeaders(List * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public ApacheHttpClientTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -88,7 +110,11 @@ public ApacheHttpClientTelemetryBuilder setKnownMethods(Set knownMethods * * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link + * Experimental#setEmitExperimentalTelemetry(ApacheHttpClientTelemetryBuilder, boolean)} + * instead. */ + @Deprecated @CanIgnoreReturnValue public ApacheHttpClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( boolean emitExperimentalHttpClientMetrics) { @@ -97,20 +123,32 @@ public ApacheHttpClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public ApacheHttpClientTelemetryBuilder setSpanNameExtractor( Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + SpanNameExtractor, + SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; } + @Override + public ApacheHttpClientTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Returns a new {@link ApacheHttpClientTelemetry} configured with this {@link * ApacheHttpClientTelemetryBuilder}. */ + @Override public ApacheHttpClientTelemetry build() { return new ApacheHttpClientTelemetry(builder.build(), openTelemetry.getPropagators()); } diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.3/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v4_3/internal/Experimental.java b/instrumentation/apache-httpclient/apache-httpclient-4.3/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v4_3/internal/Experimental.java new file mode 100644 index 000000000000..44fda8c106dc --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-4.3/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v4_3/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachehttpclient.v4_3.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.apachehttpclient.v4_3.ApacheHttpClientTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + ApacheHttpClientTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + ApacheHttpClientTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/README.md b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/README.md index 22694b3076cd..c1053547fc56 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/README.md +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/README.md @@ -29,32 +29,32 @@ implementation("io.opentelemetry.instrumentation:opentelemetry-apache-httpclient ### Usage -The instrumentation library provides the class `ApacheHttpClient5Telemetry` that has a builder +The instrumentation library provides the class `ApacheHttpClientTelemetry` that has a builder method and allows the creation of an instance of the `HttpClientBuilder` to provide OpenTelemetry-based spans and context propagation: ```java import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.instrumentation.apachehttpclient.v5_2.ApacheHttpClient5Telemetry; +import io.opentelemetry.instrumentation.apachehttpclient.v5_2.ApacheHttpClientTelemetry; import org.apache.hc.client5.http.classic.HttpClient; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; -public class ApacheHttpClient5Configuration { +public class ApacheHttpClientConfiguration { private OpenTelemetry openTelemetry; - public ApacheHttpClient5Configuration(OpenTelemetry openTelemetry) { + public ApacheHttpClientConfiguration(OpenTelemetry openTelemetry) { this.openTelemetry = openTelemetry; } // creates a new http client builder for constructing http clients with open telemetry instrumentation public HttpClientBuilder createBuilder() { - return ApacheHttpClient5Telemetry.builder(openTelemetry).build().newHttpClientBuilder(); + return ApacheHttpClientTelemetry.builder(openTelemetry).build().newHttpClientBuilder(); } // creates a new http client with open telemetry instrumentation public HttpClient newHttpClient() { - return ApacheHttpClient5Telemetry.builder(openTelemetry).build().newHttpClient(); + return ApacheHttpClientTelemetry.builder(openTelemetry).build().newHttpClient(); } } ``` diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5HttpAttributesGetter.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5HttpAttributesGetter.java index 36d69791d57c..67c6b78087fe 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5HttpAttributesGetter.java +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5HttpAttributesGetter.java @@ -15,6 +15,7 @@ import org.apache.hc.core5.http.MessageHeaders; import org.apache.hc.core5.http.ProtocolVersion; +@Deprecated enum ApacheHttpClient5HttpAttributesGetter implements HttpClientAttributesGetter { INSTANCE; diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Request.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Request.java index d0c96600ecf5..5adca552c464 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Request.java +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Request.java @@ -14,6 +14,10 @@ import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpRequest; +/** + * @deprecated Use {@link ApacheHttpClientRequest} instead. + */ +@Deprecated public final class ApacheHttpClient5Request { private static final Logger logger = Logger.getLogger(ApacheHttpClient5Request.class.getName()); diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Telemetry.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Telemetry.java index dca1909a1b44..3abcf6fef1c5 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Telemetry.java +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Telemetry.java @@ -13,7 +13,12 @@ import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.core5.http.HttpResponse; -/** Entrypoint for instrumenting Apache HTTP Client. */ +/** + * Entrypoint for instrumenting Apache HTTP Client. + * + * @deprecated Use {@link ApacheHttpClientTelemetry} instead. + */ +@Deprecated public final class ApacheHttpClient5Telemetry { /** @@ -53,6 +58,6 @@ public HttpClientBuilder newHttpClientBuilder() { .addExecInterceptorAfter( ChainElement.PROTOCOL.name(), "OtelExecChainHandler", - new OtelExecChainHandler(instrumenter, propagators)); + new OtelExecChainHandlerOld(instrumenter, propagators)); } } diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5TelemetryBuilder.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5TelemetryBuilder.java index 8d7b323462cf..d340d7a60ae6 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5TelemetryBuilder.java +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5TelemetryBuilder.java @@ -7,6 +7,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.apachehttpclient.v5_2.internal.Experimental; import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; @@ -16,7 +17,12 @@ import java.util.function.Function; import org.apache.hc.core5.http.HttpResponse; -/** A builder for {@link ApacheHttpClient5Telemetry}. */ +/** + * A builder for {@link ApacheHttpClient5Telemetry}. + * + * @deprecated Use {@link ApacheHttpClientTelemetryBuilder} instead. + */ +@Deprecated public final class ApacheHttpClient5TelemetryBuilder { private static final String INSTRUMENTATION_NAME = "io.opentelemetry.apache-httpclient-5.2"; @@ -39,7 +45,7 @@ public final class ApacheHttpClient5TelemetryBuilder { public ApacheHttpClient5TelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { - builder.addAttributeExtractor(attributesExtractor); + builder.addAttributesExtractor(attributesExtractor); return this; } @@ -90,7 +96,11 @@ public ApacheHttpClient5TelemetryBuilder setKnownMethods(Set knownMethod * * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link + * Experimental#setEmitExperimentalTelemetry(ApacheHttpClientTelemetryBuilder, boolean)} + * instead. */ + @Deprecated @CanIgnoreReturnValue public ApacheHttpClient5TelemetryBuilder setEmitExperimentalHttpClientMetrics( boolean emitExperimentalHttpClientMetrics) { @@ -102,8 +112,8 @@ public ApacheHttpClient5TelemetryBuilder setEmitExperimentalHttpClientMetrics( @CanIgnoreReturnValue public ApacheHttpClient5TelemetryBuilder setSpanNameExtractor( Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + SpanNameExtractor, + SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientHttpAttributesGetter.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientHttpAttributesGetter.java new file mode 100644 index 000000000000..813d584ff9e9 --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientHttpAttributesGetter.java @@ -0,0 +1,114 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachehttpclient.v5_2; + +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.MessageHeaders; +import org.apache.hc.core5.http.ProtocolVersion; + +enum ApacheHttpClientHttpAttributesGetter + implements HttpClientAttributesGetter { + INSTANCE; + + @Override + public String getHttpRequestMethod(ApacheHttpClientRequest request) { + return request.getMethod(); + } + + @Override + @Nullable + public String getUrlFull(ApacheHttpClientRequest request) { + return request.getUrl(); + } + + @Override + public List getHttpRequestHeader(ApacheHttpClientRequest request, String name) { + return getHeader(request, name); + } + + @Override + public Integer getHttpResponseStatusCode( + ApacheHttpClientRequest request, HttpResponse response, @Nullable Throwable error) { + return response.getCode(); + } + + @Override + public List getHttpResponseHeader( + ApacheHttpClientRequest request, HttpResponse response, String name) { + return getHeader(response, name); + } + + private static List getHeader(MessageHeaders messageHeaders, String name) { + return headersToList(messageHeaders.getHeaders(name)); + } + + private static List getHeader(ApacheHttpClientRequest messageHeaders, String name) { + return headersToList(messageHeaders.getDelegate().getHeaders(name)); + } + + // minimize memory overhead by not using streams + private static List headersToList(Header[] headers) { + if (headers.length == 0) { + return Collections.emptyList(); + } + List headersList = new ArrayList<>(headers.length); + for (Header header : headers) { + headersList.add(header.getValue()); + } + return headersList; + } + + @Nullable + @Override + public String getNetworkProtocolName( + ApacheHttpClientRequest request, @Nullable HttpResponse response) { + ProtocolVersion protocolVersion = getVersion(request, response); + if (protocolVersion == null) { + return null; + } + return protocolVersion.getProtocol(); + } + + @Nullable + @Override + public String getNetworkProtocolVersion( + ApacheHttpClientRequest request, @Nullable HttpResponse response) { + ProtocolVersion protocolVersion = getVersion(request, response); + if (protocolVersion == null) { + return null; + } + if (protocolVersion.getMinor() == 0) { + return Integer.toString(protocolVersion.getMajor()); + } + return protocolVersion.getMajor() + "." + protocolVersion.getMinor(); + } + + @Override + @Nullable + public String getServerAddress(ApacheHttpClientRequest request) { + return request.getDelegate().getAuthority().getHostName(); + } + + @Override + public Integer getServerPort(ApacheHttpClientRequest request) { + return request.getDelegate().getAuthority().getPort(); + } + + private static ProtocolVersion getVersion( + ApacheHttpClientRequest request, @Nullable HttpResponse response) { + ProtocolVersion protocolVersion = request.getDelegate().getVersion(); + if (protocolVersion == null && response != null) { + protocolVersion = response.getVersion(); + } + return protocolVersion; + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientRequest.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientRequest.java new file mode 100644 index 000000000000..4654b08ac056 --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientRequest.java @@ -0,0 +1,75 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachehttpclient.v5_2; + +import static java.util.logging.Level.FINE; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.logging.Logger; +import javax.annotation.Nullable; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpRequest; + +public final class ApacheHttpClientRequest { + + private static final Logger logger = Logger.getLogger(ApacheHttpClientRequest.class.getName()); + + @Nullable private final URI uri; + private final HttpRequest delegate; + + ApacheHttpClientRequest(@Nullable HttpHost httpHost, HttpRequest httpRequest) { + URI calculatedUri = getUri(httpRequest); + if (calculatedUri != null && httpHost != null) { + uri = getCalculatedUri(httpHost, calculatedUri); + } else { + uri = calculatedUri; + } + delegate = httpRequest; + } + + /** Returns the actual {@link HttpRequest} being executed by the client. */ + public HttpRequest getDelegate() { + return delegate; + } + + String getMethod() { + return delegate.getMethod(); + } + + @Nullable + String getUrl() { + return uri != null ? uri.toString() : null; + } + + @Nullable + private static URI getUri(HttpRequest httpRequest) { + try { + // this can be relative or absolute + return new URI(httpRequest.getUri().toString()); + } catch (URISyntaxException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } + + @Nullable + private static URI getCalculatedUri(HttpHost httpHost, URI uri) { + try { + return new URI( + httpHost.getSchemeName(), + uri.getUserInfo(), + httpHost.getHostName(), + httpHost.getPort(), + uri.getPath(), + uri.getQuery(), + uri.getFragment()); + } catch (URISyntaxException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientTelemetry.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientTelemetry.java new file mode 100644 index 000000000000..0ef5497a3890 --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientTelemetry.java @@ -0,0 +1,58 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachehttpclient.v5_2; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import org.apache.hc.client5.http.impl.ChainElement; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.core5.http.HttpResponse; + +/** Entrypoint for instrumenting Apache HTTP Client. */ +public final class ApacheHttpClientTelemetry { + + /** + * Returns a new {@link ApacheHttpClientTelemetry} configured with the given {@link + * OpenTelemetry}. + */ + public static ApacheHttpClientTelemetry create(OpenTelemetry openTelemetry) { + return builder(openTelemetry).build(); + } + + /** + * Returns a new {@link ApacheHttpClientTelemetryBuilder} configured with the given {@link + * OpenTelemetry}. + */ + public static ApacheHttpClientTelemetryBuilder builder(OpenTelemetry openTelemetry) { + return new ApacheHttpClientTelemetryBuilder(openTelemetry); + } + + private final Instrumenter instrumenter; + private final ContextPropagators propagators; + + ApacheHttpClientTelemetry( + Instrumenter instrumenter, + ContextPropagators propagators) { + this.instrumenter = instrumenter; + this.propagators = propagators; + } + + /** Returns a new {@link CloseableHttpClient} with tracing configured. */ + public CloseableHttpClient newHttpClient() { + return newHttpClientBuilder().build(); + } + + /** Returns a new {@link HttpClientBuilder} to create a client with tracing configured. */ + public HttpClientBuilder newHttpClientBuilder() { + return HttpClientBuilder.create() + .addExecInterceptorAfter( + ChainElement.PROTOCOL.name(), + "OtelExecChainHandler", + new OtelExecChainHandler(instrumenter, propagators)); + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientTelemetryBuilder.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientTelemetryBuilder.java new file mode 100644 index 000000000000..8326ac3bdf4e --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientTelemetryBuilder.java @@ -0,0 +1,131 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachehttpclient.v5_2; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.apachehttpclient.v5_2.internal.Experimental; +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import org.apache.hc.core5.http.HttpResponse; + +/** A builder for {@link ApacheHttpClientTelemetry}. */ +public final class ApacheHttpClientTelemetryBuilder + implements HttpClientTelemetryBuilder { + + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.apache-httpclient-5.2"; + private final DefaultHttpClientInstrumenterBuilder builder; + private final OpenTelemetry openTelemetry; + + ApacheHttpClientTelemetryBuilder(OpenTelemetry openTelemetry) { + builder = + DefaultHttpClientInstrumenterBuilder.create( + INSTRUMENTATION_NAME, openTelemetry, ApacheHttpClientHttpAttributesGetter.INSTANCE); + this.openTelemetry = openTelemetry; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. The {@link AttributesExtractor} will be executed after all default extractors. + */ + @Override + @CanIgnoreReturnValue + public ApacheHttpClientTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Configures the HTTP request headers that will be captured as span attributes. + * + * @param requestHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public ApacheHttpClientTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { + builder.setCapturedRequestHeaders(requestHeaders); + return this; + } + + /** + * Configures the HTTP response headers that will be captured as span attributes. + * + * @param responseHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public ApacheHttpClientTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { + builder.setCapturedResponseHeaders(responseHeaders); + return this; + } + + /** + * Configures the instrumentation to recognize an alternative set of HTTP request methods. + * + *

By default, this instrumentation defines "known" methods as the ones listed in RFC9110 and the PATCH + * method defined in RFC5789. + * + *

Note: calling this method overrides the default known method sets completely; it does + * not supplement it. + * + * @param knownMethods A set of recognized HTTP request methods. + * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) + */ + @Override + @CanIgnoreReturnValue + public ApacheHttpClientTelemetryBuilder setKnownMethods(Set knownMethods) { + builder.setKnownMethods(knownMethods); + return this; + } + + /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override + @CanIgnoreReturnValue + public ApacheHttpClientTelemetryBuilder setSpanNameExtractor( + Function< + SpanNameExtractor, + SpanNameExtractor> + spanNameExtractorTransformer) { + builder.setSpanNameExtractor(spanNameExtractorTransformer); + return this; + } + + @Override + public ApacheHttpClientTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + spanNameExtractorTransformer) { + builder.setStatusExtractor(spanNameExtractorTransformer); + return this; + } + + /** + * Can be used via the unstable method {@link + * Experimental#setEmitExperimentalTelemetry(ApacheHttpClientTelemetryBuilder, boolean)}. + */ + void setEmitExperimentalHttpClientMetrics(boolean emitExperimentalHttpClientMetrics) { + builder.setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientMetrics); + } + + /** + * Returns a new {@link ApacheHttpClientTelemetry} configured with this {@link + * ApacheHttpClientTelemetryBuilder}. + */ + @Override + public ApacheHttpClientTelemetry build() { + return new ApacheHttpClientTelemetry(builder.build(), openTelemetry.getPropagators()); + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/OtelExecChainHandler.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/OtelExecChainHandler.java index bf361ea646d1..94dce0b4d67d 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/OtelExecChainHandler.java +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/OtelExecChainHandler.java @@ -24,11 +24,11 @@ class OtelExecChainHandler implements ExecChainHandler { private static final String REQUEST_PARENT_CONTEXT_ATTRIBUTE_ID = OtelExecChainHandler.class.getName() + ".context"; - private final Instrumenter instrumenter; + private final Instrumenter instrumenter; private final ContextPropagators propagators; public OtelExecChainHandler( - Instrumenter instrumenter, + Instrumenter instrumenter, ContextPropagators propagators) { this.instrumenter = instrumenter; this.propagators = propagators; @@ -45,7 +45,7 @@ public ClassicHttpResponse execute(ClassicHttpRequest request, Scope scope, Exec scope.clientContext.setAttribute(REQUEST_PARENT_CONTEXT_ATTRIBUTE_ID, parentContext); } - ApacheHttpClient5Request instrumenterRequest = getApacheHttpClient5Request(request, scope); + ApacheHttpClientRequest instrumenterRequest = getApacheHttpClientRequest(request, scope); if (!instrumenter.shouldStart(parentContext, instrumenterRequest)) { return chain.proceed(request, scope); @@ -59,7 +59,7 @@ public ClassicHttpResponse execute(ClassicHttpRequest request, Scope scope, Exec private ClassicHttpResponse execute( ClassicHttpRequest request, - ApacheHttpClient5Request instrumenterRequest, + ApacheHttpClientRequest instrumenterRequest, ExecChain chain, Scope scope, Context context) @@ -77,7 +77,7 @@ private ClassicHttpResponse execute( } } - private static ApacheHttpClient5Request getApacheHttpClient5Request( + private static ApacheHttpClientRequest getApacheHttpClientRequest( ClassicHttpRequest request, Scope scope) { HttpHost host = null; if (scope.route.getTargetHost() != null) { @@ -94,6 +94,6 @@ private static ApacheHttpClient5Request getApacheHttpClient5Request( host = new HttpHost(host.getSchemeName(), host.getHostName(), -1); } - return new ApacheHttpClient5Request(host, request); + return new ApacheHttpClientRequest(host, request); } } diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/OtelExecChainHandlerOld.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/OtelExecChainHandlerOld.java new file mode 100644 index 000000000000..a19a8b756773 --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/OtelExecChainHandlerOld.java @@ -0,0 +1,100 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachehttpclient.v5_2; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientRequestResendCount; +import java.io.IOException; +import org.apache.hc.client5.http.classic.ExecChain; +import org.apache.hc.client5.http.classic.ExecChain.Scope; +import org.apache.hc.client5.http.classic.ExecChainHandler; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpResponse; + +@Deprecated +class OtelExecChainHandlerOld implements ExecChainHandler { + + private static final String REQUEST_PARENT_CONTEXT_ATTRIBUTE_ID = + OtelExecChainHandlerOld.class.getName() + ".context"; + + private final Instrumenter instrumenter; + private final ContextPropagators propagators; + + public OtelExecChainHandlerOld( + Instrumenter instrumenter, + ContextPropagators propagators) { + this.instrumenter = instrumenter; + this.propagators = propagators; + } + + @Override + public ClassicHttpResponse execute(ClassicHttpRequest request, Scope scope, ExecChain chain) + throws IOException, HttpException { + Context parentContext = + scope.clientContext.getAttribute(REQUEST_PARENT_CONTEXT_ATTRIBUTE_ID, Context.class); + request.setVersion(scope.clientContext.getProtocolVersion()); + if (parentContext == null) { + parentContext = HttpClientRequestResendCount.initialize(Context.current()); + scope.clientContext.setAttribute(REQUEST_PARENT_CONTEXT_ATTRIBUTE_ID, parentContext); + } + + ApacheHttpClient5Request instrumenterRequest = getApacheHttpClient5Request(request, scope); + + if (!instrumenter.shouldStart(parentContext, instrumenterRequest)) { + return chain.proceed(request, scope); + } + + Context context = instrumenter.start(parentContext, instrumenterRequest); + propagators.getTextMapPropagator().inject(context, request, HttpHeaderSetter.INSTANCE); + + return execute(request, instrumenterRequest, chain, scope, context); + } + + private ClassicHttpResponse execute( + ClassicHttpRequest request, + ApacheHttpClient5Request instrumenterRequest, + ExecChain chain, + Scope scope, + Context context) + throws IOException, HttpException { + ClassicHttpResponse response = null; + Throwable error = null; + try (io.opentelemetry.context.Scope ignored = context.makeCurrent()) { + response = chain.proceed(request, scope); + return response; + } catch (Exception e) { + error = e; + throw e; + } finally { + instrumenter.end(context, instrumenterRequest, response, error); + } + } + + private static ApacheHttpClient5Request getApacheHttpClient5Request( + ClassicHttpRequest request, Scope scope) { + HttpHost host = null; + if (scope.route.getTargetHost() != null) { + host = scope.route.getTargetHost(); + } else if (scope.clientContext.getHttpRoute().getTargetHost() != null) { + host = scope.clientContext.getHttpRoute().getTargetHost(); + } + if (host != null + && ((host.getSchemeName().equals("https") && host.getPort() == 443) + || (host.getSchemeName().equals("http") && host.getPort() == 80))) { + // port seems to be added to the host by route planning for standard ports even if not + // specified in the URL. There doesn't seem to be a way to differentiate between explicit + // and implicit port, but ignore in both cases to match the more common case. + host = new HttpHost(host.getSchemeName(), host.getHostName(), -1); + } + + return new ApacheHttpClient5Request(host, request); + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/internal/Experimental.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/internal/Experimental.java new file mode 100644 index 000000000000..eaadacaf369a --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/main/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/internal/Experimental.java @@ -0,0 +1,52 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.apachehttpclient.v5_2.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.apachehttpclient.v5_2.ApacheHttpClientTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable private static final Method emitExperimentalTelemetry = getEmitExperimentalTelemetry(); + + public void setEmitExperimentalTelemetry( + ApacheHttpClientTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (Experimental.emitExperimentalTelemetry != null) { + try { + Experimental.emitExperimentalTelemetry.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetry() { + try { + Method method = + ApacheHttpClientTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/AbstractApacheHttpClient5Test.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/AbstractApacheHttpClientTest.java similarity index 99% rename from instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/AbstractApacheHttpClient5Test.java rename to instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/AbstractApacheHttpClientTest.java index b23b5f32d247..47684a841037 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/AbstractApacheHttpClient5Test.java +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/AbstractApacheHttpClientTest.java @@ -27,7 +27,7 @@ import org.junit.jupiter.api.TestInstance; @TestInstance(TestInstance.Lifecycle.PER_CLASS) -abstract class AbstractApacheHttpClient5Test { +abstract class AbstractApacheHttpClientTest { protected abstract InstrumentationExtension testing(); diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Test.java b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientTest.java similarity index 94% rename from instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Test.java rename to instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientTest.java index 8d8f5a4c289f..744063576a31 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClient5Test.java +++ b/instrumentation/apache-httpclient/apache-httpclient-5.2/library/src/test/java/io/opentelemetry/instrumentation/apachehttpclient/v5_2/ApacheHttpClientTest.java @@ -18,7 +18,7 @@ import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.extension.RegisterExtension; -class ApacheHttpClient5Test extends AbstractApacheHttpClient5Test { +class ApacheHttpClientTest extends AbstractApacheHttpClientTest { @RegisterExtension static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forLibrary(); @@ -31,7 +31,7 @@ protected InstrumentationExtension testing() { @Override protected CloseableHttpClient createClient(boolean readTimeout) { HttpClientBuilder builder = - ApacheHttpClient5Telemetry.builder(testing.getOpenTelemetry()) + ApacheHttpClientTelemetry.builder(testing.getOpenTelemetry()) .setCapturedRequestHeaders( Collections.singletonList(AbstractHttpClientTest.TEST_REQUEST_HEADER)) .setCapturedResponseHeaders( diff --git a/instrumentation/armeria/armeria-1.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/armeria/v1_3/ArmeriaSingletons.java b/instrumentation/armeria/armeria-1.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/armeria/v1_3/ArmeriaSingletons.java index 4845c528e7e1..8d1fe03762ea 100644 --- a/instrumentation/armeria/armeria-1.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/armeria/v1_3/ArmeriaSingletons.java +++ b/instrumentation/armeria/armeria-1.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/armeria/v1_3/ArmeriaSingletons.java @@ -9,8 +9,10 @@ import com.linecorp.armeria.server.HttpService; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.CommonConfig; -import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaTelemetry; -import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaTelemetryBuilder; +import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaClientTelemetry; +import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaClientTelemetryBuilder; +import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaServerTelemetry; +import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaServerTelemetryBuilder; import io.opentelemetry.instrumentation.armeria.v1_3.internal.ArmeriaInstrumenterBuilderUtil; import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import java.util.function.Function; @@ -23,15 +25,25 @@ public final class ArmeriaSingletons { public static final Function SERVER_DECORATOR; static { - ArmeriaTelemetryBuilder builder = ArmeriaTelemetry.builder(GlobalOpenTelemetry.get()); CommonConfig config = AgentCommonConfig.get(); - ArmeriaInstrumenterBuilderUtil.getClientBuilderExtractor().apply(builder).configure(config); - ArmeriaInstrumenterBuilderUtil.getServerBuilderExtractor().apply(builder).configure(config); - ArmeriaTelemetry telemetry = builder.build(); - CLIENT_DECORATOR = telemetry.newClientDecorator(); + ArmeriaClientTelemetryBuilder clientBuilder = + ArmeriaClientTelemetry.builder(GlobalOpenTelemetry.get()); + ArmeriaInstrumenterBuilderUtil.getClientBuilderExtractor() + .apply(clientBuilder) + .configure(config); + ArmeriaClientTelemetry clientTelemetry = clientBuilder.build(); + + ArmeriaServerTelemetryBuilder serverBuilder = + ArmeriaServerTelemetry.builder(GlobalOpenTelemetry.get()); + ArmeriaInstrumenterBuilderUtil.getServerBuilderExtractor() + .apply(serverBuilder) + .configure(config); + ArmeriaServerTelemetry serverTelemetry = serverBuilder.build(); + + CLIENT_DECORATOR = clientTelemetry.newDecorator(); Function libraryDecorator = - telemetry.newServiceDecorator().compose(ResponseCustomizingDecorator::new); + serverTelemetry.newDecorator().compose(ResponseCustomizingDecorator::new); SERVER_DECORATOR = service -> new ServerDecorator(service, libraryDecorator.apply(service)); } diff --git a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaClientTelemetry.java b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaClientTelemetry.java new file mode 100644 index 000000000000..b6da6cb0a8be --- /dev/null +++ b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaClientTelemetry.java @@ -0,0 +1,42 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.armeria.v1_3; + +import com.linecorp.armeria.client.ClientRequestContext; +import com.linecorp.armeria.client.HttpClient; +import com.linecorp.armeria.common.logging.RequestLog; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import java.util.function.Function; + +/** Entrypoint for instrumenting Armeria clients. */ +public final class ArmeriaClientTelemetry { + + /** + * Returns a new {@link ArmeriaClientTelemetry} configured with the given {@link OpenTelemetry}. + */ + public static ArmeriaClientTelemetry create(OpenTelemetry openTelemetry) { + return builder(openTelemetry).build(); + } + + public static ArmeriaClientTelemetryBuilder builder(OpenTelemetry openTelemetry) { + return new ArmeriaClientTelemetryBuilder(openTelemetry); + } + + private final Instrumenter instrumenter; + + ArmeriaClientTelemetry(Instrumenter instrumenter) { + this.instrumenter = instrumenter; + } + + /** + * Returns a new {@link HttpClient} decorator for use with methods like {@link + * com.linecorp.armeria.client.ClientBuilder#decorator(Function)}. + */ + public Function newDecorator() { + return client -> new OpenTelemetryClient(client, instrumenter); + } +} diff --git a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaClientTelemetryBuilder.java b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaClientTelemetryBuilder.java new file mode 100644 index 000000000000..e8f03cfd9aa8 --- /dev/null +++ b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaClientTelemetryBuilder.java @@ -0,0 +1,136 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.armeria.v1_3; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.linecorp.armeria.client.ClientRequestContext; +import com.linecorp.armeria.common.logging.RequestLog; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; +import io.opentelemetry.instrumentation.armeria.v1_3.internal.ArmeriaInstrumenterBuilderFactory; +import io.opentelemetry.instrumentation.armeria.v1_3.internal.ArmeriaInstrumenterBuilderUtil; +import io.opentelemetry.instrumentation.armeria.v1_3.internal.Experimental; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +public final class ArmeriaClientTelemetryBuilder + implements HttpClientTelemetryBuilder { + + private final DefaultHttpClientInstrumenterBuilder builder; + + static { + ArmeriaInstrumenterBuilderUtil.setClientBuilderExtractor(builder -> builder.builder); + } + + ArmeriaClientTelemetryBuilder(OpenTelemetry openTelemetry) { + builder = ArmeriaInstrumenterBuilderFactory.getClientBuilder(openTelemetry); + } + + /** Sets the status extractor for client spans. */ + @Override + @CanIgnoreReturnValue + public ArmeriaClientTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractor) { + builder.setStatusExtractor(statusExtractor); + return this; + } + + /** + * Adds an extra {@link AttributesExtractor} to invoke to set attributes to instrumented items. + * The {@link AttributesExtractor} will be executed after all default extractors. + */ + @Override + @CanIgnoreReturnValue + public ArmeriaClientTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Configures the HTTP client request headers that will be captured as span attributes. + * + * @param requestHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public ArmeriaClientTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { + builder.setCapturedRequestHeaders(requestHeaders); + return this; + } + + /** + * Configures the HTTP client response headers that will be captured as span attributes. + * + * @param responseHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public ArmeriaClientTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { + builder.setCapturedResponseHeaders(responseHeaders); + return this; + } + + /** + * Configures the instrumentation to recognize an alternative set of HTTP request methods. + * + *

By default, this instrumentation defines "known" methods as the ones listed in RFC9110 and the PATCH + * method defined in RFC5789. + * + *

Note: calling this method overrides the default known method sets completely; it does + * not supplement it. + * + * @param knownMethods A set of recognized HTTP request methods. + * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) + */ + @Override + @CanIgnoreReturnValue + public ArmeriaClientTelemetryBuilder setKnownMethods(Set knownMethods) { + builder.setKnownMethods(knownMethods); + return this; + } + + /** Sets custom client {@link SpanNameExtractor} via transform function. */ + @Override + @CanIgnoreReturnValue + public ArmeriaClientTelemetryBuilder setSpanNameExtractor( + Function, SpanNameExtractor> + clientSpanNameExtractor) { + builder.setSpanNameExtractor(clientSpanNameExtractor); + return this; + } + + /** + * Can be used via the unstable method {@link + * Experimental#setClientPeerService(ArmeriaClientTelemetryBuilder, String)}. + */ + void setPeerService(String peerService) { + builder.setPeerService(peerService); + } + + /** + * Can be used via the unstable method {@link + * Experimental#setEmitExperimentalTelemetry(ArmeriaClientTelemetryBuilder, boolean)}. + */ + void setEmitExperimentalHttpClientMetrics(boolean emitExperimentalHttpClientMetrics) { + builder.setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientMetrics); + } + + @Override + public ArmeriaClientTelemetry build() { + return new ArmeriaClientTelemetry(builder.build()); + } +} diff --git a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaServerTelemetry.java b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaServerTelemetry.java new file mode 100644 index 000000000000..827610367620 --- /dev/null +++ b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaServerTelemetry.java @@ -0,0 +1,42 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.armeria.v1_3; + +import com.linecorp.armeria.common.logging.RequestLog; +import com.linecorp.armeria.server.HttpService; +import com.linecorp.armeria.server.ServiceRequestContext; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import java.util.function.Function; + +/** Entrypoint for instrumenting Armeria services. */ +public final class ArmeriaServerTelemetry { + + /** + * Returns a new {@link ArmeriaServerTelemetry} configured with the given {@link OpenTelemetry}. + */ + public static ArmeriaServerTelemetry create(OpenTelemetry openTelemetry) { + return builder(openTelemetry).build(); + } + + public static ArmeriaServerTelemetryBuilder builder(OpenTelemetry openTelemetry) { + return new ArmeriaServerTelemetryBuilder(openTelemetry); + } + + private final Instrumenter instrumenter; + + ArmeriaServerTelemetry(Instrumenter instrumenter) { + this.instrumenter = instrumenter; + } + + /** + * Returns a new {@link HttpService} decorator for use with methods like {@link + * HttpService#decorate(Function)}. + */ + public Function newDecorator() { + return service -> new OpenTelemetryService(service, instrumenter); + } +} diff --git a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaServerTelemetryBuilder.java b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaServerTelemetryBuilder.java new file mode 100644 index 000000000000..8cdf0c131077 --- /dev/null +++ b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaServerTelemetryBuilder.java @@ -0,0 +1,128 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.armeria.v1_3; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.linecorp.armeria.common.logging.RequestLog; +import com.linecorp.armeria.server.ServiceRequestContext; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder; +import io.opentelemetry.instrumentation.armeria.v1_3.internal.ArmeriaInstrumenterBuilderFactory; +import io.opentelemetry.instrumentation.armeria.v1_3.internal.ArmeriaInstrumenterBuilderUtil; +import io.opentelemetry.instrumentation.armeria.v1_3.internal.Experimental; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +public final class ArmeriaServerTelemetryBuilder + implements HttpServerTelemetryBuilder { + + private final DefaultHttpServerInstrumenterBuilder builder; + + static { + ArmeriaInstrumenterBuilderUtil.setServerBuilderExtractor(builder -> builder.builder); + } + + ArmeriaServerTelemetryBuilder(OpenTelemetry openTelemetry) { + builder = ArmeriaInstrumenterBuilderFactory.getServerBuilder(openTelemetry); + } + + /** Sets the status extractor for server spans. */ + @Override + @CanIgnoreReturnValue + public ArmeriaServerTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractor) { + builder.setStatusExtractor(statusExtractor); + return this; + } + + /** + * Adds an extra {@link AttributesExtractor} to invoke to set attributes to instrumented items. + * The {@link AttributesExtractor} will be executed after all default extractors. + */ + @Override + @CanIgnoreReturnValue + public ArmeriaServerTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Configures the HTTP server request headers that will be captured as span attributes. + * + * @param requestHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public ArmeriaServerTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { + builder.setCapturedRequestHeaders(requestHeaders); + return this; + } + + /** + * Configures the HTTP server response headers that will be captured as span attributes. + * + * @param responseHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public ArmeriaServerTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { + builder.setCapturedResponseHeaders(responseHeaders); + return this; + } + + /** + * Configures the instrumentation to recognize an alternative set of HTTP request methods. + * + *

By default, this instrumentation defines "known" methods as the ones listed in RFC9110 and the PATCH + * method defined in RFC5789. + * + *

Note: calling this method overrides the default known method sets completely; it does + * not supplement it. + * + * @param knownMethods A set of recognized HTTP request methods. + * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) + */ + @Override + @CanIgnoreReturnValue + public ArmeriaServerTelemetryBuilder setKnownMethods(Set knownMethods) { + builder.setKnownMethods(knownMethods); + return this; + } + + /** Sets custom server {@link SpanNameExtractor} via transform function. */ + @Override + @CanIgnoreReturnValue + public ArmeriaServerTelemetryBuilder setSpanNameExtractor( + Function, SpanNameExtractor> + serverSpanNameExtractor) { + builder.setSpanNameExtractor(serverSpanNameExtractor); + return this; + } + + /** + * Can be used via the unstable method {@link + * Experimental#setEmitExperimentalTelemetry(ArmeriaServerTelemetryBuilder, boolean)}. + */ + void setEmitExperimentalHttpServerMetrics(boolean emitExperimentalHttpServerMetrics) { + builder.setEmitExperimentalHttpServerMetrics(emitExperimentalHttpServerMetrics); + } + + @Override + public ArmeriaServerTelemetry build() { + return new ArmeriaServerTelemetry(builder.build()); + } +} diff --git a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTelemetry.java b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTelemetry.java index 94accffa1a73..1d6cd136f859 100644 --- a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTelemetry.java +++ b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTelemetry.java @@ -14,14 +14,30 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import java.util.function.Function; -/** Entrypoint for instrumenting Armeria services or clients. */ +/** + * Entrypoint for instrumenting Armeria services or clients. + * + * @deprecated Use {@link ArmeriaClientTelemetry} and {@link ArmeriaServerTelemetry} instead. + */ +@Deprecated public final class ArmeriaTelemetry { - /** Returns a new {@link ArmeriaTelemetry} configured with the given {@link OpenTelemetry}. */ + /** + * Returns a new {@link ArmeriaTelemetry} configured with the given {@link OpenTelemetry}. + * + * @deprecated Use {@link ArmeriaClientTelemetry#create(OpenTelemetry)} and {@link + * ArmeriaServerTelemetry#create(OpenTelemetry)} instead. + */ + @Deprecated public static ArmeriaTelemetry create(OpenTelemetry openTelemetry) { return builder(openTelemetry).build(); } + /** + * @deprecated Use {@link ArmeriaClientTelemetry#builder(OpenTelemetry)} and {@link + * ArmeriaServerTelemetry#builder(OpenTelemetry)} instead. + */ + @Deprecated public static ArmeriaTelemetryBuilder builder(OpenTelemetry openTelemetry) { return new ArmeriaTelemetryBuilder(openTelemetry); } @@ -39,7 +55,10 @@ public static ArmeriaTelemetryBuilder builder(OpenTelemetry openTelemetry) { /** * Returns a new {@link HttpClient} decorator for use with methods like {@link * com.linecorp.armeria.client.ClientBuilder#decorator(Function)}. + * + * @deprecated Use {@link ArmeriaClientTelemetry#newDecorator()} instead. */ + @Deprecated public Function newClientDecorator() { return client -> new OpenTelemetryClient(client, clientInstrumenter); } @@ -47,7 +66,10 @@ public static ArmeriaTelemetryBuilder builder(OpenTelemetry openTelemetry) { /** * Returns a new {@link HttpService} decorator for use with methods like {@link * HttpService#decorate(Function)}. + * + * @deprecated Use {@link ArmeriaServerTelemetry#newDecorator()} instead. */ + @Deprecated public Function newServiceDecorator() { return service -> new OpenTelemetryService(service, serverInstrumenter); } diff --git a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTelemetryBuilder.java b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTelemetryBuilder.java index 5d6a17eb6586..1f424edbe7cf 100644 --- a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTelemetryBuilder.java +++ b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaTelemetryBuilder.java @@ -19,11 +19,16 @@ import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; import io.opentelemetry.instrumentation.armeria.v1_3.internal.ArmeriaInstrumenterBuilderFactory; -import io.opentelemetry.instrumentation.armeria.v1_3.internal.ArmeriaInstrumenterBuilderUtil; +import io.opentelemetry.instrumentation.armeria.v1_3.internal.Experimental; import java.util.List; import java.util.Set; import java.util.function.Function; +/** + * @deprecated Use {@link ArmeriaClientTelemetryBuilder} and {@link ArmeriaServerTelemetryBuilder} + * instead. + */ +@Deprecated public final class ArmeriaTelemetryBuilder { private final DefaultHttpClientInstrumenterBuilder @@ -31,13 +36,6 @@ public final class ArmeriaTelemetryBuilder { private final DefaultHttpServerInstrumenterBuilder serverBuilder; - static { - ArmeriaInstrumenterBuilderUtil.setClientBuilderExtractor( - ArmeriaTelemetryBuilder::getClientBuilder); - ArmeriaInstrumenterBuilderUtil.setServerBuilderExtractor( - ArmeriaTelemetryBuilder::getServerBuilder); - } - ArmeriaTelemetryBuilder(OpenTelemetry openTelemetry) { clientBuilder = ArmeriaInstrumenterBuilderFactory.getClientBuilder(openTelemetry); serverBuilder = ArmeriaInstrumenterBuilderFactory.getServerBuilder(openTelemetry); @@ -46,8 +44,8 @@ public final class ArmeriaTelemetryBuilder { /** * Sets the status extractor for both client and server spans. * - * @deprecated Use {@link #setClientStatusExtractor(Function)} or {@link - * #setServerStatusExtractor(Function)} instead. + * @deprecated Use {@link ArmeriaClientTelemetryBuilder#setStatusExtractor(Function)} and {@link + * ArmeriaServerTelemetryBuilder#setStatusExtractor(Function)} instead. */ @Deprecated @SuppressWarnings({"unchecked", "rawtypes"}) @@ -62,23 +60,33 @@ public ArmeriaTelemetryBuilder setStatusExtractor( return this; } - /** Sets the status extractor for client spans. */ + /** + * Sets the status extractor for client spans. + * + * @deprecated Use {@link ArmeriaClientTelemetryBuilder#setStatusExtractor(Function)} instead. + */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setClientStatusExtractor( Function< - SpanStatusExtractor, - ? extends SpanStatusExtractor> + SpanStatusExtractor, + SpanStatusExtractor> statusExtractor) { clientBuilder.setStatusExtractor(statusExtractor); return this; } - /** Sets the status extractor for server spans. */ + /** + * Sets the status extractor for server spans. + * + * @deprecated Use {@link ArmeriaServerTelemetryBuilder#setStatusExtractor(Function)} instead. + */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setServerStatusExtractor( Function< - SpanStatusExtractor, - ? extends SpanStatusExtractor> + SpanStatusExtractor, + SpanStatusExtractor> statusExtractor) { serverBuilder.setStatusExtractor(statusExtractor); return this; @@ -88,14 +96,15 @@ public ArmeriaTelemetryBuilder setServerStatusExtractor( * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. The {@link AttributesExtractor} will be executed after all default extractors. * - * @deprecated Use {@link #addClientAttributeExtractor(AttributesExtractor)} or {@link - * #addServerAttributeExtractor(AttributesExtractor)} instead. + * @deprecated Use {@link + * ArmeriaClientTelemetryBuilder#addAttributesExtractor(AttributesExtractor)} and {@link + * ArmeriaServerTelemetryBuilder#addAttributesExtractor(AttributesExtractor)} instead. */ @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { - clientBuilder.addAttributeExtractor(attributesExtractor); + clientBuilder.addAttributesExtractor(attributesExtractor); serverBuilder.addAttributesExtractor(attributesExtractor); return this; } @@ -104,11 +113,15 @@ public ArmeriaTelemetryBuilder addAttributeExtractor( * Adds an extra client-only {@link AttributesExtractor} to invoke to set attributes to * instrumented items. The {@link AttributesExtractor} will be executed after all default * extractors. + * + * @deprecated Use {@link + * ArmeriaClientTelemetryBuilder#addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder addClientAttributeExtractor( AttributesExtractor attributesExtractor) { - clientBuilder.addAttributeExtractor(attributesExtractor); + clientBuilder.addAttributesExtractor(attributesExtractor); return this; } @@ -116,7 +129,11 @@ public ArmeriaTelemetryBuilder addClientAttributeExtractor( * Adds an extra server-only {@link AttributesExtractor} to invoke to set attributes to * instrumented items. The {@link AttributesExtractor} will be executed after all default * extractors. + * + * @deprecated Use {@link + * ArmeriaServerTelemetryBuilder#addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder addServerAttributeExtractor( AttributesExtractor attributesExtractor) { @@ -124,7 +141,13 @@ public ArmeriaTelemetryBuilder addServerAttributeExtractor( return this; } - /** Sets the {@code peer.service} attribute for http client spans. */ + /** + * Sets the {@code peer.service} attribute for http client spans. + * + * @deprecated Use {@link Experimental#setClientPeerService(ArmeriaClientTelemetryBuilder, + * String)} instead. + */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setPeerService(String peerService) { clientBuilder.setPeerService(peerService); @@ -135,7 +158,9 @@ public ArmeriaTelemetryBuilder setPeerService(String peerService) { * Configures the HTTP client request headers that will be captured as span attributes. * * @param requestHeaders A list of HTTP header names. + * @deprecated Use {@link ArmeriaClientTelemetryBuilder#setCapturedRequestHeaders(List)} instead. */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setCapturedClientRequestHeaders(List requestHeaders) { clientBuilder.setCapturedRequestHeaders(requestHeaders); @@ -146,7 +171,9 @@ public ArmeriaTelemetryBuilder setCapturedClientRequestHeaders(List requ * Configures the HTTP client response headers that will be captured as span attributes. * * @param responseHeaders A list of HTTP header names. + * @deprecated Use {@link ArmeriaClientTelemetryBuilder#setCapturedResponseHeaders(List)} instead. */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setCapturedClientResponseHeaders(List responseHeaders) { clientBuilder.setCapturedResponseHeaders(responseHeaders); @@ -157,7 +184,9 @@ public ArmeriaTelemetryBuilder setCapturedClientResponseHeaders(List res * Configures the HTTP server request headers that will be captured as span attributes. * * @param requestHeaders A list of HTTP header names. + * @deprecated Use {@link ArmeriaServerTelemetryBuilder#setCapturedRequestHeaders(List)} instead. */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setCapturedServerRequestHeaders(List requestHeaders) { serverBuilder.setCapturedRequestHeaders(requestHeaders); @@ -168,7 +197,9 @@ public ArmeriaTelemetryBuilder setCapturedServerRequestHeaders(List requ * Configures the HTTP server response headers that will be captured as span attributes. * * @param responseHeaders A list of HTTP header names. + * @deprecated Use {@link ArmeriaServerTelemetryBuilder#setCapturedResponseHeaders(List)} instead. */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setCapturedServerResponseHeaders(List responseHeaders) { serverBuilder.setCapturedResponseHeaders(responseHeaders); @@ -188,7 +219,10 @@ public ArmeriaTelemetryBuilder setCapturedServerResponseHeaders(List res * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) + * @deprecated Use {@link ArmeriaClientTelemetryBuilder#setKnownMethods(Set)} and {@link + * ArmeriaServerTelemetryBuilder#setKnownMethods(Set)} instead. */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setKnownMethods(Set knownMethods) { clientBuilder.setKnownMethods(knownMethods); @@ -201,7 +235,10 @@ public ArmeriaTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(ArmeriaClientTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setEmitExperimentalHttpClientMetrics( boolean emitExperimentalHttpClientMetrics) { @@ -214,7 +251,10 @@ public ArmeriaTelemetryBuilder setEmitExperimentalHttpClientMetrics( * * @param emitExperimentalHttpServerMetrics {@code true} if the experimental HTTP server metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(ArmeriaServerTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setEmitExperimentalHttpServerMetrics( boolean emitExperimentalHttpServerMetrics) { @@ -222,39 +262,40 @@ public ArmeriaTelemetryBuilder setEmitExperimentalHttpServerMetrics( return this; } - /** Sets custom client {@link SpanNameExtractor} via transform function. */ + /** + * Sets custom client {@link SpanNameExtractor} via transform function. + * + * @deprecated Use {@link ArmeriaClientTelemetryBuilder#setSpanNameExtractor(Function)} instead. + */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setClientSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> clientSpanNameExtractor) { clientBuilder.setSpanNameExtractor(clientSpanNameExtractor); return this; } - /** Sets custom server {@link SpanNameExtractor} via transform function. */ + /** + * Sets custom server {@link SpanNameExtractor} via transform function. + * + * @deprecated Use {@link ArmeriaServerTelemetryBuilder#setSpanNameExtractor(Function)} instead. + */ + @Deprecated @CanIgnoreReturnValue public ArmeriaTelemetryBuilder setServerSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> serverSpanNameExtractor) { serverBuilder.setSpanNameExtractor(serverSpanNameExtractor); return this; } + /** + * @deprecated Use {@link ArmeriaClientTelemetryBuilder#build()} and {@link + * ArmeriaServerTelemetryBuilder#build()} instead. + */ + @Deprecated public ArmeriaTelemetry build() { return new ArmeriaTelemetry(clientBuilder.build(), serverBuilder.build()); } - - private DefaultHttpClientInstrumenterBuilder - getClientBuilder() { - return clientBuilder; - } - - private DefaultHttpServerInstrumenterBuilder - getServerBuilder() { - return serverBuilder; - } } diff --git a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/internal/ArmeriaInstrumenterBuilderUtil.java b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/internal/ArmeriaInstrumenterBuilderUtil.java index a9a7d8b43b09..448a244d48e3 100644 --- a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/internal/ArmeriaInstrumenterBuilderUtil.java +++ b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/internal/ArmeriaInstrumenterBuilderUtil.java @@ -10,7 +10,8 @@ import com.linecorp.armeria.server.ServiceRequestContext; import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; -import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaTelemetryBuilder; +import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaClientTelemetryBuilder; +import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaServerTelemetryBuilder; import java.util.function.Function; import javax.annotation.Nullable; @@ -23,19 +24,19 @@ private ArmeriaInstrumenterBuilderUtil() {} @Nullable private static Function< - ArmeriaTelemetryBuilder, + ArmeriaClientTelemetryBuilder, DefaultHttpClientInstrumenterBuilder> clientBuilderExtractor; @Nullable private static Function< - ArmeriaTelemetryBuilder, + ArmeriaServerTelemetryBuilder, DefaultHttpServerInstrumenterBuilder> serverBuilderExtractor; @Nullable public static Function< - ArmeriaTelemetryBuilder, + ArmeriaClientTelemetryBuilder, DefaultHttpClientInstrumenterBuilder> getClientBuilderExtractor() { return clientBuilderExtractor; @@ -43,7 +44,7 @@ private ArmeriaInstrumenterBuilderUtil() {} public static void setClientBuilderExtractor( Function< - ArmeriaTelemetryBuilder, + ArmeriaClientTelemetryBuilder, DefaultHttpClientInstrumenterBuilder> clientBuilderExtractor) { ArmeriaInstrumenterBuilderUtil.clientBuilderExtractor = clientBuilderExtractor; @@ -51,7 +52,7 @@ public static void setClientBuilderExtractor( @Nullable public static Function< - ArmeriaTelemetryBuilder, + ArmeriaServerTelemetryBuilder, DefaultHttpServerInstrumenterBuilder> getServerBuilderExtractor() { return serverBuilderExtractor; @@ -59,7 +60,7 @@ public static void setClientBuilderExtractor( public static void setServerBuilderExtractor( Function< - ArmeriaTelemetryBuilder, + ArmeriaServerTelemetryBuilder, DefaultHttpServerInstrumenterBuilder> serverBuilderExtractor) { ArmeriaInstrumenterBuilderUtil.serverBuilderExtractor = serverBuilderExtractor; diff --git a/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/internal/Experimental.java b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/internal/Experimental.java new file mode 100644 index 000000000000..606065990bd7 --- /dev/null +++ b/instrumentation/armeria/armeria-1.3/library/src/main/java/io/opentelemetry/instrumentation/armeria/v1_3/internal/Experimental.java @@ -0,0 +1,108 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.armeria.v1_3.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaClientTelemetryBuilder; +import io.opentelemetry.instrumentation.armeria.v1_3.ArmeriaServerTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalClientTelemetryMethod = + getEmitExperimentalClientTelemetryMethod(); + + @Nullable private static final Method clientPeerServiceMethod = getClientPeerServiceMethod(); + + @Nullable + private static final Method emitExperimentalHttpServerMetricsMethod = + getEmitExperimentalHttpServerMetricsMethod(); + + public void setEmitExperimentalTelemetry( + ArmeriaClientTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalClientTelemetryMethod != null) { + try { + emitExperimentalClientTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + public void setEmitExperimentalTelemetry( + ArmeriaServerTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalHttpServerMetricsMethod != null) { + try { + emitExperimentalHttpServerMetricsMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + public void setClientPeerService(ArmeriaClientTelemetryBuilder builder, String peerService) { + + if (clientPeerServiceMethod != null) { + try { + clientPeerServiceMethod.invoke(builder, peerService); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalClientTelemetryMethod() { + try { + Method method = + ArmeriaClientTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } + + @Nullable + private static Method getClientPeerServiceMethod() { + try { + Method method = + ArmeriaClientTelemetryBuilder.class.getDeclaredMethod("setPeerService", String.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } + + @Nullable + private static Method getEmitExperimentalHttpServerMetricsMethod() { + try { + return ArmeriaServerTelemetryBuilder.class.getMethod( + "setEmitExperimentalHttpServerMetrics", boolean.class); + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/armeria/armeria-1.3/library/src/test/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpClientTest.java b/instrumentation/armeria/armeria-1.3/library/src/test/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpClientTest.java index eb35610d5023..3cb317cd7f34 100644 --- a/instrumentation/armeria/armeria-1.3/library/src/test/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpClientTest.java +++ b/instrumentation/armeria/armeria-1.3/library/src/test/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpClientTest.java @@ -21,13 +21,13 @@ class ArmeriaHttpClientTest extends AbstractArmeriaHttpClientTest { @Override protected WebClientBuilder configureClient(WebClientBuilder clientBuilder) { return clientBuilder.decorator( - ArmeriaTelemetry.builder(testing.getOpenTelemetry()) - .setCapturedClientRequestHeaders( + ArmeriaClientTelemetry.builder(testing.getOpenTelemetry()) + .setCapturedRequestHeaders( Collections.singletonList(AbstractHttpClientTest.TEST_REQUEST_HEADER)) - .setCapturedClientResponseHeaders( + .setCapturedResponseHeaders( Collections.singletonList(AbstractHttpClientTest.TEST_RESPONSE_HEADER)) .build() - .newClientDecorator()); + .newDecorator()); } @Override diff --git a/instrumentation/armeria/armeria-1.3/library/src/test/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpServerTest.java b/instrumentation/armeria/armeria-1.3/library/src/test/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpServerTest.java index 283261595fa8..399eeee0f897 100644 --- a/instrumentation/armeria/armeria-1.3/library/src/test/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpServerTest.java +++ b/instrumentation/armeria/armeria-1.3/library/src/test/java/io/opentelemetry/instrumentation/armeria/v1_3/ArmeriaHttpServerTest.java @@ -21,13 +21,13 @@ class ArmeriaHttpServerTest extends AbstractArmeriaHttpServerTest { @Override protected ServerBuilder configureServer(ServerBuilder sb) { return sb.decorator( - ArmeriaTelemetry.builder(testing.getOpenTelemetry()) - .setCapturedServerRequestHeaders( + ArmeriaServerTelemetry.builder(testing.getOpenTelemetry()) + .setCapturedRequestHeaders( Collections.singletonList(AbstractHttpServerTest.TEST_REQUEST_HEADER)) - .setCapturedServerResponseHeaders( + .setCapturedResponseHeaders( Collections.singletonList(AbstractHttpServerTest.TEST_RESPONSE_HEADER)) .build() - .newServiceDecorator()); + .newDecorator()); } @Override diff --git a/instrumentation/grpc-1.6/library/src/main/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcTelemetryBuilder.java b/instrumentation/grpc-1.6/library/src/main/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcTelemetryBuilder.java index 98a9ae52ed94..0e1240158d71 100644 --- a/instrumentation/grpc-1.6/library/src/main/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcTelemetryBuilder.java +++ b/instrumentation/grpc-1.6/library/src/main/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcTelemetryBuilder.java @@ -59,7 +59,10 @@ public final class GrpcTelemetryBuilder { /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. The {@link AttributesExtractor} will be executed after all default extractors. + * + * @deprecated Use {@link #addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public GrpcTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { @@ -67,6 +70,17 @@ public GrpcTelemetryBuilder addAttributeExtractor( return this; } + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. The {@link AttributesExtractor} will be executed after all default extractors. + */ + @CanIgnoreReturnValue + public GrpcTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + additionalExtractors.add(attributesExtractor); + return this; + } + /** * Adds an extra client-only {@link AttributesExtractor} to invoke to set attributes to * instrumented items. The {@link AttributesExtractor} will be executed after all default diff --git a/instrumentation/grpc-1.6/library/src/test/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcTest.java b/instrumentation/grpc-1.6/library/src/test/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcTest.java index 5aa6f1aa9a41..36b27c83fbed 100644 --- a/instrumentation/grpc-1.6/library/src/test/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcTest.java +++ b/instrumentation/grpc-1.6/library/src/test/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcTest.java @@ -91,7 +91,7 @@ public void sayHello( .addService(greeter) .intercept( GrpcTelemetry.builder(testing.getOpenTelemetry()) - .addAttributeExtractor(new CustomAttributesExtractor()) + .addAttributesExtractor(new CustomAttributesExtractor()) .addServerAttributeExtractor(new CustomAttributesExtractorV2("serverSideValue")) .build() .newServerInterceptor()) @@ -103,7 +103,7 @@ public void sayHello( ManagedChannelBuilder.forAddress("localhost", server.getPort()) .intercept( GrpcTelemetry.builder(testing.getOpenTelemetry()) - .addAttributeExtractor(new CustomAttributesExtractor()) + .addAttributesExtractor(new CustomAttributesExtractor()) .addClientAttributeExtractor( new CustomAttributesExtractorV2("clientSideValue")) .build() diff --git a/instrumentation/java-http-client/library/src/main/java/io/opentelemetry/instrumentation/httpclient/JavaHttpClientTelemetryBuilder.java b/instrumentation/java-http-client/library/src/main/java/io/opentelemetry/instrumentation/httpclient/JavaHttpClientTelemetryBuilder.java index ae2040ffcc96..8db21eac2380 100644 --- a/instrumentation/java-http-client/library/src/main/java/io/opentelemetry/instrumentation/httpclient/JavaHttpClientTelemetryBuilder.java +++ b/instrumentation/java-http-client/library/src/main/java/io/opentelemetry/instrumentation/httpclient/JavaHttpClientTelemetryBuilder.java @@ -10,7 +10,10 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; +import io.opentelemetry.instrumentation.httpclient.internal.Experimental; import io.opentelemetry.instrumentation.httpclient.internal.HttpHeadersSetter; import io.opentelemetry.instrumentation.httpclient.internal.JavaHttpClientInstrumenterBuilderFactory; import java.net.http.HttpRequest; @@ -19,7 +22,8 @@ import java.util.Set; import java.util.function.Function; -public final class JavaHttpClientTelemetryBuilder { +public final class JavaHttpClientTelemetryBuilder + implements HttpClientTelemetryBuilder> { private final DefaultHttpClientInstrumenterBuilder> builder; private final OpenTelemetry openTelemetry; @@ -32,11 +36,26 @@ public final class JavaHttpClientTelemetryBuilder { /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. The {@link AttributesExtractor} will be executed after all default extractors. + * + * @deprecated Use {@link #addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public JavaHttpClientTelemetryBuilder addAttributeExtractor( AttributesExtractor> attributesExtractor) { - builder.addAttributeExtractor(attributesExtractor); + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. The {@link AttributesExtractor} will be executed after all default extractors. + */ + @Override + @CanIgnoreReturnValue + public JavaHttpClientTelemetryBuilder addAttributesExtractor( + AttributesExtractor> attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); return this; } @@ -45,6 +64,7 @@ public JavaHttpClientTelemetryBuilder addAttributeExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public JavaHttpClientTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -56,6 +76,7 @@ public JavaHttpClientTelemetryBuilder setCapturedRequestHeaders(List req * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public JavaHttpClientTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -75,6 +96,7 @@ public JavaHttpClientTelemetryBuilder setCapturedResponseHeaders(List re * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public JavaHttpClientTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -86,7 +108,11 @@ public JavaHttpClientTelemetryBuilder setKnownMethods(Set knownMethods) * * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link + * Experimental#setEmitExperimentalTelemetry(JavaHttpClientTelemetryBuilder, boolean)} + * instead. */ + @Deprecated @CanIgnoreReturnValue public JavaHttpClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( boolean emitExperimentalHttpClientMetrics) { @@ -95,16 +121,26 @@ public JavaHttpClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public JavaHttpClientTelemetryBuilder setSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; } + @Override + public JavaHttpClientTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor>, + SpanStatusExtractor>> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + + @Override public JavaHttpClientTelemetry build() { return new JavaHttpClientTelemetry( builder.build(), new HttpHeadersSetter(openTelemetry.getPropagators())); diff --git a/instrumentation/java-http-client/library/src/main/java/io/opentelemetry/instrumentation/httpclient/internal/Experimental.java b/instrumentation/java-http-client/library/src/main/java/io/opentelemetry/instrumentation/httpclient/internal/Experimental.java new file mode 100644 index 000000000000..8eb8516d35e9 --- /dev/null +++ b/instrumentation/java-http-client/library/src/main/java/io/opentelemetry/instrumentation/httpclient/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.httpclient.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.httpclient.JavaHttpClientTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + JavaHttpClientTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + JavaHttpClientTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetryBuilder.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetryBuilder.java index ec5c8b379d50..f736417ffc8f 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetryBuilder.java +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetryBuilder.java @@ -10,7 +10,10 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; +import io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal.Experimental; import io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal.JettyHttpClientInstrumenterBuilderFactory; import java.util.List; import java.util.Set; @@ -20,7 +23,8 @@ import org.eclipse.jetty.client.Response; import org.eclipse.jetty.util.ssl.SslContextFactory; -public final class JettyClientTelemetryBuilder { +public final class JettyClientTelemetryBuilder + implements HttpClientTelemetryBuilder { private final DefaultHttpClientInstrumenterBuilder builder; private HttpClientTransport httpClientTransport; @@ -47,11 +51,26 @@ public JettyClientTelemetryBuilder setSslContextFactory( /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. + * + * @deprecated Use {@link #addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public JettyClientTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { - builder.addAttributeExtractor(attributesExtractor); + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. + */ + @Override + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); return this; } @@ -60,6 +79,7 @@ public JettyClientTelemetryBuilder addAttributeExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public JettyClientTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -71,6 +91,7 @@ public JettyClientTelemetryBuilder setCapturedRequestHeaders(List reques * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public JettyClientTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -90,6 +111,7 @@ public JettyClientTelemetryBuilder setCapturedResponseHeaders(List respo * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public JettyClientTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -101,7 +123,10 @@ public JettyClientTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(JettyClientTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public JettyClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( boolean emitExperimentalHttpClientMetrics) { @@ -110,18 +135,28 @@ public JettyClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public JettyClientTelemetryBuilder setSpanNameExtractor( - Function, ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; } + @Override + public JettyClientTelemetryBuilder setStatusExtractor( + Function, SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Returns a new {@link JettyClientTelemetry} with the settings of this {@link * JettyClientTelemetryBuilder}. */ + @Override public JettyClientTelemetry build() { TracingHttpClient tracingHttpClient = TracingHttpClient.buildNew(builder.build(), sslContextFactory, httpClientTransport); diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/Experimental.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/Experimental.java new file mode 100644 index 000000000000..401afc9bfd05 --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.jetty.httpclient.v12_0.JettyClientTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + JettyClientTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + JettyClientTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/JettyClientTelemetryBuilder.java b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/JettyClientTelemetryBuilder.java index a976fe7a2f30..bfb8838cdfd6 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/JettyClientTelemetryBuilder.java +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/JettyClientTelemetryBuilder.java @@ -10,7 +10,10 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; +import io.opentelemetry.instrumentation.jetty.httpclient.v9_2.internal.Experimental; import io.opentelemetry.instrumentation.jetty.httpclient.v9_2.internal.JettyHttpClientInstrumenterBuilderFactory; import java.util.List; import java.util.Set; @@ -21,7 +24,8 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; /** A builder of {@link JettyClientTelemetry}. */ -public final class JettyClientTelemetryBuilder { +public final class JettyClientTelemetryBuilder + implements HttpClientTelemetryBuilder { private final DefaultHttpClientInstrumenterBuilder builder; private HttpClientTransport httpClientTransport; @@ -47,11 +51,26 @@ public JettyClientTelemetryBuilder setSslContextFactory(SslContextFactory sslCon /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. + * + * @deprecated Use {@link #addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public JettyClientTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { - builder.addAttributeExtractor(attributesExtractor); + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. + */ + @Override + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); return this; } @@ -60,6 +79,7 @@ public JettyClientTelemetryBuilder addAttributeExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public JettyClientTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -71,6 +91,7 @@ public JettyClientTelemetryBuilder setCapturedRequestHeaders(List reques * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public JettyClientTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -90,6 +111,7 @@ public JettyClientTelemetryBuilder setCapturedResponseHeaders(List respo * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public JettyClientTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -101,7 +123,10 @@ public JettyClientTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(JettyClientTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public JettyClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( boolean emitExperimentalHttpClientMetrics) { @@ -110,18 +135,28 @@ public JettyClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public JettyClientTelemetryBuilder setSpanNameExtractor( - Function, ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; } + @Override + public JettyClientTelemetryBuilder setStatusExtractor( + Function, SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Returns a new {@link JettyClientTelemetry} with the settings of this {@link * JettyClientTelemetryBuilder}. */ + @Override public JettyClientTelemetry build() { TracingHttpClient tracingHttpClient = TracingHttpClient.buildNew(builder.build(), sslContextFactory, httpClientTransport); diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/Experimental.java b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/Experimental.java new file mode 100644 index 000000000000..0a5e5db3166c --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v9_2.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.jetty.httpclient.v9_2.JettyClientTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + JettyClientTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + JettyClientTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/ktor/ktor-1.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerTelemetry.kt b/instrumentation/ktor/ktor-1.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerTelemetry.kt new file mode 100644 index 000000000000..1ecdf34b18d9 --- /dev/null +++ b/instrumentation/ktor/ktor-1.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerTelemetry.kt @@ -0,0 +1,169 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v1_0 + +import io.ktor.application.* +import io.ktor.request.* +import io.ktor.response.* +import io.ktor.routing.* +import io.ktor.util.* +import io.ktor.util.pipeline.* +import io.opentelemetry.api.OpenTelemetry +import io.opentelemetry.context.Context +import io.opentelemetry.extension.kotlin.asContextElement +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter +import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor +import io.opentelemetry.instrumentation.api.internal.InstrumenterUtil +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource +import kotlinx.coroutines.withContext + +class KtorServerTelemetry private constructor( + private val instrumenter: Instrumenter, +) { + + class Configuration { + internal lateinit var builder: DefaultHttpServerInstrumenterBuilder + + internal var spanKindExtractor: + (SpanKindExtractor) -> SpanKindExtractor = { a -> a } + + fun setOpenTelemetry(openTelemetry: OpenTelemetry) { + this.builder = + DefaultHttpServerInstrumenterBuilder.create( + INSTRUMENTATION_NAME, + openTelemetry, + KtorHttpServerAttributesGetter.INSTANCE + ) + } + + fun setStatusExtractor( + extractor: (SpanStatusExtractor) -> SpanStatusExtractor + ) { + builder.setStatusExtractor { prevExtractor -> + SpanStatusExtractor { spanStatusBuilder: SpanStatusBuilder, + request: ApplicationRequest, + response: ApplicationResponse?, + throwable: Throwable? -> + extractor(prevExtractor).extract(spanStatusBuilder, request, response, throwable) + } + } + } + + fun setSpanKindExtractor(extractor: (SpanKindExtractor) -> SpanKindExtractor) { + this.spanKindExtractor = extractor + } + + fun addAttributeExtractor(extractor: AttributesExtractor) { + builder.addAttributesExtractor(extractor) + } + + fun setCapturedRequestHeaders(requestHeaders: List) { + builder.setCapturedRequestHeaders(requestHeaders) + } + + fun setCapturedResponseHeaders(responseHeaders: List) { + builder.setCapturedResponseHeaders(responseHeaders) + } + + fun setKnownMethods(knownMethods: Set) { + builder.setKnownMethods(knownMethods) + } + + internal fun isOpenTelemetryInitialized(): Boolean = this::builder.isInitialized + } + + private fun start(call: ApplicationCall): Context? { + val parentContext = Context.current() + if (!instrumenter.shouldStart(parentContext, call.request)) { + return null + } + + return instrumenter.start(parentContext, call.request) + } + + private fun end(context: Context, call: ApplicationCall, error: Throwable?) { + instrumenter.end(context, call.request, call.response, error) + } + + companion object Feature : ApplicationFeature { + private const val INSTRUMENTATION_NAME = "io.opentelemetry.ktor-1.0" + + private val contextKey = AttributeKey("OpenTelemetry") + private val errorKey = AttributeKey("OpenTelemetryException") + + override val key: AttributeKey = AttributeKey("OpenTelemetry") + + override fun install(pipeline: Application, configure: Configuration.() -> Unit): KtorServerTelemetry { + val configuration = Configuration().apply(configure) + + if (!configuration.isOpenTelemetryInitialized()) { + throw IllegalArgumentException("OpenTelemetry must be set") + } + + val instrumenter = InstrumenterUtil.buildUpstreamInstrumenter( + configuration.builder.instrumenterBuilder(), + ApplicationRequestGetter, + configuration.spanKindExtractor(SpanKindExtractor.alwaysServer()) + ) + + val feature = KtorServerTelemetry(instrumenter) + + val startPhase = PipelinePhase("OpenTelemetry") + pipeline.insertPhaseBefore(ApplicationCallPipeline.Monitoring, startPhase) + pipeline.intercept(startPhase) { + val context = feature.start(call) + + if (context != null) { + call.attributes.put(contextKey, context) + withContext(context.asContextElement()) { + try { + proceed() + } catch (err: Throwable) { + // Stash error for reporting later since need ktor to finish setting up the response + call.attributes.put(errorKey, err) + throw err + } + } + } else { + proceed() + } + } + + val postSendPhase = PipelinePhase("OpenTelemetryPostSend") + pipeline.sendPipeline.insertPhaseAfter(ApplicationSendPipeline.After, postSendPhase) + pipeline.sendPipeline.intercept(postSendPhase) { + val context = call.attributes.getOrNull(contextKey) + if (context != null) { + var error: Throwable? = call.attributes.getOrNull(errorKey) + try { + proceed() + } catch (t: Throwable) { + error = t + throw t + } finally { + feature.end(context, call, error) + } + } else { + proceed() + } + } + + pipeline.environment.monitor.subscribe(Routing.RoutingCallStarted) { call -> + val context = call.attributes.getOrNull(contextKey) + if (context != null) { + HttpServerRoute.update(context, HttpServerRouteSource.SERVER, { _, arg -> arg.route.parent.toString() }, call) + } + } + + return feature + } + } +} diff --git a/instrumentation/ktor/ktor-1.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerTracing.kt b/instrumentation/ktor/ktor-1.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerTracing.kt index 844cbe2895fd..1073053d0639 100644 --- a/instrumentation/ktor/ktor-1.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerTracing.kt +++ b/instrumentation/ktor/ktor-1.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerTracing.kt @@ -25,6 +25,7 @@ import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource import kotlinx.coroutines.withContext +@Deprecated("Use KtorServerTelemetry instead", ReplaceWith("KtorServerTelemetry")) class KtorServerTracing private constructor( private val instrumenter: Instrumenter, ) { diff --git a/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerSpanKindExtractorTest.kt b/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerSpanKindExtractorTest.kt index 364c67a9e1a5..a494ed33aced 100644 --- a/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerSpanKindExtractorTest.kt +++ b/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorServerSpanKindExtractorTest.kt @@ -58,7 +58,7 @@ class KtorServerSpanKindExtractorTest : AbstractHttpServerUsingTest diff --git a/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorTestUtil.kt b/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorTestUtil.kt index 6daf7382ec40..85fd9d6b78fa 100644 --- a/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorTestUtil.kt +++ b/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorTestUtil.kt @@ -12,7 +12,7 @@ import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTes class KtorTestUtil { companion object { fun installOpenTelemetry(application: Application, openTelemetry: OpenTelemetry) { - application.install(KtorServerTracing) { + application.install(KtorServerTelemetry) { setOpenTelemetry(openTelemetry) setCapturedRequestHeaders(listOf(AbstractHttpServerTest.TEST_REQUEST_HEADER)) setCapturedResponseHeaders(listOf(AbstractHttpServerTest.TEST_RESPONSE_HEADER)) diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTelemetry.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTelemetry.kt new file mode 100644 index 000000000000..fe7dffce7c1e --- /dev/null +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTelemetry.kt @@ -0,0 +1,42 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.common.client + +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.opentelemetry.context.Context +import io.opentelemetry.context.propagation.ContextPropagators +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter + +abstract class AbstractKtorClientTelemetry( + private val instrumenter: Instrumenter, + private val propagators: ContextPropagators, +) { + + internal fun createSpan(requestBuilder: HttpRequestBuilder): Context? { + val parentContext = Context.current() + val requestData = requestBuilder.build() + + return if (instrumenter.shouldStart(parentContext, requestData)) { + instrumenter.start(parentContext, requestData) + } else { + null + } + } + + internal fun populateRequestHeaders(requestBuilder: HttpRequestBuilder, context: Context) { + propagators.textMapPropagator.inject(context, requestBuilder, KtorHttpHeadersSetter) + } + + internal fun endSpan(context: Context, call: HttpClientCall, error: Throwable?) { + endSpan(context, HttpRequestBuilder().takeFrom(call.request), call.response, error) + } + + internal fun endSpan(context: Context, requestBuilder: HttpRequestBuilder, response: HttpResponse?, error: Throwable?) { + instrumenter.end(context, requestBuilder.build(), response, error) + } +} diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTelemetryBuilder.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTelemetryBuilder.kt new file mode 100644 index 000000000000..4b2bc13104cf --- /dev/null +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTelemetryBuilder.kt @@ -0,0 +1,121 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.common.client + +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.opentelemetry.api.OpenTelemetry +import io.opentelemetry.api.common.AttributesBuilder +import io.opentelemetry.context.Context +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil + +abstract class AbstractKtorClientTelemetryBuilder( + private val instrumentationName: String +) { + companion object { + init { + KtorBuilderUtil.clientBuilderExtractor = { it.builder } + } + } + + internal lateinit var openTelemetry: OpenTelemetry + protected lateinit var builder: DefaultHttpClientInstrumenterBuilder + + fun setOpenTelemetry(openTelemetry: OpenTelemetry) { + this.openTelemetry = openTelemetry + this.builder = DefaultHttpClientInstrumenterBuilder.create( + instrumentationName, + openTelemetry, + KtorHttpClientAttributesGetter + ) + } + + protected fun getOpenTelemetry(): OpenTelemetry { + return openTelemetry + } + + fun capturedRequestHeaders(vararg headers: String) = capturedRequestHeaders(headers.asIterable()) + + fun capturedRequestHeaders(headers: Iterable) { + builder.setCapturedRequestHeaders(headers.toList()) + } + + fun capturedResponseHeaders(vararg headers: String) = capturedResponseHeaders(headers.asIterable()) + + fun capturedResponseHeaders(headers: Iterable) { + builder.setCapturedResponseHeaders(headers.toList()) + } + + fun knownMethods(vararg methods: String) = knownMethods(methods.asIterable()) + + fun knownMethods(vararg methods: HttpMethod) = knownMethods(methods.asIterable()) + + @JvmName("knownMethodsJvm") + fun knownMethods(methods: Iterable) = knownMethods(methods.map { it.value }) + + fun knownMethods(methods: Iterable) { + builder.setKnownMethods(methods.toSet()) + } + + fun attributesExtractor(extractorBuilder: ExtractorBuilder.() -> Unit = {}) { + val builder = ExtractorBuilder().apply(extractorBuilder).build() + this.builder.addAttributesExtractor( + object : AttributesExtractor { + override fun onStart(attributes: AttributesBuilder, parentContext: Context, request: HttpRequestData) { + builder.onStart(OnStartData(attributes, parentContext, request)) + } + + override fun onEnd(attributes: AttributesBuilder, context: Context, request: HttpRequestData, response: HttpResponse?, error: Throwable?) { + builder.onEnd(OnEndData(attributes, context, request, response, error)) + } + } + ) + } + + class ExtractorBuilder { + private var onStart: OnStartData.() -> Unit = {} + private var onEnd: OnEndData.() -> Unit = {} + + fun onStart(block: OnStartData.() -> Unit) { + onStart = block + } + + fun onEnd(block: OnEndData.() -> Unit) { + onEnd = block + } + + internal fun build(): Extractor { + return Extractor(onStart, onEnd) + } + } + + internal class Extractor(val onStart: OnStartData.() -> Unit, val onEnd: OnEndData.() -> Unit) + + data class OnStartData( + val attributes: AttributesBuilder, + val parentContext: Context, + val request: HttpRequestData + ) + + data class OnEndData( + val attributes: AttributesBuilder, + val parentContext: Context, + val request: HttpRequestData, + val response: HttpResponse?, + val error: Throwable? + ) + + /** + * Can be used via the unstable method {@link + * Experimental#setEmitExperimentalHttpClientMetrics(AbstractKtorClientTelemetryBuilder, boolean)}. + */ + internal fun emitExperimentalHttpClientMetrics() { + builder.setEmitExperimentalHttpClientMetrics(true) + } +} diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/AbstractKtorClientTracing.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTracing.kt similarity index 89% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/AbstractKtorClientTracing.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTracing.kt index 925cb6cf3156..99d4f861622d 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/AbstractKtorClientTracing.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTracing.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.client +package io.opentelemetry.instrumentation.ktor.v2_0.common.client import io.ktor.client.call.* import io.ktor.client.request.* @@ -12,6 +12,7 @@ import io.opentelemetry.context.Context import io.opentelemetry.context.propagation.ContextPropagators import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter +@Deprecated("Use AbstractKtorClientTelemetry instead", ReplaceWith("AbstractKtorClientTelemetry")) abstract class AbstractKtorClientTracing( private val instrumenter: Instrumenter, private val propagators: ContextPropagators, diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/AbstractKtorClientTracingBuilder.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTracingBuilder.kt similarity index 91% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/AbstractKtorClientTracingBuilder.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTracingBuilder.kt index 3b99bba1f6af..405877f5ded5 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/AbstractKtorClientTracingBuilder.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/AbstractKtorClientTracingBuilder.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.client +package io.opentelemetry.instrumentation.ktor.v2_0.common.client import io.ktor.client.request.* import io.ktor.client.statement.* @@ -13,14 +13,15 @@ import io.opentelemetry.api.common.AttributesBuilder import io.opentelemetry.context.Context import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor -import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtilOld +@Deprecated("Use AbstractKtorClientTelemetryBuilder instead", ReplaceWith("AbstractKtorClientTelemetryBuilder")) abstract class AbstractKtorClientTracingBuilder( private val instrumentationName: String ) { companion object { init { - KtorBuilderUtil.clientBuilderExtractor = { it.clientBuilder } + KtorBuilderUtilOld.clientBuilderExtractor = { it.clientBuilder } } } @@ -108,7 +109,7 @@ abstract class AbstractKtorClientTracingBuilder( fun attributeExtractor(extractorBuilder: ExtractorBuilder.() -> Unit = {}) { val builder = ExtractorBuilder().apply(extractorBuilder).build() - this.clientBuilder.addAttributeExtractor( + this.clientBuilder.addAttributesExtractor( object : AttributesExtractor { override fun onStart(attributes: AttributesBuilder, parentContext: Context, request: HttpRequestData) { builder.onStart(OnStartData(attributes, parentContext, request)) @@ -159,13 +160,14 @@ abstract class AbstractKtorClientTracingBuilder( * * @param emitExperimentalHttpClientMetrics `true` if the experimental HTTP client metrics are to be emitted. */ - @Deprecated("Please use method `emitExperimentalHttpClientMetrics`") + @Deprecated("Please use method `Experimental.emitExperimentalHttpClientMetrics`") fun setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientMetrics: Boolean) { if (emitExperimentalHttpClientMetrics) { emitExperimentalHttpClientMetrics() } } + @Deprecated("Please use method `Experimental.emitExperimentalHttpClientMetrics`") fun emitExperimentalHttpClientMetrics() { clientBuilder.setEmitExperimentalHttpClientMetrics(true) } diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/KtorHttpClientAttributesGetter.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/KtorHttpClientAttributesGetter.kt similarity index 95% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/KtorHttpClientAttributesGetter.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/KtorHttpClientAttributesGetter.kt index db1a9d1a0f0b..9d4a739dbae4 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/KtorHttpClientAttributesGetter.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/KtorHttpClientAttributesGetter.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.client +package io.opentelemetry.instrumentation.ktor.v2_0.common.client import io.ktor.client.request.* import io.ktor.client.statement.* diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/KtorHttpHeadersSetter.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/KtorHttpHeadersSetter.kt similarity index 85% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/KtorHttpHeadersSetter.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/KtorHttpHeadersSetter.kt index d6be22087a26..c04de9e9352e 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/client/KtorHttpHeadersSetter.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/KtorHttpHeadersSetter.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.client +package io.opentelemetry.instrumentation.ktor.v2_0.common.client import io.ktor.client.request.HttpRequestBuilder import io.opentelemetry.context.propagation.TextMapSetter diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/internal/Experimental.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/internal/Experimental.kt new file mode 100644 index 000000000000..c1e6c8da7de2 --- /dev/null +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/client/internal/Experimental.kt @@ -0,0 +1,52 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.common.client.internal + +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTelemetryBuilder +import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Method +import java.util.logging.Level +import java.util.logging.Logger + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +class Experimental { + + companion object { + private val logger: Logger = Logger.getLogger(Experimental::class.java.name) + + private val emitExperimentalTelemetryMethod = getEmitExperimentalTelemetry() + + fun setEmitExperimentalTelemetry(builder: AbstractKtorClientTelemetryBuilder?, emitExperimentalTelemetry: Boolean) { + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry) + } catch (e: IllegalAccessException) { + logger.log(Level.FINE, e.message, e) + } catch (e: InvocationTargetException) { + logger.log(Level.FINE, e.message, e) + } + } + } + + private fun getEmitExperimentalTelemetry(): Method? { + try { + val method = AbstractKtorClientTelemetryBuilder::class.java.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", + Boolean::class.javaPrimitiveType + ) + method.setAccessible(true) + return method + } catch (e: NoSuchMethodException) { + logger.log(Level.FINE, e.message, e) + return null + } + } + } +} diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorBuilderUtil.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorBuilderUtil.kt new file mode 100644 index 000000000000..d916a48c4487 --- /dev/null +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorBuilderUtil.kt @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.common.internal + +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTelemetryBuilder +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTelemetryBuilder + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +object KtorBuilderUtil { + lateinit var clientBuilderExtractor: (AbstractKtorClientTelemetryBuilder) -> DefaultHttpClientInstrumenterBuilder + lateinit var serverBuilderExtractor: ( + AbstractKtorServerTelemetryBuilder + ) -> DefaultHttpServerInstrumenterBuilder +} diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorBuilderUtil.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorBuilderUtilOld.kt similarity index 70% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorBuilderUtil.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorBuilderUtilOld.kt index ec074cca66bd..9154c7f7cd60 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorBuilderUtil.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorBuilderUtilOld.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.internal +package io.opentelemetry.instrumentation.ktor.v2_0.common.internal import io.ktor.client.request.* import io.ktor.client.statement.* @@ -11,14 +11,15 @@ import io.ktor.server.request.* import io.ktor.server.response.* import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder -import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracingBuilder -import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracingBuilder +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTracingBuilder /** * This class is internal and is hence not for public use. Its APIs are unstable and can change at * any time. */ -object KtorBuilderUtil { +@Deprecated("Use KtorBuilderUtil instead", ReplaceWith("KtorBuilderUtil")) +object KtorBuilderUtilOld { lateinit var clientBuilderExtractor: (AbstractKtorClientTracingBuilder) -> DefaultHttpClientInstrumenterBuilder lateinit var serverBuilderExtractor: ( AbstractKtorServerTracingBuilder diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorClientTelemetryUtil.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorClientTelemetryUtil.kt new file mode 100644 index 000000000000..52408fa0f9a6 --- /dev/null +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorClientTelemetryUtil.kt @@ -0,0 +1,88 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.common.internal + +import io.ktor.client.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.util.* +import io.ktor.util.pipeline.* +import io.opentelemetry.context.Context +import io.opentelemetry.extension.kotlin.asContextElement +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientRequestResendCount +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTelemetry +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +object KtorClientTelemetryUtil { + private val openTelemetryContextKey = AttributeKey("OpenTelemetry") + + fun install(plugin: AbstractKtorClientTelemetry, scope: HttpClient) { + installSpanCreation(plugin, scope) + installSpanEnd(plugin, scope) + } + + private fun installSpanCreation(plugin: AbstractKtorClientTelemetry, scope: HttpClient) { + val initializeRequestPhase = PipelinePhase("OpenTelemetryInitializeRequest") + scope.requestPipeline.insertPhaseAfter(HttpRequestPipeline.State, initializeRequestPhase) + + scope.requestPipeline.intercept(initializeRequestPhase) { + val openTelemetryContext = HttpClientRequestResendCount.initialize(Context.current()) + withContext(openTelemetryContext.asContextElement()) { proceed() } + } + + val createSpanPhase = PipelinePhase("OpenTelemetryCreateSpan") + scope.sendPipeline.insertPhaseAfter(HttpSendPipeline.State, createSpanPhase) + + scope.sendPipeline.intercept(createSpanPhase) { + val requestBuilder = context + val openTelemetryContext = plugin.createSpan(requestBuilder) + + if (openTelemetryContext != null) { + try { + requestBuilder.attributes.put(openTelemetryContextKey, openTelemetryContext) + plugin.populateRequestHeaders(requestBuilder, openTelemetryContext) + + withContext(openTelemetryContext.asContextElement()) { proceed() } + } catch (e: Throwable) { + plugin.endSpan(openTelemetryContext, requestBuilder, null, e) + throw e + } + } else { + proceed() + } + } + } + + @OptIn(InternalCoroutinesApi::class) + private fun installSpanEnd(plugin: AbstractKtorClientTelemetry, scope: HttpClient) { + val endSpanPhase = PipelinePhase("OpenTelemetryEndSpan") + scope.receivePipeline.insertPhaseBefore(HttpReceivePipeline.State, endSpanPhase) + + scope.receivePipeline.intercept(endSpanPhase) { + val openTelemetryContext = it.call.attributes.getOrNull(openTelemetryContextKey) + openTelemetryContext ?: return@intercept + + scope.launch { + val job = it.call.coroutineContext.job + job.join() + val cause = if (!job.isCancelled) { + null + } else { + kotlin.runCatching { job.getCancellationException() }.getOrNull() + } + + plugin.endSpan(openTelemetryContext, it.call, cause) + } + } + } +} diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorClientTracingUtil.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorClientTracingUtil.kt similarity index 92% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorClientTracingUtil.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorClientTracingUtil.kt index b1735217a99a..45e0f1d22559 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorClientTracingUtil.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorClientTracingUtil.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.internal +package io.opentelemetry.instrumentation.ktor.v2_0.common.internal import io.ktor.client.* import io.ktor.client.request.* @@ -13,7 +13,7 @@ import io.ktor.util.pipeline.* import io.opentelemetry.context.Context import io.opentelemetry.extension.kotlin.asContextElement import io.opentelemetry.instrumentation.api.semconv.http.HttpClientRequestResendCount -import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracing +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracing import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.job import kotlinx.coroutines.launch @@ -23,6 +23,7 @@ import kotlinx.coroutines.withContext * This class is internal and is hence not for public use. Its APIs are unstable and can change at * any time. */ +@Deprecated("Use KtorClientTelemetryUtil instead", ReplaceWith("KtorClientTelemetryUtil")) object KtorClientTracingUtil { private val openTelemetryContextKey = AttributeKey("OpenTelemetry") diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorServerTelemetryUtil.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorServerTelemetryUtil.kt new file mode 100644 index 000000000000..02900444202d --- /dev/null +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorServerTelemetryUtil.kt @@ -0,0 +1,83 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.common.internal + +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.util.* +import io.ktor.util.pipeline.* +import io.opentelemetry.context.Context +import io.opentelemetry.extension.kotlin.asContextElement +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter +import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor +import io.opentelemetry.instrumentation.api.internal.InstrumenterUtil +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTelemetryBuilder +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.ApplicationRequestGetter +import kotlinx.coroutines.withContext + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +object KtorServerTelemetryUtil { + + fun configureTelemetry(builder: AbstractKtorServerTelemetryBuilder, application: Application) { + val contextKey = AttributeKey("OpenTelemetry") + val errorKey = AttributeKey("OpenTelemetryException") + + val instrumenter = instrumenter(builder) + val tracer = KtorServerTracer(instrumenter) + val startPhase = PipelinePhase("OpenTelemetry") + + application.insertPhaseBefore(ApplicationCallPipeline.Monitoring, startPhase) + application.intercept(startPhase) { + val context = tracer.start(call) + + if (context != null) { + call.attributes.put(contextKey, context) + withContext(context.asContextElement()) { + try { + proceed() + } catch (err: Throwable) { + // Stash error for reporting later since need ktor to finish setting up the response + call.attributes.put(errorKey, err) + throw err + } + } + } else { + proceed() + } + } + + val postSendPhase = PipelinePhase("OpenTelemetryPostSend") + application.sendPipeline.insertPhaseAfter(ApplicationSendPipeline.After, postSendPhase) + application.sendPipeline.intercept(postSendPhase) { + val context = call.attributes.getOrNull(contextKey) + if (context != null) { + var error: Throwable? = call.attributes.getOrNull(errorKey) + try { + proceed() + } catch (t: Throwable) { + error = t + throw t + } finally { + tracer.end(context, call, error) + } + } else { + proceed() + } + } + } + + private fun instrumenter(builder: AbstractKtorServerTelemetryBuilder): Instrumenter { + return InstrumenterUtil.buildUpstreamInstrumenter( + builder.builder.instrumenterBuilder(), + ApplicationRequestGetter, + builder.spanKindExtractor(SpanKindExtractor.alwaysServer()) + ) + } +} diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorServerTracer.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorServerTracer.kt similarity index 92% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorServerTracer.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorServerTracer.kt index 2226f4169a94..7e6f5af975a8 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorServerTracer.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorServerTracer.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.internal +package io.opentelemetry.instrumentation.ktor.v2_0.common.internal import io.ktor.server.application.* import io.ktor.server.request.* diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorServerTracingUtil.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorServerTracingUtil.kt similarity index 88% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorServerTracingUtil.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorServerTracingUtil.kt index e5e3ea4fc908..1834e7c487e6 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/internal/KtorServerTracingUtil.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/internal/KtorServerTracingUtil.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.internal +package io.opentelemetry.instrumentation.ktor.v2_0.common.internal import io.ktor.server.application.* import io.ktor.server.request.* @@ -15,14 +15,15 @@ import io.opentelemetry.extension.kotlin.asContextElement import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor import io.opentelemetry.instrumentation.api.internal.InstrumenterUtil -import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder -import io.opentelemetry.instrumentation.ktor.server.ApplicationRequestGetter +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTracingBuilder +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.ApplicationRequestGetter import kotlinx.coroutines.withContext /** * This class is internal and is hence not for public use. Its APIs are unstable and can change at * any time. */ +@Deprecated("Use KtorServerTelemetryUtil instead", ReplaceWith("KtorServerTelemetryUtil")) object KtorServerTracingUtil { fun configureTracing(builder: AbstractKtorServerTracingBuilder, application: Application) { diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/AbstractKtorServerTelemetryBuilder.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/AbstractKtorServerTelemetryBuilder.kt new file mode 100644 index 000000000000..e8a3754337ab --- /dev/null +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/AbstractKtorServerTelemetryBuilder.kt @@ -0,0 +1,149 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.common.server + +import io.ktor.http.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.opentelemetry.api.OpenTelemetry +import io.opentelemetry.api.common.AttributesBuilder +import io.opentelemetry.api.trace.SpanKind +import io.opentelemetry.context.Context +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor +import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil + +abstract class AbstractKtorServerTelemetryBuilder(private val instrumentationName: String) { + companion object { + init { + KtorBuilderUtil.serverBuilderExtractor = { it.builder } + } + } + + internal lateinit var builder: DefaultHttpServerInstrumenterBuilder + + internal var spanKindExtractor: + (SpanKindExtractor) -> SpanKindExtractor = { a -> a } + + fun setOpenTelemetry(openTelemetry: OpenTelemetry) { + this.builder = + DefaultHttpServerInstrumenterBuilder.create( + instrumentationName, + openTelemetry, + KtorHttpServerAttributesGetter.INSTANCE + ) + } + + fun spanStatusExtractor(extract: SpanStatusData.(SpanStatusExtractor) -> Unit) { + builder.setStatusExtractor { prevExtractor -> + SpanStatusExtractor { spanStatusBuilder: SpanStatusBuilder, + request: ApplicationRequest, + response: ApplicationResponse?, + throwable: Throwable? -> + extract( + SpanStatusData(spanStatusBuilder, request, response, throwable), + prevExtractor + ) + } + } + } + + data class SpanStatusData( + val spanStatusBuilder: SpanStatusBuilder, + val request: ApplicationRequest, + val response: ApplicationResponse?, + val error: Throwable? + ) + + fun spanKindExtractor(extract: ApplicationRequest.(SpanKindExtractor) -> SpanKind) { + spanKindExtractor = { prevExtractor -> + SpanKindExtractor { request: ApplicationRequest -> + extract(request, prevExtractor) + } + } + } + + fun attributesExtractor(extractorBuilder: ExtractorBuilder.() -> Unit = {}) { + val builder = ExtractorBuilder().apply(extractorBuilder).build() + this.builder.addAttributesExtractor( + object : AttributesExtractor { + override fun onStart(attributes: AttributesBuilder, parentContext: Context, request: ApplicationRequest) { + builder.onStart(OnStartData(attributes, parentContext, request)) + } + + override fun onEnd(attributes: AttributesBuilder, context: Context, request: ApplicationRequest, response: ApplicationResponse?, error: Throwable?) { + builder.onEnd(OnEndData(attributes, context, request, response, error)) + } + } + ) + } + + class ExtractorBuilder { + private var onStart: OnStartData.() -> Unit = {} + private var onEnd: OnEndData.() -> Unit = {} + + fun onStart(block: OnStartData.() -> Unit) { + onStart = block + } + + fun onEnd(block: OnEndData.() -> Unit) { + onEnd = block + } + + internal fun build(): Extractor { + return Extractor(onStart, onEnd) + } + } + + internal class Extractor(val onStart: OnStartData.() -> Unit, val onEnd: OnEndData.() -> Unit) + + data class OnStartData( + val attributes: AttributesBuilder, + val parentContext: Context, + val request: ApplicationRequest + ) + + data class OnEndData( + val attributes: AttributesBuilder, + val parentContext: Context, + val request: ApplicationRequest, + val response: ApplicationResponse?, + val error: Throwable? + ) + + fun capturedRequestHeaders(vararg headers: String) = capturedRequestHeaders(headers.asIterable()) + + fun capturedRequestHeaders(headers: Iterable) { + builder.setCapturedRequestHeaders(headers.toList()) + } + + fun capturedResponseHeaders(vararg headers: String) = capturedResponseHeaders(headers.asIterable()) + + fun capturedResponseHeaders(headers: Iterable) { + builder.setCapturedResponseHeaders(headers.toList()) + } + + fun knownMethods(vararg methods: String) = knownMethods(methods.asIterable()) + + fun knownMethods(vararg methods: HttpMethod) = knownMethods(methods.asIterable()) + + @JvmName("knownMethodsJvm") + fun knownMethods(methods: Iterable) = knownMethods(methods.map { it.value }) + + fun knownMethods(methods: Iterable) { + methods.toSet().apply { + builder.setKnownMethods(this) + } + } + + /** + * {@link #setOpenTelemetry(OpenTelemetry)} sets the serverBuilder to a non-null value. + */ + fun isOpenTelemetryInitialized(): Boolean = this::builder.isInitialized +} diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/server/AbstractKtorServerTracingBuilder.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/AbstractKtorServerTracingBuilder.kt similarity index 95% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/server/AbstractKtorServerTracingBuilder.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/AbstractKtorServerTracingBuilder.kt index 65abba99460c..64c67b4d70ff 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/server/AbstractKtorServerTracingBuilder.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/AbstractKtorServerTracingBuilder.kt @@ -3,10 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.server +package io.opentelemetry.instrumentation.ktor.v2_0.common.server import io.ktor.http.* -import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.opentelemetry.api.OpenTelemetry @@ -18,12 +17,13 @@ import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor -import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtilOld +@Deprecated("Use AbstractKtorServerTelemetryBuilder instead", ReplaceWith("AbstractKtorServerTelemetryBuilder")) abstract class AbstractKtorServerTracingBuilder(private val instrumentationName: String) { companion object { init { - KtorBuilderUtil.serverBuilderExtractor = { it.serverBuilder } + KtorBuilderUtilOld.serverBuilderExtractor = { it.serverBuilder } } } diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/server/ApplicationRequestGetter.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/ApplicationRequestGetter.kt similarity index 88% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/server/ApplicationRequestGetter.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/ApplicationRequestGetter.kt index 053436977ef2..cfe7e0b35a11 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/server/ApplicationRequestGetter.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/ApplicationRequestGetter.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.server +package io.opentelemetry.instrumentation.ktor.v2_0.common.server import io.ktor.server.request.* import io.opentelemetry.context.propagation.TextMapGetter diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/server/KtorHttpServerAttributesGetter.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/KtorHttpServerAttributesGetter.kt similarity index 96% rename from instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/server/KtorHttpServerAttributesGetter.kt rename to instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/KtorHttpServerAttributesGetter.kt index 9471aa44f64b..d49daead2c9d 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/server/KtorHttpServerAttributesGetter.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/server/KtorHttpServerAttributesGetter.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.ktor.server +package io.opentelemetry.instrumentation.ktor.v2_0.common.server import io.ktor.server.plugins.* import io.ktor.server.request.* diff --git a/instrumentation/ktor/ktor-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v2_0/HttpClientInstrumentation.java b/instrumentation/ktor/ktor-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v2_0/HttpClientInstrumentation.java index 79fb525fdb7a..65e8ded4e967 100644 --- a/instrumentation/ktor/ktor-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v2_0/HttpClientInstrumentation.java +++ b/instrumentation/ktor/ktor-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v2_0/HttpClientInstrumentation.java @@ -13,9 +13,9 @@ import io.ktor.client.HttpClientConfig; import io.ktor.client.engine.HttpClientEngineConfig; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil; -import io.opentelemetry.instrumentation.ktor.v2_0.client.KtorClientTracing; -import io.opentelemetry.instrumentation.ktor.v2_0.client.KtorClientTracingBuilder; +import io.opentelemetry.instrumentation.ktor.v2_0.client.KtorClientTelemetry; +import io.opentelemetry.instrumentation.ktor.v2_0.client.KtorClientTelemetryBuilder; +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil; import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -46,14 +46,14 @@ public static class ConstructorAdvice { @Advice.OnMethodEnter public static void onEnter( @Advice.Argument(1) HttpClientConfig httpClientConfig) { - httpClientConfig.install(KtorClientTracing.Companion, new SetupFunction()); + httpClientConfig.install(KtorClientTelemetry.Companion, new SetupFunction()); } } - public static class SetupFunction implements Function1 { + public static class SetupFunction implements Function1 { @Override - public Unit invoke(KtorClientTracingBuilder builder) { + public Unit invoke(KtorClientTelemetryBuilder builder) { builder.setOpenTelemetry(GlobalOpenTelemetry.get()); KtorBuilderUtil.clientBuilderExtractor.invoke(builder).configure(AgentCommonConfig.get()); return kotlin.Unit.INSTANCE; diff --git a/instrumentation/ktor/ktor-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v2_0/ServerInstrumentation.java b/instrumentation/ktor/ktor-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v2_0/ServerInstrumentation.java index 214d94d80df0..6f9611499bec 100644 --- a/instrumentation/ktor/ktor-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v2_0/ServerInstrumentation.java +++ b/instrumentation/ktor/ktor-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v2_0/ServerInstrumentation.java @@ -11,9 +11,9 @@ import io.ktor.server.application.Application; import io.ktor.server.application.ApplicationPluginKt; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil; -import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder; -import io.opentelemetry.instrumentation.ktor.v2_0.server.KtorServerTracingBuilderKt; +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil; +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTelemetryBuilder; +import io.opentelemetry.instrumentation.ktor.v2_0.server.KtorServerTelemetryBuilderKt; import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -41,15 +41,15 @@ public static class ConstructorAdvice { @Advice.OnMethodExit public static void onExit(@Advice.FieldValue("_applicationInstance") Application application) { ApplicationPluginKt.install( - application, KtorServerTracingBuilderKt.getKtorServerTracing(), new SetupFunction()); + application, KtorServerTelemetryBuilderKt.getKtorServerTelemetry(), new SetupFunction()); } } public static class SetupFunction - implements Function1 { + implements Function1 { @Override - public Unit invoke(AbstractKtorServerTracingBuilder builder) { + public Unit invoke(AbstractKtorServerTelemetryBuilder builder) { builder.setOpenTelemetry(GlobalOpenTelemetry.get()); KtorBuilderUtil.serverBuilderExtractor.invoke(builder).configure(AgentCommonConfig.get()); return kotlin.Unit.INSTANCE; diff --git a/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTelemetry.kt b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTelemetry.kt new file mode 100644 index 000000000000..3963999e9b63 --- /dev/null +++ b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTelemetry.kt @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.client + +import io.ktor.client.* +import io.ktor.client.plugins.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.util.* +import io.opentelemetry.context.propagation.ContextPropagators +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTelemetry +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorClientTelemetryUtil + +class KtorClientTelemetry internal constructor( + instrumenter: Instrumenter, + propagators: ContextPropagators +) : AbstractKtorClientTelemetry(instrumenter, propagators) { + + companion object : HttpClientPlugin { + + override val key = AttributeKey("OpenTelemetry") + + override fun prepare(block: KtorClientTelemetryBuilder.() -> Unit) = KtorClientTelemetryBuilder().apply(block).build() + + override fun install(plugin: KtorClientTelemetry, scope: HttpClient) { + KtorClientTelemetryUtil.install(plugin, scope) + } + } +} diff --git a/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTelemetryBuilder.kt b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTelemetryBuilder.kt new file mode 100644 index 000000000000..6e5449f1d2ef --- /dev/null +++ b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTelemetryBuilder.kt @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.client + +import io.opentelemetry.instrumentation.ktor.v2_0.InstrumentationProperties.INSTRUMENTATION_NAME +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTelemetryBuilder + +class KtorClientTelemetryBuilder : AbstractKtorClientTelemetryBuilder(INSTRUMENTATION_NAME) { + + internal fun build(): KtorClientTelemetry = KtorClientTelemetry( + instrumenter = builder.build(), + propagators = getOpenTelemetry().propagators, + ) +} diff --git a/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTracing.kt b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTracing.kt index 429e2ccdfe0c..d9dcf9796f67 100644 --- a/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTracing.kt +++ b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTracing.kt @@ -12,9 +12,10 @@ import io.ktor.client.statement.* import io.ktor.util.* import io.opentelemetry.context.propagation.ContextPropagators import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter -import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracing -import io.opentelemetry.instrumentation.ktor.internal.KtorClientTracingUtil +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracing +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorClientTracingUtil +@Deprecated("Use KtorClientTelemetry instead", ReplaceWith("KtorClientTelemetry")) class KtorClientTracing internal constructor( instrumenter: Instrumenter, propagators: ContextPropagators diff --git a/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTracingBuilder.kt b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTracingBuilder.kt index b93fb82f02da..706852a3178a 100644 --- a/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTracingBuilder.kt +++ b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorClientTracingBuilder.kt @@ -5,9 +5,10 @@ package io.opentelemetry.instrumentation.ktor.v2_0.client -import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracingBuilder import io.opentelemetry.instrumentation.ktor.v2_0.InstrumentationProperties.INSTRUMENTATION_NAME +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracingBuilder +@Deprecated("Use KtorClientTelemetryBuilder instead", ReplaceWith("KtorClientTelemetryBuilder")) class KtorClientTracingBuilder : AbstractKtorClientTracingBuilder(INSTRUMENTATION_NAME) { internal fun build(): KtorClientTracing = KtorClientTracing( diff --git a/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorServerTelemetryBuilder.kt b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorServerTelemetryBuilder.kt new file mode 100644 index 000000000000..af6a84d9ee5e --- /dev/null +++ b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorServerTelemetryBuilder.kt @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v2_0.server + +import io.ktor.server.application.* +import io.ktor.server.routing.* +import io.opentelemetry.context.Context +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource +import io.opentelemetry.instrumentation.ktor.v2_0.InstrumentationProperties.INSTRUMENTATION_NAME +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorServerTelemetryUtil +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTelemetryBuilder + +class KtorServerTelemetryBuilder internal constructor( + instrumentationName: String +) : AbstractKtorServerTelemetryBuilder(instrumentationName) + +val KtorServerTelemetry = createRouteScopedPlugin("OpenTelemetry", { KtorServerTelemetryBuilder(INSTRUMENTATION_NAME) }) { + require(pluginConfig.isOpenTelemetryInitialized()) { "OpenTelemetry must be set" } + + KtorServerTelemetryUtil.configureTelemetry(pluginConfig, application) + + application.environment.monitor.subscribe(Routing.RoutingCallStarted) { call -> + HttpServerRoute.update(Context.current(), HttpServerRouteSource.SERVER, { _, arg -> arg.route.parent.toString() }, call) + } +} diff --git a/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorServerTracingBuilder.kt b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorServerTracingBuilder.kt index b2c4be9b86db..c82c99fccb5e 100644 --- a/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorServerTracingBuilder.kt +++ b/instrumentation/ktor/ktor-2.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorServerTracingBuilder.kt @@ -10,10 +10,11 @@ import io.ktor.server.routing.* import io.opentelemetry.context.Context import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource -import io.opentelemetry.instrumentation.ktor.internal.KtorServerTracingUtil -import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder import io.opentelemetry.instrumentation.ktor.v2_0.InstrumentationProperties.INSTRUMENTATION_NAME +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorServerTracingUtil +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTracingBuilder +@Deprecated("Use KtorServerTelemetryBuilder instead", ReplaceWith("KtorServerTelemetryBuilder")) class KtorServerTracingBuilder internal constructor( instrumentationName: String ) : AbstractKtorServerTracingBuilder(instrumentationName) diff --git a/instrumentation/ktor/ktor-2.0/testing/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/AbstractKtorHttpClientTest.kt b/instrumentation/ktor/ktor-2.0/testing/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/AbstractKtorHttpClientTest.kt index 991e32f347f6..25984db55484 100644 --- a/instrumentation/ktor/ktor-2.0/testing/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/AbstractKtorHttpClientTest.kt +++ b/instrumentation/ktor/ktor-2.0/testing/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/AbstractKtorHttpClientTest.kt @@ -17,7 +17,10 @@ import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions.DEFAULT_HTTP_ATTRIBUTES import io.opentelemetry.semconv.NetworkAttributes -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.AfterAll import java.net.URI diff --git a/instrumentation/ktor/ktor-2.0/testing/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorHttpClientSingleConnection.kt b/instrumentation/ktor/ktor-2.0/testing/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorHttpClientSingleConnection.kt index 2396d62bb6b1..4e61403a4bdf 100644 --- a/instrumentation/ktor/ktor-2.0/testing/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorHttpClientSingleConnection.kt +++ b/instrumentation/ktor/ktor-2.0/testing/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/client/KtorHttpClientSingleConnection.kt @@ -6,7 +6,6 @@ package io.opentelemetry.instrumentation.ktor.v2_0.client import io.ktor.client.* -import io.ktor.client.engine.cio.* import io.ktor.client.request.* import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection import kotlinx.coroutines.runBlocking diff --git a/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/HttpClientInstrumentation.java b/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/HttpClientInstrumentation.java index 09dfcca67e20..0ab6f7609276 100644 --- a/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/HttpClientInstrumentation.java +++ b/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/HttpClientInstrumentation.java @@ -13,9 +13,9 @@ import io.ktor.client.HttpClientConfig; import io.ktor.client.engine.HttpClientEngineConfig; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil; -import io.opentelemetry.instrumentation.ktor.v3_0.client.KtorClientTracing; -import io.opentelemetry.instrumentation.ktor.v3_0.client.KtorClientTracingBuilder; +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil; +import io.opentelemetry.instrumentation.ktor.v3_0.client.KtorClientTelemetry; +import io.opentelemetry.instrumentation.ktor.v3_0.client.KtorClientTelemetryBuilder; import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -46,14 +46,14 @@ public static class ConstructorAdvice { @Advice.OnMethodEnter public static void onEnter( @Advice.Argument(1) HttpClientConfig httpClientConfig) { - httpClientConfig.install(KtorClientTracing.Companion, new SetupFunction()); + httpClientConfig.install(KtorClientTelemetry.Companion, new SetupFunction()); } } - public static class SetupFunction implements Function1 { + public static class SetupFunction implements Function1 { @Override - public Unit invoke(KtorClientTracingBuilder builder) { + public Unit invoke(KtorClientTelemetryBuilder builder) { builder.setOpenTelemetry(GlobalOpenTelemetry.get()); KtorBuilderUtil.clientBuilderExtractor.invoke(builder).configure(AgentCommonConfig.get()); return Unit.INSTANCE; diff --git a/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/ServerInstrumentation.java b/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/ServerInstrumentation.java index df4335fa686d..b4b5a0832256 100644 --- a/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/ServerInstrumentation.java +++ b/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/ServerInstrumentation.java @@ -11,9 +11,9 @@ import io.ktor.server.application.Application; import io.ktor.server.application.ApplicationPluginKt; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil; -import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder; -import io.opentelemetry.instrumentation.ktor.v3_0.server.KtorServerTracingBuilderKt; +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil; +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTelemetryBuilder; +import io.opentelemetry.instrumentation.ktor.v3_0.server.KtorServerTelemetryBuilderKt; import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -41,14 +41,14 @@ public static class ConstructorAdvice { @Advice.OnMethodExit public static void onExit(@Advice.FieldValue("_applicationInstance") Application application) { ApplicationPluginKt.install( - application, KtorServerTracingBuilderKt.getKtorServerTracing(), new SetupFunction()); + application, KtorServerTelemetryBuilderKt.getKtorServerTelemetry(), new SetupFunction()); } } - public static class SetupFunction implements Function1 { + public static class SetupFunction implements Function1 { @Override - public Unit invoke(AbstractKtorServerTracingBuilder builder) { + public Unit invoke(AbstractKtorServerTelemetryBuilder builder) { builder.setOpenTelemetry(GlobalOpenTelemetry.get()); KtorBuilderUtil.serverBuilderExtractor.invoke(builder).configure(AgentCommonConfig.get()); return Unit.INSTANCE; diff --git a/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTelemetry.kt b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTelemetry.kt new file mode 100644 index 000000000000..aa0f2d4ecf88 --- /dev/null +++ b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTelemetry.kt @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v3_0.client + +import io.ktor.client.* +import io.ktor.client.plugins.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.util.* +import io.opentelemetry.context.propagation.ContextPropagators +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTelemetry +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorClientTelemetryUtil + +class KtorClientTelemetry internal constructor( + instrumenter: Instrumenter, + propagators: ContextPropagators +) : AbstractKtorClientTelemetry(instrumenter, propagators) { + + companion object : HttpClientPlugin { + + override val key = AttributeKey("OpenTelemetry") + + override fun prepare(block: KtorClientTelemetryBuilder.() -> Unit) = KtorClientTelemetryBuilder().apply(block).build() + + override fun install(plugin: KtorClientTelemetry, scope: HttpClient) { + KtorClientTelemetryUtil.install(plugin, scope) + } + } +} diff --git a/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTelemetryBuilder.kt b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTelemetryBuilder.kt new file mode 100644 index 000000000000..bbf21d7a8b48 --- /dev/null +++ b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTelemetryBuilder.kt @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v3_0.client + +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTelemetryBuilder +import io.opentelemetry.instrumentation.ktor.v3_0.InstrumentationProperties.INSTRUMENTATION_NAME + +class KtorClientTelemetryBuilder : AbstractKtorClientTelemetryBuilder(INSTRUMENTATION_NAME) { + + internal fun build(): KtorClientTelemetry = KtorClientTelemetry( + instrumenter = builder.build(), + propagators = getOpenTelemetry().propagators, + ) +} diff --git a/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTracing.kt b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTracing.kt index d5bf578cc56c..b63c4f6974ad 100644 --- a/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTracing.kt +++ b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTracing.kt @@ -12,9 +12,10 @@ import io.ktor.client.statement.* import io.ktor.util.* import io.opentelemetry.context.propagation.ContextPropagators import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter -import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracing -import io.opentelemetry.instrumentation.ktor.internal.KtorClientTracingUtil +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracing +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorClientTracingUtil +@Deprecated("Use KtorClientTelemetry instead", ReplaceWith("KtorClientTelemetry")) class KtorClientTracing internal constructor( instrumenter: Instrumenter, propagators: ContextPropagators diff --git a/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTracingBuilder.kt b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTracingBuilder.kt index 6f68939d9f06..b4787662b8e2 100644 --- a/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTracingBuilder.kt +++ b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/client/KtorClientTracingBuilder.kt @@ -5,9 +5,10 @@ package io.opentelemetry.instrumentation.ktor.v3_0.client -import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracingBuilder +import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracingBuilder import io.opentelemetry.instrumentation.ktor.v3_0.InstrumentationProperties.INSTRUMENTATION_NAME +@Deprecated("Use KtorClientTelemetryBuilder instead", ReplaceWith("KtorClientTelemetryBuilder")) class KtorClientTracingBuilder : AbstractKtorClientTracingBuilder(INSTRUMENTATION_NAME) { internal fun build(): KtorClientTracing = KtorClientTracing( diff --git a/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/server/KtorServerTelemetryBuilder.kt b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/server/KtorServerTelemetryBuilder.kt new file mode 100644 index 000000000000..43c4ec92952a --- /dev/null +++ b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/server/KtorServerTelemetryBuilder.kt @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ktor.v3_0.server + +import io.ktor.server.application.* +import io.ktor.server.routing.* +import io.opentelemetry.context.Context +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorServerTelemetryUtil +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTelemetryBuilder +import io.opentelemetry.instrumentation.ktor.v3_0.InstrumentationProperties.INSTRUMENTATION_NAME + +class KtorServerTelemetryBuilder internal constructor( + instrumentationName: String +) : AbstractKtorServerTelemetryBuilder(instrumentationName) + +val KtorServerTelemetry = createRouteScopedPlugin("OpenTelemetry", { KtorServerTelemetryBuilder(INSTRUMENTATION_NAME) }) { + require(pluginConfig.isOpenTelemetryInitialized()) { "OpenTelemetry must be set" } + + KtorServerTelemetryUtil.configureTelemetry(pluginConfig, application) + + application.monitor.subscribe(RoutingRoot.RoutingCallStarted) { call -> + HttpServerRoute.update(Context.current(), HttpServerRouteSource.SERVER, { _, arg -> arg.route.parent.toString() }, call) + } +} diff --git a/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/server/KtorServerTracingBuilder.kt b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/server/KtorServerTracingBuilder.kt index a086f7473fd8..e77e5487c866 100644 --- a/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/server/KtorServerTracingBuilder.kt +++ b/instrumentation/ktor/ktor-3.0/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v3_0/server/KtorServerTracingBuilder.kt @@ -10,10 +10,11 @@ import io.ktor.server.routing.* import io.opentelemetry.context.Context import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource -import io.opentelemetry.instrumentation.ktor.internal.KtorServerTracingUtil -import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder +import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorServerTracingUtil +import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTracingBuilder import io.opentelemetry.instrumentation.ktor.v3_0.InstrumentationProperties.INSTRUMENTATION_NAME +@Deprecated("Use KtorServerTelemetryBuilder instead", ReplaceWith("KtorServerTelemetryBuilder")) class KtorServerTracingBuilder internal constructor( instrumentationName: String ) : AbstractKtorServerTracingBuilder(instrumentationName) diff --git a/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/NettyClientTelemetryBuilder.java b/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/NettyClientTelemetryBuilder.java index a7e3b8d61bb3..f1a9a092a771 100644 --- a/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/NettyClientTelemetryBuilder.java +++ b/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/NettyClientTelemetryBuilder.java @@ -11,30 +11,39 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; import io.opentelemetry.instrumentation.netty.v4.common.HttpRequestAndChannel; import io.opentelemetry.instrumentation.netty.v4.common.internal.client.NettyClientInstrumenterBuilderFactory; import io.opentelemetry.instrumentation.netty.v4.common.internal.client.NettyClientInstrumenterFactory; import io.opentelemetry.instrumentation.netty.v4.common.internal.client.NettyConnectionInstrumentationFlag; +import io.opentelemetry.instrumentation.netty.v4_1.internal.Experimental; import java.util.List; import java.util.Set; import java.util.function.Function; /** A builder of {@link NettyClientTelemetry}. */ -public final class NettyClientTelemetryBuilder { +public final class NettyClientTelemetryBuilder + implements HttpClientTelemetryBuilder { private final DefaultHttpClientInstrumenterBuilder builder; - private boolean emitExperimentalHttpClientEvents = false; + private boolean emitExperimentalTelemetry = false; NettyClientTelemetryBuilder(OpenTelemetry openTelemetry) { builder = NettyClientInstrumenterBuilderFactory.create("io.opentelemetry.netty-4.1", openTelemetry); } + /** + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(NettyClientTelemetryBuilder, + * boolean)} instead. + */ + @Deprecated @CanIgnoreReturnValue public NettyClientTelemetryBuilder setEmitExperimentalHttpClientEvents( - boolean emitExperimentalHttpClientEvents) { - this.emitExperimentalHttpClientEvents = emitExperimentalHttpClientEvents; + boolean emitExperimentalTelemetry) { + this.emitExperimentalTelemetry = emitExperimentalTelemetry; return this; } @@ -43,6 +52,7 @@ public NettyClientTelemetryBuilder setEmitExperimentalHttpClientEvents( * * @param capturedRequestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public NettyClientTelemetryBuilder setCapturedRequestHeaders( List capturedRequestHeaders) { @@ -55,6 +65,7 @@ public NettyClientTelemetryBuilder setCapturedRequestHeaders( * * @param capturedResponseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public NettyClientTelemetryBuilder setCapturedResponseHeaders( List capturedResponseHeaders) { @@ -66,10 +77,11 @@ public NettyClientTelemetryBuilder setCapturedResponseHeaders( * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. */ + @Override @CanIgnoreReturnValue public NettyClientTelemetryBuilder addAttributesExtractor( AttributesExtractor attributesExtractor) { - builder.addAttributeExtractor(attributesExtractor); + builder.addAttributesExtractor(attributesExtractor); return this; } @@ -86,6 +98,7 @@ public NettyClientTelemetryBuilder addAttributesExtractor( * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public NettyClientTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -95,28 +108,42 @@ public NettyClientTelemetryBuilder setKnownMethods(Set knownMethods) { /** * Configures the instrumentation to emit experimental HTTP client metrics. * - * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics - * are to be emitted. + * @param emitExperimentalTelemetry {@code true} if the experimental HTTP client metrics are to be + * emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(NettyClientTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public NettyClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( - boolean emitExperimentalHttpClientMetrics) { - builder.setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientMetrics); + boolean emitExperimentalTelemetry) { + builder.setEmitExperimentalHttpClientMetrics(emitExperimentalTelemetry); + this.emitExperimentalTelemetry = emitExperimentalTelemetry; return this; } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public NettyClientTelemetryBuilder setSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; } + @Override + public NettyClientTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** Returns a new {@link NettyClientTelemetry} with the given configuration. */ + @Override public NettyClientTelemetry build() { return new NettyClientTelemetry( new NettyClientInstrumenterFactory( @@ -124,6 +151,6 @@ public NettyClientTelemetry build() { NettyConnectionInstrumentationFlag.DISABLED, NettyConnectionInstrumentationFlag.DISABLED) .instrumenter(), - emitExperimentalHttpClientEvents); + emitExperimentalTelemetry); } } diff --git a/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/NettyServerTelemetryBuilder.java b/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/NettyServerTelemetryBuilder.java index 874bcb586bed..f65b22e32011 100644 --- a/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/NettyServerTelemetryBuilder.java +++ b/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/NettyServerTelemetryBuilder.java @@ -9,17 +9,24 @@ import io.netty.handler.codec.http.HttpResponse; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder; import io.opentelemetry.instrumentation.netty.v4.common.HttpRequestAndChannel; import io.opentelemetry.instrumentation.netty.v4.common.internal.server.HttpRequestHeadersGetter; import io.opentelemetry.instrumentation.netty.v4.common.internal.server.NettyHttpServerAttributesGetter; +import io.opentelemetry.instrumentation.netty.v4_1.internal.Experimental; import io.opentelemetry.instrumentation.netty.v4_1.internal.ProtocolEventHandler; import io.opentelemetry.instrumentation.netty.v4_1.internal.server.NettyServerInstrumenterBuilderUtil; import java.util.List; import java.util.Set; +import java.util.function.Function; /** A builder of {@link NettyServerTelemetry}. */ -public final class NettyServerTelemetryBuilder { +public final class NettyServerTelemetryBuilder + implements HttpServerTelemetryBuilder { private final DefaultHttpServerInstrumenterBuilder builder; @@ -39,6 +46,31 @@ public final class NettyServerTelemetryBuilder { HttpRequestHeadersGetter.INSTANCE); } + @Override + public NettyServerTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + @Override + public NettyServerTelemetryBuilder setSpanNameExtractor( + Function, SpanNameExtractor> + spanNameExtractorTransformer) { + builder.setSpanNameExtractor(spanNameExtractorTransformer); + return this; + } + + @Override + public NettyServerTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Configures emission of experimental events. * @@ -56,6 +88,7 @@ public NettyServerTelemetryBuilder setEmitExperimentalHttpServerEvents( * * @param capturedRequestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public NettyServerTelemetryBuilder setCapturedRequestHeaders( List capturedRequestHeaders) { @@ -68,6 +101,7 @@ public NettyServerTelemetryBuilder setCapturedRequestHeaders( * * @param capturedResponseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public NettyServerTelemetryBuilder setCapturedResponseHeaders( List capturedResponseHeaders) { @@ -88,6 +122,7 @@ public NettyServerTelemetryBuilder setCapturedResponseHeaders( * @param knownMethods A set of recognized HTTP request methods. * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public NettyServerTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -99,7 +134,10 @@ public NettyServerTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpServerMetrics {@code true} if the experimental HTTP server metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(NettyServerTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public NettyServerTelemetryBuilder setEmitExperimentalHttpServerMetrics( boolean emitExperimentalHttpServerMetrics) { @@ -108,6 +146,7 @@ public NettyServerTelemetryBuilder setEmitExperimentalHttpServerMetrics( } /** Returns a new {@link NettyServerTelemetry} with the given configuration. */ + @Override public NettyServerTelemetry build() { return new NettyServerTelemetry( builder.build(), diff --git a/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/internal/Experimental.java b/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/internal/Experimental.java new file mode 100644 index 000000000000..a92e890a752d --- /dev/null +++ b/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/internal/Experimental.java @@ -0,0 +1,85 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.netty.v4_1.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.netty.v4_1.NettyClientTelemetryBuilder; +import io.opentelemetry.instrumentation.netty.v4_1.NettyServerTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalClientTelemetryMethod = + getEmitExperimentalClientTelemetryMethod(); + + @Nullable + private static final Method emitExperimentalServerTelemetryMethod = + getEmitExperimentalServerTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + NettyClientTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalClientTelemetryMethod != null) { + try { + emitExperimentalClientTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + public void setEmitExperimentalTelemetry( + NettyServerTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalServerTelemetryMethod != null) { + try { + emitExperimentalServerTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalClientTelemetryMethod() { + try { + Method method = + NettyClientTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } + + @Nullable + private static Method getEmitExperimentalServerTelemetryMethod() { + try { + Method method = + NettyServerTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpServerMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/OkHttpTelemetryBuilder.java b/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/OkHttpTelemetryBuilder.java index 3595aaa91a20..9c5527a4db07 100644 --- a/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/OkHttpTelemetryBuilder.java +++ b/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/OkHttpTelemetryBuilder.java @@ -10,7 +10,10 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; +import io.opentelemetry.instrumentation.okhttp.v3_0.internal.Experimental; import io.opentelemetry.instrumentation.okhttp.v3_0.internal.OkHttpClientInstrumenterBuilderFactory; import java.util.List; import java.util.Set; @@ -19,7 +22,8 @@ import okhttp3.Response; /** A builder of {@link OkHttpTelemetry}. */ -public final class OkHttpTelemetryBuilder { +public final class OkHttpTelemetryBuilder + implements HttpClientTelemetryBuilder { private final DefaultHttpClientInstrumenterBuilder builder; private final OpenTelemetry openTelemetry; @@ -32,11 +36,26 @@ public final class OkHttpTelemetryBuilder { /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. + * + * @deprecated Use {@link #addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public OkHttpTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { - builder.addAttributeExtractor(attributesExtractor); + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. + */ + @Override + @CanIgnoreReturnValue + public OkHttpTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); return this; } @@ -45,6 +64,7 @@ public OkHttpTelemetryBuilder addAttributeExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public OkHttpTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -56,6 +76,7 @@ public OkHttpTelemetryBuilder setCapturedRequestHeaders(List requestHead * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public OkHttpTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -75,6 +96,7 @@ public OkHttpTelemetryBuilder setCapturedResponseHeaders(List responseHe * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public OkHttpTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -86,7 +108,10 @@ public OkHttpTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(OkHttpTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public OkHttpTelemetryBuilder setEmitExperimentalHttpClientMetrics( boolean emitExperimentalHttpClientMetrics) { @@ -95,19 +120,29 @@ public OkHttpTelemetryBuilder setEmitExperimentalHttpClientMetrics( } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public OkHttpTelemetryBuilder setSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; } + @Override + public OkHttpTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Returns a new {@link OkHttpTelemetry} with the settings of this {@link OkHttpTelemetryBuilder}. */ + @Override public OkHttpTelemetry build() { return new OkHttpTelemetry(builder.build(), openTelemetry.getPropagators()); } diff --git a/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/internal/Experimental.java b/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/internal/Experimental.java new file mode 100644 index 000000000000..97c99b9baac1 --- /dev/null +++ b/instrumentation/okhttp/okhttp-3.0/library/src/main/java/io/opentelemetry/instrumentation/okhttp/v3_0/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.okhttp.v3_0.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + OkHttpTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + OkHttpTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/quartz-2.0/library/src/main/java/io/opentelemetry/instrumentation/quartz/v2_0/QuartzTelemetryBuilder.java b/instrumentation/quartz-2.0/library/src/main/java/io/opentelemetry/instrumentation/quartz/v2_0/QuartzTelemetryBuilder.java index 27269c4b45e1..e857de5f9398 100644 --- a/instrumentation/quartz-2.0/library/src/main/java/io/opentelemetry/instrumentation/quartz/v2_0/QuartzTelemetryBuilder.java +++ b/instrumentation/quartz-2.0/library/src/main/java/io/opentelemetry/instrumentation/quartz/v2_0/QuartzTelemetryBuilder.java @@ -38,7 +38,10 @@ public final class QuartzTelemetryBuilder { /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. The {@link AttributesExtractor} will be executed after all default extractors. + * + * @deprecated Use {@link #addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public QuartzTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { @@ -46,6 +49,17 @@ public QuartzTelemetryBuilder addAttributeExtractor( return this; } + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. The {@link AttributesExtractor} will be executed after all default extractors. + */ + @CanIgnoreReturnValue + public QuartzTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + additionalExtractors.add(attributesExtractor); + return this; + } + /** * Sets whether experimental attributes should be set to spans. These attributes may be changed or * removed in the future, so only enable this if you know you do not require attributes filled by diff --git a/instrumentation/r2dbc-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/r2dbc/v1_0/R2dbcSingletons.java b/instrumentation/r2dbc-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/r2dbc/v1_0/R2dbcSingletons.java index 36ebe81accbf..e733a77f8a0e 100644 --- a/instrumentation/r2dbc-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/r2dbc/v1_0/R2dbcSingletons.java +++ b/instrumentation/r2dbc-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/r2dbc/v1_0/R2dbcSingletons.java @@ -21,7 +21,7 @@ public final class R2dbcSingletons { .getBoolean( "otel.instrumentation.r2dbc.statement-sanitizer.enabled", AgentCommonConfig.get().isStatementSanitizationEnabled())) - .addAttributeExtractor( + .addAttributesExtractor( PeerServiceAttributesExtractor.create( R2dbcNetAttributesGetter.INSTANCE, AgentCommonConfig.get().getPeerServiceResolver())) diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java index 3cd1f16e0eaf..413212a8eb2d 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/R2dbcTelemetryBuilder.java @@ -25,10 +25,21 @@ public final class R2dbcTelemetryBuilder { instrumenterBuilder = new R2dbcInstrumenterBuilder(openTelemetry); } + /** + * @deprecated Use {@link #addAttributesExtractor(AttributesExtractor)} instead. + */ + @Deprecated @CanIgnoreReturnValue public R2dbcTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { - instrumenterBuilder.addAttributeExtractor(attributesExtractor); + instrumenterBuilder.addAttributesExtractor(attributesExtractor); + return this; + } + + @CanIgnoreReturnValue + public R2dbcTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + instrumenterBuilder.addAttributesExtractor(attributesExtractor); return this; } diff --git a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java index f094125633bb..6db0f3a48caf 100644 --- a/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java +++ b/instrumentation/r2dbc-1.0/library/src/main/java/io/opentelemetry/instrumentation/r2dbc/v1_0/internal/R2dbcInstrumenterBuilder.java @@ -37,7 +37,7 @@ public R2dbcInstrumenterBuilder(OpenTelemetry openTelemetry) { } @CanIgnoreReturnValue - public R2dbcInstrumenterBuilder addAttributeExtractor( + public R2dbcInstrumenterBuilder addAttributesExtractor( AttributesExtractor attributesExtractor) { additionalExtractors.add(attributesExtractor); return this; diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackClientTelemetry.java b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackClientTelemetry.java new file mode 100644 index 000000000000..e8300fdd4cd7 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackClientTelemetry.java @@ -0,0 +1,62 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryExecInitializer; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryHttpClient; +import ratpack.http.client.HttpClient; +import ratpack.http.client.HttpResponse; +import ratpack.http.client.RequestSpec; +import ratpack.registry.RegistrySpec; + +/** + * Entrypoint for instrumenting Ratpack http client. + * + *

To apply OpenTelemetry instrumentation to a http client, wrap the {@link HttpClient} using + * {@link #instrument(HttpClient)}. + * + *

{@code
+ * RatpackClientTelemetry telemetry = RatpackClientTelemetry.create(OpenTelemetrySdk.builder()
+ *   ...
+ *   .build());
+ * HttpClient instrumentedHttpClient = telemetry.instrument(httpClient);
+ * }
+ */ +public final class RatpackClientTelemetry { + + /** + * Returns a new {@link RatpackClientTelemetry} configured with the given {@link OpenTelemetry}. + */ + public static RatpackClientTelemetry create(OpenTelemetry openTelemetry) { + return builder(openTelemetry).build(); + } + + /** + * Returns a new {@link RatpackClientTelemetryBuilder} configured with the given {@link + * OpenTelemetry}. + */ + public static RatpackClientTelemetryBuilder builder(OpenTelemetry openTelemetry) { + return new RatpackClientTelemetryBuilder(openTelemetry); + } + + private final OpenTelemetryHttpClient httpClientInstrumenter; + + RatpackClientTelemetry(Instrumenter clientInstrumenter) { + httpClientInstrumenter = new OpenTelemetryHttpClient(clientInstrumenter); + } + + /** Returns instrumented instance of {@link HttpClient} with OpenTelemetry. */ + public HttpClient instrument(HttpClient httpClient) throws Exception { + return httpClientInstrumenter.instrument(httpClient); + } + + /** Configures the {@link RegistrySpec} with OpenTelemetry. */ + public void configureRegistry(RegistrySpec registry) { + registry.add(OpenTelemetryExecInitializer.INSTANCE); + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackClientTelemetryBuilder.java b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackClientTelemetryBuilder.java new file mode 100644 index 000000000000..a809937be80f --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackClientTelemetryBuilder.java @@ -0,0 +1,121 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.Experimental; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.RatpackClientInstrumenterBuilderFactory; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import ratpack.http.client.HttpResponse; +import ratpack.http.client.RequestSpec; + +/** A builder for {@link RatpackClientTelemetry}. */ +public final class RatpackClientTelemetryBuilder + implements HttpClientTelemetryBuilder { + + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.ratpack-1.7"; + + private final DefaultHttpClientInstrumenterBuilder builder; + + RatpackClientTelemetryBuilder(OpenTelemetry openTelemetry) { + builder = RatpackClientInstrumenterBuilderFactory.create(INSTRUMENTATION_NAME, openTelemetry); + } + + @Override + @CanIgnoreReturnValue + public RatpackClientTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Configures the HTTP client request headers that will be captured as span attributes. + * + * @param requestHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public RatpackClientTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { + builder.setCapturedRequestHeaders(requestHeaders); + return this; + } + + /** + * Configures the HTTP client response headers that will be captured as span attributes. + * + * @param responseHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public RatpackClientTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { + builder.setCapturedResponseHeaders(responseHeaders); + return this; + } + + /** + * Configures the instrumentation to recognize an alternative set of HTTP request methods. + * + *

By default, this instrumentation defines "known" methods as the ones listed in RFC9110 and the PATCH + * method defined in RFC5789. + * + *

Note: calling this method overrides the default known method sets completely; it does + * not supplement it. + * + * @param knownMethods A set of recognized HTTP request methods. + * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) + */ + @Override + @CanIgnoreReturnValue + public RatpackClientTelemetryBuilder setKnownMethods(Set knownMethods) { + builder.setKnownMethods(knownMethods); + return this; + } + + /** Sets custom client {@link SpanNameExtractor} via transform function. */ + @Override + @CanIgnoreReturnValue + public RatpackClientTelemetryBuilder setSpanNameExtractor( + Function, SpanNameExtractor> + clientSpanNameExtractor) { + builder.setSpanNameExtractor(clientSpanNameExtractor); + return this; + } + + @Override + public RatpackClientTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + + /** + * Can be used via the unstable method {@link + * Experimental#setEmitExperimentalTelemetry(RatpackClientTelemetryBuilder, boolean)}. + */ + void setEmitExperimentalHttpClientMetrics(boolean emitExperimentalHttpClientMetrics) { + builder.setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientMetrics); + } + + /** Returns a new {@link RatpackClientTelemetry} with the configuration of this builder. */ + @Override + public RatpackClientTelemetry build() { + return new RatpackClientTelemetry(builder.build()); + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackServerTelemetry.java b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackServerTelemetry.java new file mode 100644 index 000000000000..988d3b140c4e --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackServerTelemetry.java @@ -0,0 +1,80 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryExecInitializer; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryExecInterceptor; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryServerHandler; +import ratpack.exec.ExecInitializer; +import ratpack.exec.ExecInterceptor; +import ratpack.handling.Handler; +import ratpack.handling.HandlerDecorator; +import ratpack.http.Request; +import ratpack.http.Response; +import ratpack.registry.RegistrySpec; + +/** + * Entrypoint for instrumenting Ratpack server. + * + *

To apply OpenTelemetry instrumentation to a server, configure the {@link RegistrySpec} using + * {@link #configureRegistry(RegistrySpec)}. + * + *

{@code
+ * RatpackServerTelemetry telemetry = RatpackServerTelemetry.create(OpenTelemetrySdk.builder()
+ *   ...
+ *   .build());
+ * RatpackServer.start(server -> {
+ *   server.registryOf(telemetry::configureRegistry);
+ *   server.handlers(chain -> ...);
+ * });
+ * }
+ */ +public final class RatpackServerTelemetry { + + /** + * Returns a new {@link RatpackServerTelemetry} configured with the given {@link OpenTelemetry}. + */ + public static RatpackServerTelemetry create(OpenTelemetry openTelemetry) { + return builder(openTelemetry).build(); + } + + /** + * Returns a new {@link RatpackServerTelemetryBuilder} configured with the given {@link + * OpenTelemetry}. + */ + public static RatpackServerTelemetryBuilder builder(OpenTelemetry openTelemetry) { + return new RatpackServerTelemetryBuilder(openTelemetry); + } + + private final OpenTelemetryServerHandler serverHandler; + + RatpackServerTelemetry(Instrumenter serverInstrumenter) { + serverHandler = new OpenTelemetryServerHandler(serverInstrumenter); + } + + /** Returns a {@link Handler} to support Ratpack Registry binding. */ + public Handler getHandler() { + return serverHandler; + } + + /** Returns instance of {@link ExecInterceptor} to support Ratpack Registry binding. */ + public ExecInterceptor getExecInterceptor() { + return OpenTelemetryExecInterceptor.INSTANCE; + } + + /** Returns instance of {@link ExecInitializer} to support Ratpack Registry binding. */ + public ExecInitializer getExecInitializer() { + return OpenTelemetryExecInitializer.INSTANCE; + } + + /** Configures the {@link RegistrySpec} with OpenTelemetry. */ + public void configureRegistry(RegistrySpec registry) { + registry.add(HandlerDecorator.prepend(serverHandler)); + registry.add(OpenTelemetryExecInterceptor.INSTANCE); + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackServerTelemetryBuilder.java b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackServerTelemetryBuilder.java new file mode 100644 index 000000000000..92a2c4027a92 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackServerTelemetryBuilder.java @@ -0,0 +1,122 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.Experimental; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.RatpackServerInstrumenterBuilderFactory; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import ratpack.http.Request; +import ratpack.http.Response; + +/** A builder for {@link RatpackServerTelemetry}. */ +public final class RatpackServerTelemetryBuilder + implements HttpServerTelemetryBuilder { + + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.ratpack-1.7"; + + private final DefaultHttpServerInstrumenterBuilder builder; + + RatpackServerTelemetryBuilder(OpenTelemetry openTelemetry) { + builder = RatpackServerInstrumenterBuilderFactory.create(INSTRUMENTATION_NAME, openTelemetry); + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. The {@link AttributesExtractor} will be executed after all default extractors. + */ + @Override + @CanIgnoreReturnValue + public RatpackServerTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Configures the HTTP server request headers that will be captured as span attributes. + * + * @param requestHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public RatpackServerTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { + builder.setCapturedRequestHeaders(requestHeaders); + return this; + } + + /** + * Configures the HTTP server response headers that will be captured as span attributes. + * + * @param responseHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public RatpackServerTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { + builder.setCapturedResponseHeaders(responseHeaders); + return this; + } + + /** + * Configures the instrumentation to recognize an alternative set of HTTP request methods. + * + *

By default, this instrumentation defines "known" methods as the ones listed in RFC9110 and the PATCH + * method defined in RFC5789. + * + *

Note: calling this method overrides the default known method sets completely; it does + * not supplement it. + * + * @param knownMethods A set of recognized HTTP request methods. + * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) + */ + @Override + @CanIgnoreReturnValue + public RatpackServerTelemetryBuilder setKnownMethods(Set knownMethods) { + builder.setKnownMethods(knownMethods); + return this; + } + + /** Sets custom server {@link SpanNameExtractor} via transform function. */ + @Override + @CanIgnoreReturnValue + public RatpackServerTelemetryBuilder setSpanNameExtractor( + Function, SpanNameExtractor> serverSpanNameExtractor) { + builder.setSpanNameExtractor(serverSpanNameExtractor); + return this; + } + + @Override + public RatpackServerTelemetryBuilder setStatusExtractor( + Function, SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + + /** + * Can be used via the unstable method {@link + * Experimental#setEmitExperimentalTelemetry(RatpackServerTelemetryBuilder, boolean)}. + */ + void setEmitExperimentalHttpServerMetrics(boolean emitExperimentalHttpServerMetrics) { + builder.setEmitExperimentalHttpServerMetrics(emitExperimentalHttpServerMetrics); + } + + /** Returns a new {@link RatpackServerTelemetry} with the configuration of this builder. */ + @Override + public RatpackServerTelemetry build() { + return new RatpackServerTelemetry(builder.build()); + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackTelemetry.java b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackTelemetry.java index 95ea733c4fe7..f3ff0a4d82c0 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackTelemetry.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackTelemetry.java @@ -46,17 +46,30 @@ * .build()); * HttpClient instrumentedHttpClient = telemetry.instrumentHttpClient(httpClient); * } + * + * @deprecated Use {@link RatpackClientTelemetry} and {@link RatpackServerTelemetry} instead. */ +@Deprecated public final class RatpackTelemetry { - /** Returns a new {@link RatpackTelemetry} configured with the given {@link OpenTelemetry}. */ + /** + * Returns a new {@link RatpackTelemetry} configured with the given {@link OpenTelemetry}. + * + * @deprecated Use {@link RatpackClientTelemetry#create(OpenTelemetry)} and {@link + * RatpackServerTelemetry#create(OpenTelemetry)} instead. + */ + @Deprecated public static RatpackTelemetry create(OpenTelemetry openTelemetry) { return builder(openTelemetry).build(); } /** * Returns a new {@link RatpackTelemetryBuilder} configured with the given {@link OpenTelemetry}. + * + * @deprecated Use {@link RatpackClientTelemetry#builder(OpenTelemetry)} and {@link + * RatpackServerTelemetry#builder(OpenTelemetry)} instead. */ + @Deprecated public static RatpackTelemetryBuilder builder(OpenTelemetry openTelemetry) { return new RatpackTelemetryBuilder(openTelemetry); } @@ -71,29 +84,54 @@ public static RatpackTelemetryBuilder builder(OpenTelemetry openTelemetry) { httpClientInstrumenter = new OpenTelemetryHttpClient(clientInstrumenter); } - /** Returns instance of {@link OpenTelemetryServerHandler} to support Ratpack Registry binding. */ + /** + * Returns instance of {@link OpenTelemetryServerHandler} to support Ratpack Registry binding. + * + * @deprecated Use {@link RatpackServerTelemetry#getHandler()} instead. + */ + @Deprecated public OpenTelemetryServerHandler getOpenTelemetryServerHandler() { return serverHandler; } - /** Returns instance of {@link ExecInterceptor} to support Ratpack Registry binding. */ + /** + * Returns instance of {@link ExecInterceptor} to support Ratpack Registry binding. + * + * @deprecated Use {@link RatpackServerTelemetry#getExecInterceptor()} instead. + */ + @Deprecated public ExecInterceptor getOpenTelemetryExecInterceptor() { return OpenTelemetryExecInterceptor.INSTANCE; } - /** Returns instance of {@link ExecInitializer} to support Ratpack Registry binding. */ + /** + * Returns instance of {@link ExecInitializer} to support Ratpack Registry binding. + * + * @deprecated Use {@link RatpackServerTelemetry#getExecInitializer()} instead. + */ + @Deprecated public ExecInitializer getOpenTelemetryExecInitializer() { return OpenTelemetryExecInitializer.INSTANCE; } - /** Configures the {@link RegistrySpec} with OpenTelemetry. */ + /** + * Configures the {@link RegistrySpec} with OpenTelemetry. + * + * @deprecated Use {@link RatpackServerTelemetry#configureRegistry(RegistrySpec)} instead. + */ + @Deprecated public void configureServerRegistry(RegistrySpec registry) { registry.add(HandlerDecorator.prepend(serverHandler)); registry.add(OpenTelemetryExecInterceptor.INSTANCE); registry.add(OpenTelemetryExecInitializer.INSTANCE); } - /** Returns instrumented instance of {@link HttpClient} with OpenTelemetry. */ + /** + * Returns instrumented instance of {@link HttpClient} with OpenTelemetry. + * + * @deprecated Use {@link RatpackClientTelemetry#instrument(HttpClient)} instead. + */ + @Deprecated public HttpClient instrumentHttpClient(HttpClient httpClient) throws Exception { return httpClientInstrumenter.instrument(httpClient); } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackTelemetryBuilder.java b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackTelemetryBuilder.java index 1192a8d8d936..643b386b3846 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackTelemetryBuilder.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackTelemetryBuilder.java @@ -13,6 +13,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.ratpack.v1_7.internal.Experimental; import io.opentelemetry.instrumentation.ratpack.v1_7.internal.RatpackClientInstrumenterBuilderFactory; import io.opentelemetry.instrumentation.ratpack.v1_7.internal.RatpackServerInstrumenterBuilderFactory; import java.util.List; @@ -23,7 +24,13 @@ import ratpack.http.client.HttpResponse; import ratpack.http.client.RequestSpec; -/** A builder for {@link RatpackTelemetry}. */ +/** + * A builder for {@link RatpackTelemetry}. + * + * @deprecated Use {@link RatpackClientTelemetryBuilder} and {@link RatpackServerTelemetryBuilder} + * instead. + */ +@Deprecated public final class RatpackTelemetryBuilder { private static final String INSTRUMENTATION_NAME = "io.opentelemetry.ratpack-1.7"; @@ -41,7 +48,11 @@ public final class RatpackTelemetryBuilder { /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. The {@link AttributesExtractor} will be executed after all default extractors. + * + * @deprecated Use {@link + * RatpackServerTelemetryBuilder#addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { @@ -49,10 +60,15 @@ public RatpackTelemetryBuilder addAttributeExtractor( return this; } + /** + * @deprecated Use {@link + * RatpackClientTelemetryBuilder#addAttributesExtractor(AttributesExtractor)} instead. + */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder addClientAttributeExtractor( AttributesExtractor attributesExtractor) { - clientBuilder.addAttributeExtractor(attributesExtractor); + clientBuilder.addAttributesExtractor(attributesExtractor); return this; } @@ -60,7 +76,9 @@ public RatpackTelemetryBuilder addClientAttributeExtractor( * Configures the HTTP server request headers that will be captured as span attributes. * * @param requestHeaders A list of HTTP header names. + * @deprecated Use {@link RatpackServerTelemetryBuilder#setCapturedRequestHeaders(List)} instead. */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder setCapturedServerRequestHeaders(List requestHeaders) { serverBuilder.setCapturedRequestHeaders(requestHeaders); @@ -71,7 +89,9 @@ public RatpackTelemetryBuilder setCapturedServerRequestHeaders(List requ * Configures the HTTP server response headers that will be captured as span attributes. * * @param responseHeaders A list of HTTP header names. + * @deprecated Use {@link RatpackServerTelemetryBuilder#setCapturedResponseHeaders(List)} instead. */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder setCapturedServerResponseHeaders(List responseHeaders) { serverBuilder.setCapturedResponseHeaders(responseHeaders); @@ -82,7 +102,9 @@ public RatpackTelemetryBuilder setCapturedServerResponseHeaders(List res * Configures the HTTP client request headers that will be captured as span attributes. * * @param requestHeaders A list of HTTP header names. + * @deprecated Use {@link RatpackClientTelemetryBuilder#setCapturedRequestHeaders(List)} instead. */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder setCapturedClientRequestHeaders(List requestHeaders) { clientBuilder.setCapturedRequestHeaders(requestHeaders); @@ -93,7 +115,9 @@ public RatpackTelemetryBuilder setCapturedClientRequestHeaders(List requ * Configures the HTTP client response headers that will be captured as span attributes. * * @param responseHeaders A list of HTTP header names. + * @deprecated Use {@link RatpackClientTelemetryBuilder#setCapturedResponseHeaders(List)} instead. */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder setCapturedClientResponseHeaders(List responseHeaders) { clientBuilder.setCapturedResponseHeaders(responseHeaders); @@ -113,7 +137,10 @@ public RatpackTelemetryBuilder setCapturedClientResponseHeaders(List res * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) + * @deprecated Use {@link RatpackServerTelemetryBuilder#setKnownMethods(Set)} and {@link + * RatpackClientTelemetryBuilder#setKnownMethods(Set)} instead. */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder setKnownMethods(Set knownMethods) { clientBuilder.setKnownMethods(knownMethods); @@ -126,7 +153,10 @@ public RatpackTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(RatpackClientTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder setEmitExperimentalHttpClientMetrics( boolean emitExperimentalHttpClientMetrics) { @@ -139,7 +169,10 @@ public RatpackTelemetryBuilder setEmitExperimentalHttpClientMetrics( * * @param emitExperimentalHttpServerMetrics {@code true} if the experimental HTTP server metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(RatpackServerTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder setEmitExperimentalHttpServerMetrics( boolean emitExperimentalHttpServerMetrics) { @@ -147,27 +180,40 @@ public RatpackTelemetryBuilder setEmitExperimentalHttpServerMetrics( return this; } - /** Sets custom client {@link SpanNameExtractor} via transform function. */ + /** + * Sets custom client {@link SpanNameExtractor} via transform function. + * + * @deprecated Use {@link RatpackClientTelemetryBuilder#setSpanNameExtractor(Function)} instead. + */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder setClientSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> clientSpanNameExtractor) { clientBuilder.setSpanNameExtractor(clientSpanNameExtractor); return this; } - /** Sets custom server {@link SpanNameExtractor} via transform function. */ + /** + * Sets custom server {@link SpanNameExtractor} via transform function. + * + * @deprecated Use {@link RatpackServerTelemetryBuilder#setSpanNameExtractor(Function)} instead. + */ + @Deprecated @CanIgnoreReturnValue public RatpackTelemetryBuilder setServerSpanNameExtractor( - Function, ? extends SpanNameExtractor> - serverSpanNameExtractor) { + Function, SpanNameExtractor> serverSpanNameExtractor) { serverBuilder.setSpanNameExtractor(serverSpanNameExtractor); return this; } - /** Returns a new {@link RatpackTelemetry} with the configuration of this builder. */ + /** + * Returns a new {@link RatpackTelemetry} with the configuration of this builder. + * + * @deprecated Use {@link RatpackClientTelemetryBuilder#build()} and {@link + * RatpackServerTelemetryBuilder#build()} instead. + */ + @Deprecated public RatpackTelemetry build() { return new RatpackTelemetry(serverBuilder.build(), clientBuilder.build()); } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/internal/Experimental.java b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/internal/Experimental.java new file mode 100644 index 000000000000..f7ad2b2e2746 --- /dev/null +++ b/instrumentation/ratpack/ratpack-1.7/library/src/main/java/io/opentelemetry/instrumentation/ratpack/v1_7/internal/Experimental.java @@ -0,0 +1,85 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.ratpack.v1_7.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackClientTelemetryBuilder; +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalClientTelemetryMethod = + getEmitExperimentalClientTelemetryMethod(); + + @Nullable + private static final Method emitExperimentalServerTelemetryMethod = + getEmitExperimentalServerTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + RatpackClientTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalClientTelemetryMethod != null) { + try { + emitExperimentalClientTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + public void setEmitExperimentalTelemetry( + RatpackServerTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalServerTelemetryMethod != null) { + try { + emitExperimentalServerTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalClientTelemetryMethod() { + try { + Method method = + RatpackClientTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } + + @Nullable + private static Method getEmitExperimentalServerTelemetryMethod() { + try { + Method method = + RatpackServerTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpServerMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.groovy index 7a6de6f3d980..943ddd84adec 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.groovy +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/client/InstrumentedHttpClientTest.groovy @@ -11,7 +11,8 @@ import io.opentelemetry.api.trace.Tracer import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator import io.opentelemetry.context.Context import io.opentelemetry.context.propagation.ContextPropagators -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackTelemetry +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackClientTelemetry +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry import io.opentelemetry.sdk.OpenTelemetrySdk import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter import io.opentelemetry.sdk.trace.SdkTracerProvider @@ -34,9 +35,7 @@ import java.util.concurrent.TimeUnit import static io.opentelemetry.api.trace.SpanKind.CLIENT import static io.opentelemetry.api.trace.SpanKind.SERVER -import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD -import static io.opentelemetry.semconv.HttpAttributes.HTTP_ROUTE -import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE +import static io.opentelemetry.semconv.HttpAttributes.* class InstrumentedHttpClientTest extends Specification { @@ -49,7 +48,8 @@ class InstrumentedHttpClientTest extends Specification { .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .setTracerProvider(tracerProvider).build() - RatpackTelemetry telemetry = RatpackTelemetry.create(openTelemetry) + RatpackClientTelemetry telemetry = RatpackClientTelemetry.create(openTelemetry) + RatpackServerTelemetry serverTelemetry = RatpackServerTelemetry.create(openTelemetry) def cleanup() { spanExporter.reset() @@ -60,7 +60,8 @@ class InstrumentedHttpClientTest extends Specification { def otherApp = EmbeddedApp.of { spec -> spec.registry( Guice.registry { bindings -> - telemetry.configureServerRegistry(bindings) + serverTelemetry.configureRegistry(bindings) + telemetry.configureRegistry(bindings) } ) spec.handlers { @@ -71,8 +72,9 @@ class InstrumentedHttpClientTest extends Specification { def app = EmbeddedApp.of { spec -> spec.registry( Guice.registry { bindings -> - telemetry.configureServerRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrumentHttpClient(HttpClient.of(Action.noop()))) + serverTelemetry.configureRegistry(bindings) + telemetry.configureRegistry(bindings) + bindings.bindInstance(HttpClient, telemetry.instrument(HttpClient.of(Action.noop()))) } ) @@ -132,8 +134,9 @@ class InstrumentedHttpClientTest extends Specification { def app = EmbeddedApp.of { spec -> spec.registry( Guice.registry { bindings -> - telemetry.configureServerRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrumentHttpClient(HttpClient.of(Action.noop()))) + serverTelemetry.configureRegistry(bindings) + telemetry.configureRegistry(bindings) + bindings.bindInstance(HttpClient, telemetry.instrument(HttpClient.of(Action.noop()))) } ) @@ -197,8 +200,9 @@ class InstrumentedHttpClientTest extends Specification { def app = EmbeddedApp.of { spec -> spec.registry( Guice.registry { bindings -> - telemetry.configureServerRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrumentHttpClient( + serverTelemetry.configureRegistry(bindings) + telemetry.configureRegistry(bindings) + bindings.bindInstance(HttpClient, telemetry.instrument( HttpClient.of { s -> s.readTimeout(Duration.ofMillis(10)) }) ) } @@ -254,8 +258,9 @@ class InstrumentedHttpClientTest extends Specification { def app = EmbeddedApp.of { spec -> spec.registry( Guice.registry { bindings -> - telemetry.configureServerRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrumentHttpClient(HttpClient.of(Action.noop()))) + serverTelemetry.configureRegistry(bindings) + telemetry.configureRegistry(bindings) + bindings.bindInstance(HttpClient, telemetry.instrument(HttpClient.of(Action.noop()))) bindings.bindInstance(new BarService(latch, "${otherApp.address}foo", openTelemetry)) }, ) @@ -287,8 +292,9 @@ class InstrumentedHttpClientTest extends Specification { def app = EmbeddedApp.of { spec -> spec.registry( Guice.registry { bindings -> - telemetry.configureServerRegistry(bindings) - bindings.bindInstance(HttpClient, telemetry.instrumentHttpClient(HttpClient.of(Action.noop()))) + serverTelemetry.configureRegistry(bindings) + telemetry.configureRegistry(bindings) + bindings.bindInstance(HttpClient, telemetry.instrument(HttpClient.of(Action.noop()))) bindings.bindInstance(new BarForkService(latch, "${otherApp.address}foo", openTelemetry)) }, ) @@ -341,7 +347,6 @@ class BarService implements Service { } } - class BarForkService implements Service { private final String url private final CountDownLatch latch diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackAsyncHttpServerTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackAsyncHttpServerTest.groovy index c391c85a5ec3..cc18bc735592 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackAsyncHttpServerTest.groovy +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackAsyncHttpServerTest.groovy @@ -6,7 +6,7 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.server import io.opentelemetry.instrumentation.ratpack.server.AbstractRatpackAsyncHttpServerTest -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackTelemetry +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry import io.opentelemetry.instrumentation.test.LibraryTestTrait import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint @@ -15,12 +15,12 @@ import ratpack.server.RatpackServerSpec class RatpackAsyncHttpServerTest extends AbstractRatpackAsyncHttpServerTest implements LibraryTestTrait { @Override void configure(RatpackServerSpec serverSpec) { - RatpackTelemetry telemetry = RatpackTelemetry.builder(openTelemetry) - .setCapturedServerRequestHeaders([AbstractHttpServerTest.TEST_REQUEST_HEADER]) - .setCapturedServerResponseHeaders([AbstractHttpServerTest.TEST_RESPONSE_HEADER]) + RatpackServerTelemetry telemetry = RatpackServerTelemetry.builder(openTelemetry) + .setCapturedRequestHeaders([AbstractHttpServerTest.TEST_REQUEST_HEADER]) + .setCapturedResponseHeaders([AbstractHttpServerTest.TEST_RESPONSE_HEADER]) .build() serverSpec.registryOf { - telemetry.configureServerRegistry(it) + telemetry.configureRegistry(it) } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackForkedHttpServerTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackForkedHttpServerTest.groovy index a5e5657074d3..1cf178ecec20 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackForkedHttpServerTest.groovy +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackForkedHttpServerTest.groovy @@ -6,7 +6,7 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.server import io.opentelemetry.instrumentation.ratpack.server.AbstractRatpackForkedHttpServerTest -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackTelemetry +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry import io.opentelemetry.instrumentation.test.LibraryTestTrait import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint @@ -15,12 +15,12 @@ import ratpack.server.RatpackServerSpec class RatpackForkedHttpServerTest extends AbstractRatpackForkedHttpServerTest implements LibraryTestTrait { @Override void configure(RatpackServerSpec serverSpec) { - RatpackTelemetry telemetry = RatpackTelemetry.builder(openTelemetry) - .setCapturedServerRequestHeaders([AbstractHttpServerTest.TEST_REQUEST_HEADER]) - .setCapturedServerResponseHeaders([AbstractHttpServerTest.TEST_RESPONSE_HEADER]) + RatpackServerTelemetry telemetry = RatpackServerTelemetry.builder(openTelemetry) + .setCapturedRequestHeaders([AbstractHttpServerTest.TEST_REQUEST_HEADER]) + .setCapturedResponseHeaders([AbstractHttpServerTest.TEST_RESPONSE_HEADER]) .build() serverSpec.registryOf { - telemetry.configureServerRegistry(it) + telemetry.configureRegistry(it) } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackHttpServerTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackHttpServerTest.groovy index 72f1a0f43189..7e07e86c9a8a 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackHttpServerTest.groovy +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackHttpServerTest.groovy @@ -6,7 +6,7 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.server import io.opentelemetry.instrumentation.ratpack.server.AbstractRatpackHttpServerTest -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackTelemetry +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry import io.opentelemetry.instrumentation.test.LibraryTestTrait import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint @@ -15,12 +15,12 @@ import ratpack.server.RatpackServerSpec class RatpackHttpServerTest extends AbstractRatpackHttpServerTest implements LibraryTestTrait { @Override void configure(RatpackServerSpec serverSpec) { - RatpackTelemetry telemetry = RatpackTelemetry.builder(openTelemetry) - .setCapturedServerRequestHeaders([AbstractHttpServerTest.TEST_REQUEST_HEADER]) - .setCapturedServerResponseHeaders([AbstractHttpServerTest.TEST_RESPONSE_HEADER]) + RatpackServerTelemetry telemetry = RatpackServerTelemetry.builder(openTelemetry) + .setCapturedRequestHeaders([AbstractHttpServerTest.TEST_REQUEST_HEADER]) + .setCapturedResponseHeaders([AbstractHttpServerTest.TEST_RESPONSE_HEADER]) .build() serverSpec.registryOf { - telemetry.configureServerRegistry(it) + telemetry.configureRegistry(it) } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackRoutesTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackRoutesTest.groovy index 0d5004b71050..d4c3677f499a 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackRoutesTest.groovy +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackRoutesTest.groovy @@ -6,16 +6,16 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.server import io.opentelemetry.instrumentation.ratpack.server.AbstractRatpackRoutesTest -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackTelemetry +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry import io.opentelemetry.instrumentation.test.LibraryTestTrait import ratpack.server.RatpackServerSpec class RatpackRoutesTest extends AbstractRatpackRoutesTest implements LibraryTestTrait { @Override void configure(RatpackServerSpec serverSpec) { - RatpackTelemetry telemetry = RatpackTelemetry.create(openTelemetry) + RatpackServerTelemetry telemetry = RatpackServerTelemetry.create(openTelemetry) serverSpec.registryOf { - telemetry.configureServerRegistry(it) + telemetry.configureRegistry(it) } } diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.groovy index 3e0ed088f401..d2ca21755a9c 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.groovy +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerApplicationTest.groovy @@ -10,9 +10,9 @@ import com.google.inject.Provides import groovy.transform.CompileStatic import io.opentelemetry.api.OpenTelemetry import io.opentelemetry.api.trace.SpanKind -import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryServerHandler +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackClientTelemetry import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackFunctionalTest -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackTelemetry +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry import io.opentelemetry.sdk.OpenTelemetrySdk import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter import io.opentelemetry.sdk.trace.SdkTracerProvider @@ -21,6 +21,7 @@ import io.opentelemetry.sdk.trace.export.SpanExporter import ratpack.exec.ExecInitializer import ratpack.exec.ExecInterceptor import ratpack.guice.Guice +import ratpack.handling.Handler import ratpack.http.client.HttpClient import ratpack.server.RatpackServer import spock.lang.Specification @@ -28,9 +29,7 @@ import spock.util.concurrent.PollingConditions import javax.inject.Singleton -import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD -import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE -import static io.opentelemetry.semconv.HttpAttributes.HTTP_ROUTE +import static io.opentelemetry.semconv.HttpAttributes.* import static io.opentelemetry.semconv.UrlAttributes.URL_PATH class RatpackServerApplicationTest extends Specification { @@ -104,20 +103,26 @@ class OpenTelemetryModule extends AbstractModule { @Singleton @Provides - RatpackTelemetry ratpackTracing(OpenTelemetry openTelemetry) { - return RatpackTelemetry.create(openTelemetry) + RatpackClientTelemetry ratpackClientTelemetry(OpenTelemetry openTelemetry) { + return RatpackClientTelemetry.create(openTelemetry) } @Singleton @Provides - OpenTelemetryServerHandler ratpackServerHandler(RatpackTelemetry ratpackTracing) { - return ratpackTracing.getOpenTelemetryServerHandler() + RatpackServerTelemetry ratpackServerTelemetry(OpenTelemetry openTelemetry) { + return RatpackServerTelemetry.create(openTelemetry) } @Singleton @Provides - ExecInterceptor ratpackExecInterceptor(RatpackTelemetry ratpackTracing) { - return ratpackTracing.getOpenTelemetryExecInterceptor() + Handler ratpackServerHandler(RatpackServerTelemetry ratpackTracing) { + return ratpackTracing.getHandler() + } + + @Singleton + @Provides + ExecInterceptor ratpackExecInterceptor(RatpackServerTelemetry ratpackTracing) { + return ratpackTracing.getExecInterceptor() } @Provides @@ -131,14 +136,14 @@ class OpenTelemetryModule extends AbstractModule { @Singleton @Provides - HttpClient instrumentedHttpClient(RatpackTelemetry ratpackTracing) { - return ratpackTracing.instrumentHttpClient(HttpClient.of {}) + HttpClient instrumentedHttpClient(RatpackClientTelemetry ratpackTracing) { + return ratpackTracing.instrument(HttpClient.of {}) } @Singleton @Provides - ExecInitializer ratpackExecInitializer(RatpackTelemetry ratpackTracing) { - return ratpackTracing.getOpenTelemetryExecInitializer() + ExecInitializer ratpackExecInitializer(RatpackServerTelemetry ratpackTracing) { + return ratpackTracing.getExecInitializer() } } @@ -152,7 +157,7 @@ class RatpackApp { .handlers { chain -> chain .get("ignore") { ctx -> ctx.render("ignored") } - .all(OpenTelemetryServerHandler) + .all(Handler) .get("foo") { ctx -> ctx.render("hi-foo") } .get("bar") { ctx -> ctx.get(HttpClient).get(ctx.get(URI)) diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy index f04d97f458ee..19cb6d22e5ac 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/groovy/io/opentelemetry/instrumentation/ratpack/v1_7/server/RatpackServerTest.groovy @@ -8,7 +8,7 @@ package io.opentelemetry.instrumentation.ratpack.v1_7.server import io.opentelemetry.api.trace.SpanKind import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator import io.opentelemetry.context.propagation.ContextPropagators -import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackTelemetry +import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackServerTelemetry import io.opentelemetry.sdk.OpenTelemetrySdk import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter import io.opentelemetry.sdk.trace.SdkTracerProvider @@ -32,7 +32,7 @@ class RatpackServerTest extends Specification { .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .setTracerProvider(tracerProvider).build() - def telemetry = RatpackTelemetry.create(openTelemetry) + def telemetry = RatpackServerTelemetry.create(openTelemetry) def cleanup() { spanExporter.reset() @@ -41,7 +41,7 @@ class RatpackServerTest extends Specification { def "add span on handlers"() { given: def app = EmbeddedApp.of { spec -> - spec.registry { Registry.of { telemetry.configureServerRegistry(it) } } + spec.registry { Registry.of { telemetry.configureRegistry(it) } } spec.handlers { chain -> chain.get("foo") { ctx -> ctx.render("hi-foo") } } @@ -67,7 +67,7 @@ class RatpackServerTest extends Specification { def "propagate trace with instrumented async operations"() { expect: def app = EmbeddedApp.of { spec -> - spec.registry { Registry.of { telemetry.configureServerRegistry(it) } } + spec.registry { Registry.of { telemetry.configureRegistry(it) } } spec.handlers { chain -> chain.get("foo") { ctx -> ctx.render("hi-foo") @@ -106,7 +106,7 @@ class RatpackServerTest extends Specification { def "propagate trace with instrumented async concurrent operations"() { expect: def app = EmbeddedApp.of { spec -> - spec.registry { Registry.of { telemetry.configureServerRegistry(it) } } + spec.registry { Registry.of { telemetry.configureRegistry(it) } } spec.handlers { chain -> chain.get("bar") { ctx -> ctx.render("hi-bar") diff --git a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackHttpClientTest.java b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackHttpClientTest.java index 49ceb3e976e2..b993de02489b 100644 --- a/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackHttpClientTest.java +++ b/instrumentation/ratpack/ratpack-1.7/library/src/test/java/io/opentelemetry/instrumentation/ratpack/v1_7/RatpackHttpClientTest.java @@ -21,18 +21,18 @@ class RatpackHttpClientTest extends AbstractRatpackHttpClientTest { @Override protected HttpClient buildHttpClient() throws Exception { - return RatpackTelemetry.builder(testing.getOpenTelemetry()) - .setCapturedClientRequestHeaders( + return RatpackClientTelemetry.builder(testing.getOpenTelemetry()) + .setCapturedRequestHeaders( Collections.singletonList(AbstractHttpClientTest.TEST_REQUEST_HEADER)) - .setCapturedClientResponseHeaders( + .setCapturedResponseHeaders( Collections.singletonList(AbstractHttpClientTest.TEST_RESPONSE_HEADER)) .build() - .instrumentHttpClient(HttpClient.of(Action.noop())); + .instrument(HttpClient.of(Action.noop())); } @Override protected HttpClient buildHttpClient(Action action) throws Exception { - return RatpackTelemetry.create(testing.getOpenTelemetry()) - .instrumentHttpClient(HttpClient.of(action)); + return RatpackClientTelemetry.create(testing.getOpenTelemetry()) + .instrument(HttpClient.of(action)); } } diff --git a/instrumentation/restlet/restlet-1.1/library/src/main/java/io/opentelemetry/instrumentation/restlet/v1_1/RestletTelemetryBuilder.java b/instrumentation/restlet/restlet-1.1/library/src/main/java/io/opentelemetry/instrumentation/restlet/v1_1/RestletTelemetryBuilder.java index 3ff61af4a73f..9775cdaef09d 100644 --- a/instrumentation/restlet/restlet-1.1/library/src/main/java/io/opentelemetry/instrumentation/restlet/v1_1/RestletTelemetryBuilder.java +++ b/instrumentation/restlet/restlet-1.1/library/src/main/java/io/opentelemetry/instrumentation/restlet/v1_1/RestletTelemetryBuilder.java @@ -10,7 +10,10 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder; +import io.opentelemetry.instrumentation.restlet.v1_1.internal.Experimental; import io.opentelemetry.instrumentation.restlet.v1_1.internal.RestletTelemetryBuilderFactory; import java.util.List; import java.util.Set; @@ -19,7 +22,8 @@ import org.restlet.data.Response; /** A builder of {@link RestletTelemetry}. */ -public final class RestletTelemetryBuilder { +public final class RestletTelemetryBuilder + implements HttpServerTelemetryBuilder { private final DefaultHttpServerInstrumenterBuilder builder; @@ -31,6 +35,7 @@ public final class RestletTelemetryBuilder { * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder addAttributesExtractor( AttributesExtractor attributesExtractor) { @@ -43,6 +48,7 @@ public RestletTelemetryBuilder addAttributesExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -54,6 +60,7 @@ public RestletTelemetryBuilder setCapturedRequestHeaders(List requestHea * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -73,6 +80,7 @@ public RestletTelemetryBuilder setCapturedResponseHeaders(List responseH * @param knownMethods A set of recognized HTTP request methods. * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -84,7 +92,10 @@ public RestletTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpServerMetrics {@code true} if the experimental HTTP server metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(RestletTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public RestletTelemetryBuilder setEmitExperimentalHttpServerMetrics( boolean emitExperimentalHttpServerMetrics) { @@ -93,18 +104,28 @@ public RestletTelemetryBuilder setEmitExperimentalHttpServerMetrics( } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder setSpanNameExtractor( - Function, ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; } + @Override + public RestletTelemetryBuilder setStatusExtractor( + Function, SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Returns a new {@link RestletTelemetry} with the settings of this {@link * RestletTelemetryBuilder}. */ + @Override public RestletTelemetry build() { return new RestletTelemetry(builder.build()); } diff --git a/instrumentation/restlet/restlet-1.1/library/src/main/java/io/opentelemetry/instrumentation/restlet/v1_1/internal/Experimental.java b/instrumentation/restlet/restlet-1.1/library/src/main/java/io/opentelemetry/instrumentation/restlet/v1_1/internal/Experimental.java new file mode 100644 index 000000000000..30558c835ce1 --- /dev/null +++ b/instrumentation/restlet/restlet-1.1/library/src/main/java/io/opentelemetry/instrumentation/restlet/v1_1/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.restlet.v1_1.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.restlet.v1_1.RestletTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + RestletTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + RestletTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpServerMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/restlet/restlet-2.0/library/src/main/java/io/opentelemetry/instrumentation/restlet/v2_0/RestletTelemetryBuilder.java b/instrumentation/restlet/restlet-2.0/library/src/main/java/io/opentelemetry/instrumentation/restlet/v2_0/RestletTelemetryBuilder.java index a933f52cdea4..ddac6a86ecbd 100644 --- a/instrumentation/restlet/restlet-2.0/library/src/main/java/io/opentelemetry/instrumentation/restlet/v2_0/RestletTelemetryBuilder.java +++ b/instrumentation/restlet/restlet-2.0/library/src/main/java/io/opentelemetry/instrumentation/restlet/v2_0/RestletTelemetryBuilder.java @@ -10,7 +10,10 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder; +import io.opentelemetry.instrumentation.restlet.v2_0.internal.Experimental; import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletTelemetryBuilderFactory; import java.util.List; import java.util.Set; @@ -19,7 +22,8 @@ import org.restlet.Response; /** A builder of {@link RestletTelemetry}. */ -public final class RestletTelemetryBuilder { +public final class RestletTelemetryBuilder + implements HttpServerTelemetryBuilder { private final DefaultHttpServerInstrumenterBuilder builder; @@ -31,6 +35,7 @@ public final class RestletTelemetryBuilder { * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder addAttributesExtractor( AttributesExtractor attributesExtractor) { @@ -43,6 +48,7 @@ public RestletTelemetryBuilder addAttributesExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -54,6 +60,7 @@ public RestletTelemetryBuilder setCapturedRequestHeaders(List requestHea * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -73,6 +80,7 @@ public RestletTelemetryBuilder setCapturedResponseHeaders(List responseH * @param knownMethods A set of recognized HTTP request methods. * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -84,7 +92,10 @@ public RestletTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpServerMetrics {@code true} if the experimental HTTP server metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(RestletTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public RestletTelemetryBuilder setEmitExperimentalHttpServerMetrics( boolean emitExperimentalHttpServerMetrics) { @@ -93,18 +104,28 @@ public RestletTelemetryBuilder setEmitExperimentalHttpServerMetrics( } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public RestletTelemetryBuilder setSpanNameExtractor( - Function, ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; } + @Override + public RestletTelemetryBuilder setStatusExtractor( + Function, SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Returns a new {@link RestletTelemetry} with the settings of this {@link * RestletTelemetryBuilder}. */ + @Override public RestletTelemetry build() { return new RestletTelemetry(builder.build()); } diff --git a/instrumentation/restlet/restlet-2.0/library/src/main/java/io/opentelemetry/instrumentation/restlet/v2_0/internal/Experimental.java b/instrumentation/restlet/restlet-2.0/library/src/main/java/io/opentelemetry/instrumentation/restlet/v2_0/internal/Experimental.java new file mode 100644 index 000000000000..80445408e328 --- /dev/null +++ b/instrumentation/restlet/restlet-2.0/library/src/main/java/io/opentelemetry/instrumentation/restlet/v2_0/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.restlet.v2_0.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.restlet.v2_0.RestletTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + RestletTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + RestletTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpServerMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/SpringWebfluxInstrumentationAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/SpringWebfluxInstrumentationAutoConfiguration.java index bdf00acf732b..76288e4952df 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/SpringWebfluxInstrumentationAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/SpringWebfluxInstrumentationAutoConfiguration.java @@ -40,7 +40,7 @@ static WebClientBeanPostProcessor otelWebClientBeanPostProcessor( @Bean WebFilter telemetryFilter(OpenTelemetry openTelemetry, ConfigProperties config) { - return WebClientBeanPostProcessor.getWebfluxTelemetry(openTelemetry, config) + return WebClientBeanPostProcessor.getWebfluxServerTelemetry(openTelemetry, config) .createWebFilterAndRegisterReactorHook(); } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/WebClientBeanPostProcessor.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/WebClientBeanPostProcessor.java index 90dde820c4a9..22d06fe358c3 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/WebClientBeanPostProcessor.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/WebClientBeanPostProcessor.java @@ -7,7 +7,8 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.InstrumentationConfigUtil; -import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxTelemetry; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxClientTelemetry; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxServerTelemetry; import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.SpringWebfluxBuilderUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import org.springframework.beans.factory.ObjectProvider; @@ -31,12 +32,20 @@ final class WebClientBeanPostProcessor implements BeanPostProcessor { this.configPropertiesProvider = configPropertiesProvider; } - static SpringWebfluxTelemetry getWebfluxTelemetry( + static SpringWebfluxClientTelemetry getWebfluxClientTelemetry( OpenTelemetry openTelemetry, ConfigProperties config) { - return InstrumentationConfigUtil.configureClientAndServerBuilder( + return InstrumentationConfigUtil.configureClientBuilder( config, - SpringWebfluxTelemetry.builder(openTelemetry), - SpringWebfluxBuilderUtil.getClientBuilderExtractor(), + SpringWebfluxClientTelemetry.builder(openTelemetry), + SpringWebfluxBuilderUtil.getClientBuilderExtractor()) + .build(); + } + + static SpringWebfluxServerTelemetry getWebfluxServerTelemetry( + OpenTelemetry openTelemetry, ConfigProperties config) { + return InstrumentationConfigUtil.configureServerBuilder( + config, + SpringWebfluxServerTelemetry.builder(openTelemetry), SpringWebfluxBuilderUtil.getServerBuilderExtractor()) .build(); } @@ -54,9 +63,9 @@ public Object postProcessAfterInitialization(Object bean, String beanName) { } private WebClient.Builder wrapBuilder(WebClient.Builder webClientBuilder) { - SpringWebfluxTelemetry instrumentation = - getWebfluxTelemetry( + SpringWebfluxClientTelemetry instrumentation = + getWebfluxClientTelemetry( openTelemetryProvider.getObject(), configPropertiesProvider.getObject()); - return webClientBuilder.filters(instrumentation::addClientTracingFilter); + return webClientBuilder.filters(instrumentation::addTracingFilter); } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/InstrumentationConfigUtil.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/InstrumentationConfigUtil.java index 747cf33dcb09..fb5e582bfaa5 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/InstrumentationConfigUtil.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/InstrumentationConfigUtil.java @@ -19,21 +19,6 @@ public final class InstrumentationConfigUtil { private InstrumentationConfigUtil() {} - @CanIgnoreReturnValue - public static - T configureClientAndServerBuilder( - ConfigProperties config, - T builder, - Function> - getClientBuilder, - Function> - getServerBuilder) { - CommonConfig commonConfig = getConfig(config); - getClientBuilder.apply(builder).configure(commonConfig); - getServerBuilder.apply(builder).configure(commonConfig); - return builder; - } - @CanIgnoreReturnValue public static T configureClientBuilder( ConfigProperties config, diff --git a/instrumentation/spring/spring-web/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/web/v3_1/SpringWebTelemetryBuilder.java b/instrumentation/spring/spring-web/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/web/v3_1/SpringWebTelemetryBuilder.java index 86771bfa3313..9bc0b461ff41 100644 --- a/instrumentation/spring/spring-web/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/web/v3_1/SpringWebTelemetryBuilder.java +++ b/instrumentation/spring/spring-web/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/web/v3_1/SpringWebTelemetryBuilder.java @@ -10,7 +10,10 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; +import io.opentelemetry.instrumentation.spring.web.v3_1.internal.Experimental; import io.opentelemetry.instrumentation.spring.web.v3_1.internal.WebTelemetryUtil; import java.util.List; import java.util.Set; @@ -19,7 +22,9 @@ import org.springframework.http.client.ClientHttpResponse; /** A builder of {@link SpringWebTelemetry}. */ -public final class SpringWebTelemetryBuilder { +public final class SpringWebTelemetryBuilder + implements HttpClientTelemetryBuilder { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.spring-web-3.1"; private final DefaultHttpClientInstrumenterBuilder builder; @@ -43,11 +48,26 @@ private DefaultHttpClientInstrumenterBuilder ge /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. + * + * @deprecated Use {@link #addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebTelemetryBuilder addAttributeExtractor( AttributesExtractor attributesExtractor) { - builder.addAttributeExtractor(attributesExtractor); + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. + */ + @Override + @CanIgnoreReturnValue + public SpringWebTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); return this; } @@ -56,6 +76,7 @@ public SpringWebTelemetryBuilder addAttributeExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public SpringWebTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -67,6 +88,7 @@ public SpringWebTelemetryBuilder setCapturedRequestHeaders(List requestH * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public SpringWebTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -74,16 +96,25 @@ public SpringWebTelemetryBuilder setCapturedResponseHeaders(List respons } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public SpringWebTelemetryBuilder setSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractorTransformer) { builder.setSpanNameExtractor(spanNameExtractorTransformer); return this; } + @Override + public SpringWebTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Configures the instrumentation to recognize an alternative set of HTTP request methods. * @@ -97,6 +128,7 @@ public SpringWebTelemetryBuilder setSpanNameExtractor( * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public SpringWebTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -108,7 +140,10 @@ public SpringWebTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(SpringWebTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebTelemetryBuilder setEmitExperimentalHttpClientMetrics( boolean emitExperimentalHttpClientMetrics) { @@ -120,6 +155,7 @@ public SpringWebTelemetryBuilder setEmitExperimentalHttpClientMetrics( * Returns a new {@link SpringWebTelemetry} with the settings of this {@link * SpringWebTelemetryBuilder}. */ + @Override public SpringWebTelemetry build() { return new SpringWebTelemetry(builder.build()); } diff --git a/instrumentation/spring/spring-web/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/web/v3_1/internal/Experimental.java b/instrumentation/spring/spring-web/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/web/v3_1/internal/Experimental.java new file mode 100644 index 000000000000..5b365ba81747 --- /dev/null +++ b/instrumentation/spring/spring-web/spring-web-3.1/library/src/main/java/io/opentelemetry/instrumentation/spring/web/v3_1/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.web.v3_1.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.spring.web.v3_1.SpringWebTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + SpringWebTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + SpringWebTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientTelemetry.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientTelemetry.java new file mode 100644 index 000000000000..94139e19949e --- /dev/null +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientTelemetry.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.webflux.v5_3; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.WebClientTracingFilter; +import java.util.List; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; + +/** Entrypoint for instrumenting Spring Webflux HTTP clients. */ +public final class SpringWebfluxClientTelemetry { + + /** + * Returns a new {@link SpringWebfluxClientTelemetry} configured with the given {@link + * OpenTelemetry}. + */ + public static SpringWebfluxClientTelemetry create(OpenTelemetry openTelemetry) { + return builder(openTelemetry).build(); + } + + /** + * Returns a new {@link SpringWebfluxClientTelemetryBuilder} configured with the given {@link + * OpenTelemetry}. + */ + public static SpringWebfluxClientTelemetryBuilder builder(OpenTelemetry openTelemetry) { + return new SpringWebfluxClientTelemetryBuilder(openTelemetry); + } + + private final Instrumenter clientInstrumenter; + private final ContextPropagators propagators; + + SpringWebfluxClientTelemetry( + Instrumenter clientInstrumenter, + ContextPropagators propagators) { + this.clientInstrumenter = clientInstrumenter; + this.propagators = propagators; + } + + public void addTracingFilter(List exchangeFilterFunctions) { + for (ExchangeFilterFunction filterFunction : exchangeFilterFunctions) { + if (filterFunction instanceof WebClientTracingFilter) { + return; + } + } + exchangeFilterFunctions.add(new WebClientTracingFilter(clientInstrumenter, propagators)); + } +} diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientTelemetryBuilder.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientTelemetryBuilder.java new file mode 100644 index 000000000000..92fd39dc1ca8 --- /dev/null +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientTelemetryBuilder.java @@ -0,0 +1,139 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.webflux.v5_3; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientTelemetryBuilder; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.Experimental; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.SpringWebfluxBuilderUtil; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.WebClientHttpAttributesGetter; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; + +/** A builder of {@link SpringWebfluxClientTelemetry}. */ +public final class SpringWebfluxClientTelemetryBuilder + implements HttpClientTelemetryBuilder { + + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.spring-webflux-5.3"; + + private final DefaultHttpClientInstrumenterBuilder builder; + private final OpenTelemetry openTelemetry; + + static { + SpringWebfluxBuilderUtil.setClientBuilderExtractor(builder -> builder.builder); + } + + SpringWebfluxClientTelemetryBuilder(OpenTelemetry openTelemetry) { + builder = + DefaultHttpClientInstrumenterBuilder.create( + INSTRUMENTATION_NAME, openTelemetry, WebClientHttpAttributesGetter.INSTANCE); + this.openTelemetry = openTelemetry; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items for WebClient. + */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxClientTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Configures the HTTP WebClient request headers that will be captured as span attributes. + * + * @param requestHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxClientTelemetryBuilder setCapturedRequestHeaders( + List requestHeaders) { + builder.setCapturedRequestHeaders(requestHeaders); + return this; + } + + /** + * Configures the HTTP WebClient response headers that will be captured as span attributes. + * + * @param responseHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxClientTelemetryBuilder setCapturedResponseHeaders( + List responseHeaders) { + builder.setCapturedResponseHeaders(responseHeaders); + return this; + } + + /** + * Configures the instrumentation to recognize an alternative set of HTTP request methods. + * + *

By default, this instrumentation defines "known" methods as the ones listed in RFC9110 and the PATCH + * method defined in RFC5789. + * + *

Note: calling this method overrides the default known method sets completely; it does + * not supplement it. + * + * @param knownMethods A set of recognized HTTP request methods. + * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) + */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxClientTelemetryBuilder setKnownMethods(Set knownMethods) { + builder.setKnownMethods(knownMethods); + return this; + } + + /** Sets custom client {@link SpanNameExtractor} via transform function. */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxClientTelemetryBuilder setSpanNameExtractor( + Function, SpanNameExtractor> + clientSpanNameExtractor) { + builder.setSpanNameExtractor(clientSpanNameExtractor); + return this; + } + + @Override + public SpringWebfluxClientTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + + /** + * Can be used via the unstable method {@link + * Experimental#setEmitExperimentalTelemetry(SpringWebfluxClientTelemetryBuilder, boolean)}. + */ + void setEmitExperimentalHttpClientTelemetry(boolean emitExperimentalHttpClientTelemetry) { + builder.setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientTelemetry); + } + + /** + * Returns a new {@link SpringWebfluxClientTelemetry} with the settings of this {@link + * SpringWebfluxClientTelemetryBuilder}. + */ + @Override + public SpringWebfluxClientTelemetry build() { + return new SpringWebfluxClientTelemetry(builder.build(), openTelemetry.getPropagators()); + } +} diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxServerTelemetry.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxServerTelemetry.java new file mode 100644 index 000000000000..f3c1dacca15f --- /dev/null +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxServerTelemetry.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.webflux.v5_3; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.reactor.v3_1.ContextPropagationOperator; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; + +/** Entrypoint for instrumenting Spring Webflux HTTP services. */ +public final class SpringWebfluxServerTelemetry { + + /** + * Returns a new {@link SpringWebfluxServerTelemetry} configured with the given {@link + * OpenTelemetry}. + */ + public static SpringWebfluxServerTelemetry create(OpenTelemetry openTelemetry) { + return builder(openTelemetry).build(); + } + + /** + * Returns a new {@link SpringWebfluxServerTelemetryBuilder} configured with the given {@link + * OpenTelemetry}. + */ + public static SpringWebfluxServerTelemetryBuilder builder(OpenTelemetry openTelemetry) { + return new SpringWebfluxServerTelemetryBuilder(openTelemetry); + } + + // We use ServerWebExchange (which holds both the request and response) + // because we need it to get the HTTP route while instrumenting. + private final Instrumenter serverInstrumenter; + + SpringWebfluxServerTelemetry( + Instrumenter serverInstrumenter) { + this.serverInstrumenter = serverInstrumenter; + } + + public WebFilter createWebFilter() { + return new TelemetryProducingWebFilter(serverInstrumenter); + } + + public WebFilter createWebFilterAndRegisterReactorHook() { + registerReactorHook(); + return this.createWebFilter(); + } + + private static void registerReactorHook() { + ContextPropagationOperator.builder().build().registerOnEachOperator(); + } +} diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxServerTelemetryBuilder.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxServerTelemetryBuilder.java new file mode 100644 index 000000000000..ca09958ea796 --- /dev/null +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxServerTelemetryBuilder.java @@ -0,0 +1,140 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.webflux.v5_3; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.Experimental; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.SpringWebfluxBuilderUtil; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import org.springframework.web.server.ServerWebExchange; + +/** A builder of {@link SpringWebfluxServerTelemetry}. */ +public final class SpringWebfluxServerTelemetryBuilder + implements HttpServerTelemetryBuilder { + + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.spring-webflux-5.3"; + + private final DefaultHttpServerInstrumenterBuilder builder; + + static { + SpringWebfluxBuilderUtil.setServerBuilderExtractor(builder -> builder.builder); + } + + SpringWebfluxServerTelemetryBuilder(OpenTelemetry openTelemetry) { + builder = + DefaultHttpServerInstrumenterBuilder.create( + INSTRUMENTATION_NAME, + openTelemetry, + WebfluxServerHttpAttributesGetter.INSTANCE, + WebfluxTextMapGetter.INSTANCE); + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. + */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxServerTelemetryBuilder addAttributesExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributesExtractor(attributesExtractor); + return this; + } + + /** + * Configures the HTTP request headers that will be captured as span attributes from server + * instrumentation. + * + * @param requestHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxServerTelemetryBuilder setCapturedRequestHeaders( + List requestHeaders) { + builder.setCapturedRequestHeaders(requestHeaders); + return this; + } + + /** + * Configures the HTTP response headers that will be captured as span attributes from server + * instrumentation. + * + * @param responseHeaders A list of HTTP header names. + */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxServerTelemetryBuilder setCapturedResponseHeaders( + List responseHeaders) { + builder.setCapturedResponseHeaders(responseHeaders); + return this; + } + + /** + * Configures the instrumentation to recognize an alternative set of HTTP request methods. + * + *

By default, this instrumentation defines "known" methods as the ones listed in RFC9110 and the PATCH + * method defined in RFC5789. + * + *

Note: calling this method overrides the default known method sets completely; it does + * not supplement it. + * + * @param knownMethods A set of recognized HTTP request methods. + * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) + */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxServerTelemetryBuilder setKnownMethods(Set knownMethods) { + builder.setKnownMethods(knownMethods); + return this; + } + + /** Sets custom server {@link SpanNameExtractor} via transform function. */ + @Override + @CanIgnoreReturnValue + public SpringWebfluxServerTelemetryBuilder setSpanNameExtractor( + Function, SpanNameExtractor> + serverSpanNameExtractor) { + builder.setSpanNameExtractor(serverSpanNameExtractor); + return this; + } + + @Override + public SpringWebfluxServerTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + + /** + * Can be used via the unstable method {@link + * Experimental#setEmitExperimentalTelemetry(SpringWebfluxServerTelemetryBuilder, boolean)}. + */ + void setEmitExperimentalHttpServerTelemetry(boolean emitExperimentalHttpServerTelemetry) { + builder.setEmitExperimentalHttpServerMetrics(emitExperimentalHttpServerTelemetry); + } + + /** + * Returns a new {@link SpringWebfluxTelemetry} with the settings of this {@link + * SpringWebfluxServerTelemetryBuilder}. + */ + @Override + public SpringWebfluxServerTelemetry build() { + return new SpringWebfluxServerTelemetry(builder.build()); + } +} diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxTelemetry.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxTelemetry.java index 27021d22ea40..622b671fb0b9 100644 --- a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxTelemetry.java +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxTelemetry.java @@ -17,12 +17,22 @@ import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; -/** Entrypoint for instrumenting Spring Webflux HTTP clients. */ +/** + * Entrypoint for instrumenting Spring Webflux HTTP clients and services. + * + * @deprecated Use {@link SpringWebfluxClientTelemetry} and {@link SpringWebfluxServerTelemetry} + * instead. + */ +@Deprecated public final class SpringWebfluxTelemetry { /** * Returns a new {@link SpringWebfluxTelemetry} configured with the given {@link OpenTelemetry}. + * + * @deprecated Use {@link SpringWebfluxClientTelemetry#create(OpenTelemetry)} and {@link + * SpringWebfluxServerTelemetry#create(OpenTelemetry)} instead. */ + @Deprecated public static SpringWebfluxTelemetry create(OpenTelemetry openTelemetry) { return builder(openTelemetry).build(); } @@ -30,7 +40,11 @@ public static SpringWebfluxTelemetry create(OpenTelemetry openTelemetry) { /** * Returns a new {@link SpringWebfluxTelemetryBuilder} configured with the given {@link * OpenTelemetry}. + * + * @deprecated Use {@link SpringWebfluxClientTelemetry#builder(OpenTelemetry)} and {@link + * SpringWebfluxServerTelemetry#builder(OpenTelemetry)} instead. */ + @Deprecated public static SpringWebfluxTelemetryBuilder builder(OpenTelemetry openTelemetry) { return new SpringWebfluxTelemetryBuilder(openTelemetry); } @@ -50,6 +64,10 @@ public static SpringWebfluxTelemetryBuilder builder(OpenTelemetry openTelemetry) this.propagators = propagators; } + /** + * @deprecated Use {@link SpringWebfluxClientTelemetry#addTracingFilter(List)} instead. + */ + @Deprecated public void addClientTracingFilter(List exchangeFilterFunctions) { for (ExchangeFilterFunction filterFunction : exchangeFilterFunctions) { if (filterFunction instanceof WebClientTracingFilter) { @@ -59,10 +77,19 @@ public void addClientTracingFilter(List exchangeFilterFu exchangeFilterFunctions.add(new WebClientTracingFilter(clientInstrumenter, propagators)); } + /** + * @deprecated Use {@link SpringWebfluxServerTelemetry#createWebFilter()} instead. + */ + @Deprecated public WebFilter createWebFilter() { return new TelemetryProducingWebFilter(serverInstrumenter); } + /** + * @deprecated Use {@link SpringWebfluxServerTelemetry#createWebFilterAndRegisterReactorHook()} + * instead. + */ + @Deprecated public WebFilter createWebFilterAndRegisterReactorHook() { registerReactorHook(); return this.createWebFilter(); diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxTelemetryBuilder.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxTelemetryBuilder.java index 602ded9c1d4d..713f5b6cac36 100644 --- a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxTelemetryBuilder.java +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxTelemetryBuilder.java @@ -13,7 +13,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; -import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.SpringWebfluxBuilderUtil; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.Experimental; import io.opentelemetry.instrumentation.spring.webflux.v5_3.internal.WebClientHttpAttributesGetter; import java.util.List; import java.util.Set; @@ -22,7 +22,13 @@ import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.server.ServerWebExchange; -/** A builder of {@link SpringWebfluxTelemetry}. */ +/** + * A builder of {@link SpringWebfluxTelemetry}. + * + * @deprecated Use {@link SpringWebfluxClientTelemetryBuilder} and {@link + * SpringWebfluxServerTelemetryBuilder} instead. + */ +@Deprecated public final class SpringWebfluxTelemetryBuilder { private static final String INSTRUMENTATION_NAME = "io.opentelemetry.spring-webflux-5.3"; @@ -31,13 +37,6 @@ public final class SpringWebfluxTelemetryBuilder { serverBuilder; private final OpenTelemetry openTelemetry; - static { - SpringWebfluxBuilderUtil.setClientBuilderExtractor( - SpringWebfluxTelemetryBuilder::getClientBuilder); - SpringWebfluxBuilderUtil.setServerBuilderExtractor( - SpringWebfluxTelemetryBuilder::getServerBuilder); - } - SpringWebfluxTelemetryBuilder(OpenTelemetry openTelemetry) { clientBuilder = DefaultHttpClientInstrumenterBuilder.create( @@ -54,11 +53,15 @@ public final class SpringWebfluxTelemetryBuilder { /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items for WebClient. + * + * @deprecated Use {@link + * SpringWebfluxClientTelemetryBuilder#addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder addClientAttributesExtractor( AttributesExtractor attributesExtractor) { - clientBuilder.addAttributeExtractor(attributesExtractor); + clientBuilder.addAttributesExtractor(attributesExtractor); return this; } @@ -66,7 +69,10 @@ public SpringWebfluxTelemetryBuilder addClientAttributesExtractor( * Configures the HTTP WebClient request headers that will be captured as span attributes. * * @param requestHeaders A list of HTTP header names. + * @deprecated Use {@link SpringWebfluxClientTelemetryBuilder#setCapturedRequestHeaders(List)} + * instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder setCapturedClientRequestHeaders( List requestHeaders) { @@ -78,7 +84,10 @@ public SpringWebfluxTelemetryBuilder setCapturedClientRequestHeaders( * Configures the HTTP WebClient response headers that will be captured as span attributes. * * @param responseHeaders A list of HTTP header names. + * @deprecated Use {@link SpringWebfluxClientTelemetryBuilder#setCapturedResponseHeaders(List)} + * instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder setCapturedClientResponseHeaders( List responseHeaders) { @@ -89,7 +98,11 @@ public SpringWebfluxTelemetryBuilder setCapturedClientResponseHeaders( /** * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. + * + * @deprecated Use {@link + * SpringWebfluxServerTelemetryBuilder#addAttributesExtractor(AttributesExtractor)} instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder addServerAttributesExtractor( AttributesExtractor attributesExtractor) { @@ -102,7 +115,10 @@ public SpringWebfluxTelemetryBuilder addServerAttributesExtractor( * instrumentation. * * @param requestHeaders A list of HTTP header names. + * @deprecated Use {@link SpringWebfluxServerTelemetryBuilder#setCapturedRequestHeaders(List)} + * instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder setCapturedServerRequestHeaders( List requestHeaders) { @@ -115,7 +131,10 @@ public SpringWebfluxTelemetryBuilder setCapturedServerRequestHeaders( * instrumentation. * * @param responseHeaders A list of HTTP header names. + * @deprecated Use {@link SpringWebfluxServerTelemetryBuilder#setCapturedResponseHeaders(List)} + * instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder setCapturedServerResponseHeaders( List responseHeaders) { @@ -136,7 +155,10 @@ public SpringWebfluxTelemetryBuilder setCapturedServerResponseHeaders( * @param knownMethods A set of recognized HTTP request methods. * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) + * @deprecated Use {@link SpringWebfluxClientTelemetryBuilder#setKnownMethods(Set)} and {@link + * SpringWebfluxServerTelemetryBuilder#setKnownMethods(Set)} instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder setKnownMethods(Set knownMethods) { clientBuilder.setKnownMethods(knownMethods); @@ -149,7 +171,11 @@ public SpringWebfluxTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpClientTelemetry {@code true} if the experimental HTTP client metrics * are to be emitted. + * @deprecated Use {@link + * Experimental#setEmitExperimentalTelemetry(SpringWebfluxClientTelemetryBuilder, boolean)} + * instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder setEmitExperimentalHttpClientTelemetry( boolean emitExperimentalHttpClientTelemetry) { @@ -162,7 +188,11 @@ public SpringWebfluxTelemetryBuilder setEmitExperimentalHttpClientTelemetry( * * @param emitExperimentalHttpServerTelemetry {@code true} if the experimental HTTP server metrics * are to be emitted. + * @deprecated Use {@link + * Experimental#setEmitExperimentalTelemetry(SpringWebfluxServerTelemetryBuilder, boolean)} + * instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder setEmitExperimentalHttpServerTelemetry( boolean emitExperimentalHttpServerTelemetry) { @@ -170,23 +200,31 @@ public SpringWebfluxTelemetryBuilder setEmitExperimentalHttpServerTelemetry( return this; } - /** Sets custom client {@link SpanNameExtractor} via transform function. */ + /** + * Sets custom client {@link SpanNameExtractor} via transform function. + * + * @deprecated Use {@link SpringWebfluxClientTelemetryBuilder#setSpanNameExtractor(Function)} + * instead. + */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder setClientSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> clientSpanNameExtractor) { clientBuilder.setSpanNameExtractor(clientSpanNameExtractor); return this; } - /** Sets custom server {@link SpanNameExtractor} via transform function. */ + /** + * Sets custom server {@link SpanNameExtractor} via transform function. + * + * @deprecated Use {@link SpringWebfluxServerTelemetryBuilder#setSpanNameExtractor(Function)} + * instead. + */ + @Deprecated @CanIgnoreReturnValue public SpringWebfluxTelemetryBuilder setServerSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> serverSpanNameExtractor) { serverBuilder.setSpanNameExtractor(serverSpanNameExtractor); return this; @@ -195,18 +233,13 @@ public SpringWebfluxTelemetryBuilder setServerSpanNameExtractor( /** * Returns a new {@link SpringWebfluxTelemetry} with the settings of this {@link * SpringWebfluxTelemetryBuilder}. + * + * @deprecated Use {@link SpringWebfluxClientTelemetryBuilder#build()} and {@link + * SpringWebfluxServerTelemetryBuilder#build()} instead. */ + @Deprecated public SpringWebfluxTelemetry build() { return new SpringWebfluxTelemetry( clientBuilder.build(), serverBuilder.build(), openTelemetry.getPropagators()); } - - private DefaultHttpClientInstrumenterBuilder getClientBuilder() { - return clientBuilder; - } - - private DefaultHttpServerInstrumenterBuilder - getServerBuilder() { - return serverBuilder; - } } diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/internal/Experimental.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/internal/Experimental.java new file mode 100644 index 000000000000..c3d05e0967f7 --- /dev/null +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/internal/Experimental.java @@ -0,0 +1,85 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.webflux.v5_3.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxClientTelemetryBuilder; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxServerTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalClientTelemetryMethod = + getEmitExperimentalClientTelemetryMethod(); + + @Nullable + private static final Method emitExperimentalServerTelemetryMethod = + getEmitExperimentalServerTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + SpringWebfluxClientTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalClientTelemetryMethod != null) { + try { + emitExperimentalClientTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + public void setEmitExperimentalTelemetry( + SpringWebfluxServerTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalServerTelemetryMethod != null) { + try { + emitExperimentalServerTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalClientTelemetryMethod() { + try { + Method method = + SpringWebfluxClientTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpClientTelemetry", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } + + @Nullable + private static Method getEmitExperimentalServerTelemetryMethod() { + try { + Method method = + SpringWebfluxServerTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpServerTelemetry", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/internal/SpringWebfluxBuilderUtil.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/internal/SpringWebfluxBuilderUtil.java index ec1d643b1d88..e2e9ebf87b08 100644 --- a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/internal/SpringWebfluxBuilderUtil.java +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/internal/SpringWebfluxBuilderUtil.java @@ -7,7 +7,8 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; -import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxTelemetryBuilder; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxClientTelemetryBuilder; +import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxServerTelemetryBuilder; import java.util.function.Function; import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ClientResponse; @@ -22,18 +23,18 @@ private SpringWebfluxBuilderUtil() {} // allows access to the private field for the spring starter private static Function< - SpringWebfluxTelemetryBuilder, + SpringWebfluxClientTelemetryBuilder, DefaultHttpClientInstrumenterBuilder> clientBuilderExtractor; // allows access to the private field for the spring starter private static Function< - SpringWebfluxTelemetryBuilder, + SpringWebfluxServerTelemetryBuilder, DefaultHttpServerInstrumenterBuilder> serverBuilderExtractor; public static Function< - SpringWebfluxTelemetryBuilder, + SpringWebfluxServerTelemetryBuilder, DefaultHttpServerInstrumenterBuilder> getServerBuilderExtractor() { return serverBuilderExtractor; @@ -41,14 +42,14 @@ private SpringWebfluxBuilderUtil() {} public static void setServerBuilderExtractor( Function< - SpringWebfluxTelemetryBuilder, + SpringWebfluxServerTelemetryBuilder, DefaultHttpServerInstrumenterBuilder> serverBuilderExtractor) { SpringWebfluxBuilderUtil.serverBuilderExtractor = serverBuilderExtractor; } public static Function< - SpringWebfluxTelemetryBuilder, + SpringWebfluxClientTelemetryBuilder, DefaultHttpClientInstrumenterBuilder> getClientBuilderExtractor() { return clientBuilderExtractor; @@ -56,7 +57,7 @@ public static void setServerBuilderExtractor( public static void setClientBuilderExtractor( Function< - SpringWebfluxTelemetryBuilder, + SpringWebfluxClientTelemetryBuilder, DefaultHttpClientInstrumenterBuilder> clientBuilderExtractor) { SpringWebfluxBuilderUtil.clientBuilderExtractor = clientBuilderExtractor; diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/test/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientInstrumentationTest.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/test/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientInstrumentationTest.java index 6ed4170704ab..e8980ef3d9fb 100644 --- a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/test/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientInstrumentationTest.java +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/test/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/SpringWebfluxClientInstrumentationTest.java @@ -21,13 +21,13 @@ class SpringWebfluxClientInstrumentationTest @Override protected WebClient.Builder instrument(WebClient.Builder builder) { - SpringWebfluxTelemetry instrumentation = - SpringWebfluxTelemetry.builder(testing.getOpenTelemetry()) - .setCapturedClientRequestHeaders( + SpringWebfluxClientTelemetry instrumentation = + SpringWebfluxClientTelemetry.builder(testing.getOpenTelemetry()) + .setCapturedRequestHeaders( Collections.singletonList(AbstractHttpClientTest.TEST_REQUEST_HEADER)) - .setCapturedClientResponseHeaders( + .setCapturedResponseHeaders( Collections.singletonList(AbstractHttpClientTest.TEST_RESPONSE_HEADER)) .build(); - return builder.filters(instrumentation::addClientTracingFilter); + return builder.filters(instrumentation::addTracingFilter); } } diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/test/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/TestWebfluxSpringBootApp.java b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/test/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/TestWebfluxSpringBootApp.java index c0eb9a65d91e..77afcf9881c0 100644 --- a/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/test/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/TestWebfluxSpringBootApp.java +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.3/library/src/test/java/io/opentelemetry/instrumentation/spring/webflux/v5_3/TestWebfluxSpringBootApp.java @@ -52,10 +52,9 @@ static ConfigurableApplicationContext start(int port, String contextPath) { @Bean WebFilter telemetryFilter() { - return SpringWebfluxTelemetry.builder(GlobalOpenTelemetry.get()) - .setCapturedServerRequestHeaders(singletonList(AbstractHttpServerTest.TEST_REQUEST_HEADER)) - .setCapturedServerResponseHeaders( - singletonList(AbstractHttpServerTest.TEST_RESPONSE_HEADER)) + return SpringWebfluxServerTelemetry.builder(GlobalOpenTelemetry.get()) + .setCapturedRequestHeaders(singletonList(AbstractHttpServerTest.TEST_REQUEST_HEADER)) + .setCapturedResponseHeaders(singletonList(AbstractHttpServerTest.TEST_RESPONSE_HEADER)) .build() .createWebFilterAndRegisterReactorHook(); } diff --git a/instrumentation/spring/spring-webmvc/spring-webmvc-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v5_3/SpringWebMvcTelemetryBuilder.java b/instrumentation/spring/spring-webmvc/spring-webmvc-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v5_3/SpringWebMvcTelemetryBuilder.java index a24abdad8105..ed0981ed0ec5 100644 --- a/instrumentation/spring/spring-webmvc/spring-webmvc-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v5_3/SpringWebMvcTelemetryBuilder.java +++ b/instrumentation/spring/spring-webmvc/spring-webmvc-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v5_3/SpringWebMvcTelemetryBuilder.java @@ -10,7 +10,10 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder; +import io.opentelemetry.instrumentation.spring.webmvc.v5_3.internal.Experimental; import io.opentelemetry.instrumentation.spring.webmvc.v5_3.internal.SpringMvcBuilderUtil; import java.util.List; import java.util.Set; @@ -19,7 +22,8 @@ import javax.servlet.http.HttpServletResponse; /** A builder of {@link SpringWebMvcTelemetry}. */ -public final class SpringWebMvcTelemetryBuilder { +public final class SpringWebMvcTelemetryBuilder + implements HttpServerTelemetryBuilder { private static final String INSTRUMENTATION_NAME = "io.opentelemetry.spring-webmvc-5.3"; @@ -43,6 +47,7 @@ public final class SpringWebMvcTelemetryBuilder { * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder addAttributesExtractor( AttributesExtractor attributesExtractor) { @@ -55,6 +60,7 @@ public SpringWebMvcTelemetryBuilder addAttributesExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -66,6 +72,7 @@ public SpringWebMvcTelemetryBuilder setCapturedRequestHeaders(List reque * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -73,16 +80,25 @@ public SpringWebMvcTelemetryBuilder setCapturedResponseHeaders(List resp } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractor) { builder.setSpanNameExtractor(spanNameExtractor); return this; } + @Override + public SpringWebMvcTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Configures the instrumentation to recognize an alternative set of HTTP request methods. * @@ -96,6 +112,7 @@ public SpringWebMvcTelemetryBuilder setSpanNameExtractor( * @param knownMethods A set of recognized HTTP request methods. * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -107,7 +124,10 @@ public SpringWebMvcTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpServerMetrics {@code true} if the experimental HTTP server metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(SpringWebMvcTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setEmitExperimentalHttpServerMetrics( boolean emitExperimentalHttpServerMetrics) { @@ -119,6 +139,7 @@ public SpringWebMvcTelemetryBuilder setEmitExperimentalHttpServerMetrics( * Returns a new {@link SpringWebMvcTelemetry} with the settings of this {@link * SpringWebMvcTelemetryBuilder}. */ + @Override public SpringWebMvcTelemetry build() { return new SpringWebMvcTelemetry(builder.build()); } diff --git a/instrumentation/spring/spring-webmvc/spring-webmvc-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v5_3/internal/Experimental.java b/instrumentation/spring/spring-webmvc/spring-webmvc-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v5_3/internal/Experimental.java new file mode 100644 index 000000000000..07d67dcbd045 --- /dev/null +++ b/instrumentation/spring/spring-webmvc/spring-webmvc-5.3/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v5_3/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.webmvc.v5_3.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.spring.webmvc.v5_3.SpringWebMvcTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + SpringWebMvcTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + SpringWebMvcTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpServerMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +} diff --git a/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v6_0/SpringWebMvcTelemetryBuilder.java b/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v6_0/SpringWebMvcTelemetryBuilder.java index 7f768b057cbb..4be8b29858d8 100644 --- a/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v6_0/SpringWebMvcTelemetryBuilder.java +++ b/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v6_0/SpringWebMvcTelemetryBuilder.java @@ -10,7 +10,10 @@ import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerTelemetryBuilder; +import io.opentelemetry.instrumentation.spring.webmvc.v6_0.internal.Experimental; import io.opentelemetry.instrumentation.spring.webmvc.v6_0.internal.SpringMvcBuilderUtil; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -19,7 +22,8 @@ import java.util.function.Function; /** A builder of {@link SpringWebMvcTelemetry}. */ -public final class SpringWebMvcTelemetryBuilder { +public final class SpringWebMvcTelemetryBuilder + implements HttpServerTelemetryBuilder { private static final String INSTRUMENTATION_NAME = "io.opentelemetry.spring-webmvc-6.0"; private final DefaultHttpServerInstrumenterBuilder @@ -42,6 +46,7 @@ public final class SpringWebMvcTelemetryBuilder { * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented * items. */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder addAttributesExtractor( AttributesExtractor attributesExtractor) { @@ -54,6 +59,7 @@ public SpringWebMvcTelemetryBuilder addAttributesExtractor( * * @param requestHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { builder.setCapturedRequestHeaders(requestHeaders); @@ -65,6 +71,7 @@ public SpringWebMvcTelemetryBuilder setCapturedRequestHeaders(List reque * * @param responseHeaders A list of HTTP header names. */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { builder.setCapturedResponseHeaders(responseHeaders); @@ -72,16 +79,25 @@ public SpringWebMvcTelemetryBuilder setCapturedResponseHeaders(List resp } /** Sets custom {@link SpanNameExtractor} via transform function. */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setSpanNameExtractor( - Function< - SpanNameExtractor, - ? extends SpanNameExtractor> + Function, SpanNameExtractor> spanNameExtractor) { builder.setSpanNameExtractor(spanNameExtractor); return this; } + @Override + public SpringWebMvcTelemetryBuilder setStatusExtractor( + Function< + SpanStatusExtractor, + SpanStatusExtractor> + statusExtractorTransformer) { + builder.setStatusExtractor(statusExtractorTransformer); + return this; + } + /** * Configures the instrumentation to recognize an alternative set of HTTP request methods. * @@ -95,6 +111,7 @@ public SpringWebMvcTelemetryBuilder setSpanNameExtractor( * @param knownMethods A set of recognized HTTP request methods. * @see HttpServerAttributesExtractorBuilder#setKnownMethods(Set) */ + @Override @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setKnownMethods(Set knownMethods) { builder.setKnownMethods(knownMethods); @@ -106,7 +123,10 @@ public SpringWebMvcTelemetryBuilder setKnownMethods(Set knownMethods) { * * @param emitExperimentalHttpServerMetrics {@code true} if the experimental HTTP server metrics * are to be emitted. + * @deprecated Use {@link Experimental#setEmitExperimentalTelemetry(SpringWebMvcTelemetryBuilder, + * boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public SpringWebMvcTelemetryBuilder setEmitExperimentalHttpServerMetrics( boolean emitExperimentalHttpServerMetrics) { @@ -118,6 +138,7 @@ public SpringWebMvcTelemetryBuilder setEmitExperimentalHttpServerMetrics( * Returns a new {@link SpringWebMvcTelemetry} with the settings of this {@link * SpringWebMvcTelemetryBuilder}. */ + @Override public SpringWebMvcTelemetry build() { return new SpringWebMvcTelemetry(builder.build()); } diff --git a/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v6_0/internal/Experimental.java b/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v6_0/internal/Experimental.java new file mode 100644 index 000000000000..5bf6ea9c2c61 --- /dev/null +++ b/instrumentation/spring/spring-webmvc/spring-webmvc-6.0/library/src/main/java/io/opentelemetry/instrumentation/spring/webmvc/v6_0/internal/Experimental.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.webmvc.v6_0.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.instrumentation.spring.webmvc.v6_0.SpringWebMvcTelemetryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; +import javax.annotation.Nullable; + +/** + * This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public class Experimental { + + private static final Logger logger = Logger.getLogger(Experimental.class.getName()); + + @Nullable + private static final Method emitExperimentalTelemetryMethod = + getEmitExperimentalTelemetryMethod(); + + public void setEmitExperimentalTelemetry( + SpringWebMvcTelemetryBuilder builder, boolean emitExperimentalTelemetry) { + + if (emitExperimentalTelemetryMethod != null) { + try { + emitExperimentalTelemetryMethod.invoke(builder, emitExperimentalTelemetry); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(FINE, e.getMessage(), e); + } + } + } + + @Nullable + private static Method getEmitExperimentalTelemetryMethod() { + try { + Method method = + SpringWebMvcTelemetryBuilder.class.getDeclaredMethod( + "setEmitExperimentalHttpServerMetrics", boolean.class); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + logger.log(FINE, e.getMessage(), e); + return null; + } + } +}