From c1c052318ba807357d05fecd5d70c779d114b323 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Fri, 28 May 2021 17:24:19 -0700 Subject: [PATCH] Move more type instrumentations to top-level classes (#3118) --- .../AkkaHttpClientInstrumentationModule.java | 158 ----------------- .../AkkaHttpClientInstrumentationModule.java | 25 +++ .../{ => client}/AkkaHttpClientTracer.java | 5 +- .../akkahttp/client/AkkaHttpHeaders.java | 24 +++ .../client/HttpExtClientInstrumentation.java | 88 ++++++++++ .../akkahttp/client/HttpHeaderSetter.java | 25 +++ .../akkahttp/client/OnCompleteHandler.java | 31 ++++ .../{ => server}/AkkaHttpServerHeaders.java | 2 +- .../AkkaHttpServerInstrumentationModule.java | 55 +----- .../{ => server}/AkkaHttpServerTracer.java | 2 +- .../server/HttpExtServerInstrumentation.java | 64 +++++++ .../ApacheCamelInstrumentationModule.java | 41 ----- .../CamelContextInstrumentation.java | 50 ++++++ .../HttpUrlConnectionInstrumentation.java | 159 +++++++++++++++++ ...ttpUrlConnectionInstrumentationModule.java | 163 ------------------ .../httpurlconnection/HttpUrlState.java | 19 ++ .../HystrixCommandInstrumentation.java | 69 ++++++++ .../hystrix/HystrixInstrumentationModule.java | 85 --------- .../hystrix/HystrixOnSubscribe.java | 34 ++++ .../osgi/EclipseOsgiInstrumentation.java | 60 +++++++ .../EclipseOsgiInstrumentationModule.java | 51 ------ .../v1_1/ClientHandlerInstrumentation.java | 82 +++++++++ .../JaxRsClientInstrumentationModule.java | 73 -------- .../v2_0/ClientBuilderInstrumentation.java | 51 ++++++ .../JaxRsClientInstrumentationModule.java | 42 ----- ...cClientConnectionErrorInstrumentation.java | 45 +++++ ...fClientConnectionErrorInstrumentation.java | 41 +++++ .../v2_0/CxfClientInstrumentationModule.java | 61 ------- ...yClientConnectionErrorInstrumentation.java | 66 +++++++ .../JerseyClientInstrumentationModule.java | 61 +------ .../v8_0/Jetty8InstrumentationModule.java | 52 ------ .../JettyQueuedThreadPoolInstrumentation.java | 60 +++++++ .../KotlinCoroutinesInstrumentation.java | 55 ++++++ ...KotlinCoroutinesInstrumentationModule.java | 48 +----- .../ApiClientInstrumentation.java | 116 +++++++++++++ ...KubernetesClientInstrumentationModule.java | 107 ------------ ...DefaultClientResourcesInstrumentation.java | 40 +++++ .../v5_1/LettuceInstrumentationModule.java | 30 ---- .../liberty/LibertyHandleRequestAdvice.java | 74 -------- .../liberty/LibertyInstrumentationModule.java | 39 +---- .../liberty/LibertyStartSpanAdvice.java | 33 ---- .../liberty/LibertyWebAppInstrumentation.java | 126 ++++++++++++++ ...extDataInjectorFactoryInstrumentation.java | 47 +++++ .../v2_7/Log4j27InstrumentationModule.java | 36 ---- .../v2_2/OkHttp2InstrumentationModule.java | 34 ---- .../v2_2/OkHttpClientInstrumentation.java | 43 +++++ .../okhttp/v3_0/OkHttp3Instrumentation.java | 52 ++++++ .../v3_0/OkHttp3InstrumentationModule.java | 45 +---- .../oshi/OshiInstrumentationModule.java | 36 ---- .../oshi/SystemInfoInstrumentation.java | 45 +++++ .../play/v2_4/ActionInstrumentation.java | 92 ++++++++++ .../instrumentation/play/v2_4/PlayAdvice.java | 62 ------- .../play/v2_4/PlayInstrumentationModule.java | 29 ---- .../play/v2_6/ActionInstrumentation.java | 83 +++++++++ .../instrumentation/play/v2_6/PlayAdvice.java | 53 ------ .../play/v2_6/PlayInstrumentationModule.java | 29 ---- .../reactor/HooksInstrumentation.java | 37 ++++ .../reactor/ReactorHooksAdvice.java | 16 -- .../reactor/ReactorInstrumentationModule.java | 18 -- .../reactornetty/v0_9/DecoratorFunctions.java | 3 +- .../v0_9/HttpClientInstrumentation.java | 151 ++++++++++++++++ .../reactornetty/v0_9/MapConnect.java | 23 +++ .../reactornetty/v0_9/OnRequest.java | 20 +++ .../ReactorNettyInstrumentationModule.java | 162 ----------------- .../reactornetty/v1_0/DecoratorFunctions.java | 3 +- .../v1_0/HttpClientInstrumentation.java | 149 ++++++++++++++++ .../reactornetty/v1_0/MapConnect.java | 22 +++ .../reactornetty/v1_0/OnRequest.java | 20 +++ .../ReactorNettyInstrumentationModule.java | 159 ----------------- .../rediscala/OnCompleteHandler.java | 30 ++++ .../RediscalaInstrumentationModule.java | 95 ---------- .../rediscala/RequestInstrumentation.java | 84 +++++++++ .../RedisConnectionInstrumentation.java | 65 +++++++ .../RedissonInstrumentationModule.java | 57 ------ 74 files changed, 2312 insertions(+), 2000 deletions(-) delete mode 100644 instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationModule.java create mode 100644 instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpClientInstrumentationModule.java rename instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/{ => client}/AkkaHttpClientTracer.java (89%) create mode 100644 instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpHeaders.java create mode 100644 instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/HttpExtClientInstrumentation.java create mode 100644 instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/HttpHeaderSetter.java create mode 100644 instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/OnCompleteHandler.java rename instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/{ => server}/AkkaHttpServerHeaders.java (93%) rename instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/{ => server}/AkkaHttpServerInstrumentationModule.java (57%) rename instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/{ => server}/AkkaHttpServerTracer.java (96%) create mode 100644 instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/HttpExtServerInstrumentation.java create mode 100644 instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/CamelContextInstrumentation.java create mode 100644 instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentation.java create mode 100644 instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlState.java create mode 100644 instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixCommandInstrumentation.java create mode 100644 instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixOnSubscribe.java create mode 100644 instrumentation/internal/internal-eclipse-osgi-3.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/osgi/EclipseOsgiInstrumentation.java create mode 100644 instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/ClientHandlerInstrumentation.java create mode 100644 instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ClientBuilderInstrumentation.java create mode 100644 instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfAsyncClientConnectionErrorInstrumentation.java create mode 100644 instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfClientConnectionErrorInstrumentation.java create mode 100644 instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientConnectionErrorInstrumentation.java create mode 100644 instrumentation/jetty/jetty-8.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/v8_0/JettyQueuedThreadPoolInstrumentation.java create mode 100644 instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentation.java create mode 100644 instrumentation/kubernetes-client-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kubernetesclient/ApiClientInstrumentation.java create mode 100644 instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/DefaultClientResourcesInstrumentation.java delete mode 100644 instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyHandleRequestAdvice.java delete mode 100644 instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyStartSpanAdvice.java create mode 100644 instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyWebAppInstrumentation.java create mode 100644 instrumentation/log4j/log4j-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/v2_7/ContextDataInjectorFactoryInstrumentation.java create mode 100644 instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/OkHttpClientInstrumentation.java create mode 100644 instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3Instrumentation.java create mode 100644 instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/SystemInfoInstrumentation.java create mode 100644 instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/ActionInstrumentation.java delete mode 100644 instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayAdvice.java create mode 100644 instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/ActionInstrumentation.java delete mode 100644 instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayAdvice.java create mode 100644 instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/HooksInstrumentation.java delete mode 100644 instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/ReactorHooksAdvice.java create mode 100644 instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/HttpClientInstrumentation.java create mode 100644 instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/MapConnect.java create mode 100644 instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/OnRequest.java create mode 100644 instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/HttpClientInstrumentation.java create mode 100644 instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/MapConnect.java create mode 100644 instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/OnRequest.java create mode 100644 instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/OnCompleteHandler.java create mode 100644 instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RequestInstrumentation.java create mode 100644 instrumentation/redisson-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedisConnectionInstrumentation.java diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationModule.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationModule.java deleted file mode 100644 index bc5c310c8c..0000000000 --- a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationModule.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.akkahttp; - -import static io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientTracer.tracer; -import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; - -import akka.http.javadsl.model.headers.RawHeader; -import akka.http.scaladsl.HttpExt; -import akka.http.scaladsl.model.HttpRequest; -import akka.http.scaladsl.model.HttpResponse; -import com.google.auto.service.AutoService; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import io.opentelemetry.context.propagation.TextMapSetter; -import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; -import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import java.util.Collections; -import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import scala.concurrent.Future; -import scala.runtime.AbstractFunction1; -import scala.util.Try; - -@AutoService(InstrumentationModule.class) -public class AkkaHttpClientInstrumentationModule extends InstrumentationModule { - public AkkaHttpClientInstrumentationModule() { - super("akka-http", "akka-http-client"); - } - - @Override - public List typeInstrumentations() { - return Collections.singletonList(new HttpExtInstrumentation()); - } - - public static class HttpExtInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("akka.http.scaladsl.HttpExt"); - } - - @Override - public void transform(TypeTransformer transformer) { - // This is mainly for compatibility with 10.0 - transformer.applyAdviceToMethod( - named("singleRequest") - .and(takesArgument(0, named("akka.http.scaladsl.model.HttpRequest"))), - AkkaHttpClientInstrumentationModule.class.getName() + "$SingleRequestAdvice"); - // This is for 10.1+ - transformer.applyAdviceToMethod( - named("singleRequestImpl") - .and(takesArgument(0, named("akka.http.scaladsl.model.HttpRequest"))), - AkkaHttpClientInstrumentationModule.class.getName() + "$SingleRequestAdvice"); - } - } - - public static class SingleRequestAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void methodEnter( - @Advice.Argument(value = 0, readOnly = false) HttpRequest request, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - /* - Versions 10.0 and 10.1 have slightly different structure that is hard to distinguish so here - we cast 'wider net' and avoid instrumenting twice. - In the future we may want to separate these, but since lots of code is reused we would need to come up - with way of continuing to reusing it. - */ - Context parentContext = currentContext(); - if (!tracer().shouldStartSpan(parentContext)) { - return; - } - - // Request is immutable, so we have to assign new value once we update headers - AkkaHttpHeaders headers = new AkkaHttpHeaders(request); - context = tracer().startSpan(parentContext, request, headers); - scope = context.makeCurrent(); - request = headers.getRequest(); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void methodExit( - @Advice.Argument(0) HttpRequest request, - @Advice.This HttpExt thiz, - @Advice.Return Future responseFuture, - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - if (scope == null) { - return; - } - - scope.close(); - if (throwable == null) { - responseFuture.onComplete(new OnCompleteHandler(context), thiz.system().dispatcher()); - } else { - tracer().endExceptionally(context, throwable); - } - } - } - - public static class OnCompleteHandler extends AbstractFunction1, Void> { - private final Context context; - - public OnCompleteHandler(Context context) { - this.context = context; - } - - @Override - public Void apply(Try result) { - if (result.isSuccess()) { - tracer().end(context, result.get()); - } else { - tracer().endExceptionally(context, result.failed().get()); - } - return null; - } - } - - public static class AkkaHttpHeaders { - private HttpRequest request; - - public AkkaHttpHeaders(HttpRequest request) { - this.request = request; - } - - public HttpRequest getRequest() { - return request; - } - - public void setRequest(HttpRequest request) { - this.request = request; - } - } - - public static class InjectAdapter implements TextMapSetter { - - public static final InjectAdapter SETTER = new InjectAdapter(); - - @Override - public void set(AkkaHttpHeaders carrier, String key, String value) { - HttpRequest request = carrier.getRequest(); - if (request != null) { - // It looks like this cast is only needed in Java, Scala would have figured it out - carrier.setRequest( - (HttpRequest) request.removeHeader(key).addHeader(RawHeader.create(key, value))); - } - } - } -} diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpClientInstrumentationModule.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpClientInstrumentationModule.java new file mode 100644 index 0000000000..afe703c779 --- /dev/null +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpClientInstrumentationModule.java @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.akkahttp.client; + +import static java.util.Collections.singletonList; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; + +@AutoService(InstrumentationModule.class) +public class AkkaHttpClientInstrumentationModule extends InstrumentationModule { + public AkkaHttpClientInstrumentationModule() { + super("akka-http", "akka-http-client"); + } + + @Override + public List typeInstrumentations() { + return singletonList(new HttpExtClientInstrumentation()); + } +} diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientTracer.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpClientTracer.java similarity index 89% rename from instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientTracer.java rename to instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpClientTracer.java index 62cf40ff1e..21b55ce169 100644 --- a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientTracer.java +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpClientTracer.java @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.akkahttp; +package io.opentelemetry.javaagent.instrumentation.akkahttp.client; -import static io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientInstrumentationModule.InjectAdapter.SETTER; +import static io.opentelemetry.javaagent.instrumentation.akkahttp.client.HttpHeaderSetter.SETTER; import akka.http.javadsl.model.HttpHeader; import akka.http.scaladsl.model.HttpRequest; @@ -13,7 +13,6 @@ import akka.http.scaladsl.model.HttpResponse; import io.opentelemetry.context.propagation.TextMapSetter; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes; -import io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientInstrumentationModule.AkkaHttpHeaders; import java.net.URI; import java.net.URISyntaxException; diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpHeaders.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpHeaders.java new file mode 100644 index 0000000000..cccdb184ec --- /dev/null +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/AkkaHttpHeaders.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.akkahttp.client; + +import akka.http.scaladsl.model.HttpRequest; + +public class AkkaHttpHeaders { + private HttpRequest request; + + public AkkaHttpHeaders(HttpRequest request) { + this.request = request; + } + + public HttpRequest getRequest() { + return request; + } + + public void setRequest(HttpRequest request) { + this.request = request; + } +} diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/HttpExtClientInstrumentation.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/HttpExtClientInstrumentation.java new file mode 100644 index 0000000000..319b8a08b5 --- /dev/null +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/HttpExtClientInstrumentation.java @@ -0,0 +1,88 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.akkahttp.client; + +import static io.opentelemetry.javaagent.instrumentation.akkahttp.client.AkkaHttpClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import akka.http.scaladsl.HttpExt; +import akka.http.scaladsl.model.HttpRequest; +import akka.http.scaladsl.model.HttpResponse; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import scala.concurrent.Future; + +public class HttpExtClientInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("akka.http.scaladsl.HttpExt"); + } + + @Override + public void transform(TypeTransformer transformer) { + // This is mainly for compatibility with 10.0 + transformer.applyAdviceToMethod( + named("singleRequest").and(takesArgument(0, named("akka.http.scaladsl.model.HttpRequest"))), + this.getClass().getName() + "$SingleRequestAdvice"); + // This is for 10.1+ + transformer.applyAdviceToMethod( + named("singleRequestImpl") + .and(takesArgument(0, named("akka.http.scaladsl.model.HttpRequest"))), + this.getClass().getName() + "$SingleRequestAdvice"); + } + + public static class SingleRequestAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.Argument(value = 0, readOnly = false) HttpRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + /* + Versions 10.0 and 10.1 have slightly different structure that is hard to distinguish so here + we cast 'wider net' and avoid instrumenting twice. + In the future we may want to separate these, but since lots of code is reused we would need to come up + with way of continuing to reusing it. + */ + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } + + // Request is immutable, so we have to assign new value once we update headers + AkkaHttpHeaders headers = new AkkaHttpHeaders(request); + context = tracer().startSpan(parentContext, request, headers); + scope = context.makeCurrent(); + request = headers.getRequest(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.Argument(0) HttpRequest request, + @Advice.This HttpExt thiz, + @Advice.Return Future responseFuture, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + if (throwable == null) { + responseFuture.onComplete(new OnCompleteHandler(context), thiz.system().dispatcher()); + } else { + tracer().endExceptionally(context, throwable); + } + } + } +} diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/HttpHeaderSetter.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/HttpHeaderSetter.java new file mode 100644 index 0000000000..2ed7185267 --- /dev/null +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/HttpHeaderSetter.java @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.akkahttp.client; + +import akka.http.javadsl.model.headers.RawHeader; +import akka.http.scaladsl.model.HttpRequest; +import io.opentelemetry.context.propagation.TextMapSetter; + +public class HttpHeaderSetter implements TextMapSetter { + + public static final HttpHeaderSetter SETTER = new HttpHeaderSetter(); + + @Override + public void set(AkkaHttpHeaders carrier, String key, String value) { + HttpRequest request = carrier.getRequest(); + if (request != null) { + // It looks like this cast is only needed in Java, Scala would have figured it out + carrier.setRequest( + (HttpRequest) request.removeHeader(key).addHeader(RawHeader.create(key, value))); + } + } +} diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/OnCompleteHandler.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/OnCompleteHandler.java new file mode 100644 index 0000000000..e690c9aebb --- /dev/null +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/client/OnCompleteHandler.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.akkahttp.client; + +import static io.opentelemetry.javaagent.instrumentation.akkahttp.client.AkkaHttpClientTracer.tracer; + +import akka.http.scaladsl.model.HttpResponse; +import io.opentelemetry.context.Context; +import scala.runtime.AbstractFunction1; +import scala.util.Try; + +public class OnCompleteHandler extends AbstractFunction1, Void> { + private final Context context; + + public OnCompleteHandler(Context context) { + this.context = context; + } + + @Override + public Void apply(Try result) { + if (result.isSuccess()) { + tracer().end(context, result.get()); + } else { + tracer().endExceptionally(context, result.failed().get()); + } + return null; + } +} diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpServerHeaders.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/AkkaHttpServerHeaders.java similarity index 93% rename from instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpServerHeaders.java rename to instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/AkkaHttpServerHeaders.java index 1d1f842f77..b149b7ffad 100644 --- a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpServerHeaders.java +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/AkkaHttpServerHeaders.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.akkahttp; +package io.opentelemetry.javaagent.instrumentation.akkahttp.server; import akka.http.javadsl.model.HttpHeader; import akka.http.scaladsl.model.HttpRequest; diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpServerInstrumentationModule.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/AkkaHttpServerInstrumentationModule.java similarity index 57% rename from instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpServerInstrumentationModule.java rename to instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/AkkaHttpServerInstrumentationModule.java index a52e5d51c2..4e4b3a5fc5 100644 --- a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpServerInstrumentationModule.java +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/AkkaHttpServerInstrumentationModule.java @@ -3,26 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.akkahttp; +package io.opentelemetry.javaagent.instrumentation.akkahttp.server; -import static io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpServerTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.akkahttp.server.AkkaHttpServerTracer.tracer; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import akka.http.scaladsl.model.HttpRequest; import akka.http.scaladsl.model.HttpResponse; -import akka.stream.Materializer; import com.google.auto.service.AutoService; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; import scala.Function1; import scala.concurrent.ExecutionContext; import scala.concurrent.Future; @@ -36,49 +29,7 @@ public class AkkaHttpServerInstrumentationModule extends InstrumentationModule { @Override public List typeInstrumentations() { - return singletonList(new HttpExtInstrumentation()); - } - - public static class HttpExtInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("akka.http.scaladsl.HttpExt"); - } - - @Override - public void transform(TypeTransformer transformer) { - // Instrumenting akka-streams bindAndHandle api was previously attempted. - // This proved difficult as there was no clean way to close the async scope - // in the graph logic after the user's request handler completes. - // - // Instead, we're instrumenting the bindAndHandle function helpers by - // wrapping the scala functions with our own handlers. - transformer.applyAdviceToMethod( - named("bindAndHandleSync").and(takesArgument(0, named("scala.Function1"))), - AkkaHttpServerInstrumentationModule.class.getName() + "$AkkaHttpSyncAdvice"); - transformer.applyAdviceToMethod( - named("bindAndHandleAsync").and(takesArgument(0, named("scala.Function1"))), - AkkaHttpServerInstrumentationModule.class.getName() + "$AkkaHttpAsyncAdvice"); - } - } - - public static class AkkaHttpSyncAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void wrapHandler( - @Advice.Argument(value = 0, readOnly = false) - Function1 handler) { - handler = new SyncWrapper(handler); - } - } - - public static class AkkaHttpAsyncAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void wrapHandler( - @Advice.Argument(value = 0, readOnly = false) - Function1> handler, - @Advice.Argument(7) Materializer materializer) { - handler = new AsyncWrapper(handler, materializer.executionContext()); - } + return singletonList(new HttpExtServerInstrumentation()); } public static class SyncWrapper extends AbstractFunction1 { diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpServerTracer.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/AkkaHttpServerTracer.java similarity index 96% rename from instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpServerTracer.java rename to instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/AkkaHttpServerTracer.java index 862ecee05d..a0a76dbe6d 100644 --- a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpServerTracer.java +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/AkkaHttpServerTracer.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.akkahttp; +package io.opentelemetry.javaagent.instrumentation.akkahttp.server; import akka.http.javadsl.model.HttpHeader; import akka.http.scaladsl.model.HttpRequest; diff --git a/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/HttpExtServerInstrumentation.java b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/HttpExtServerInstrumentation.java new file mode 100644 index 0000000000..e08dcd2132 --- /dev/null +++ b/instrumentation/akka-http-10.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/akkahttp/server/HttpExtServerInstrumentation.java @@ -0,0 +1,64 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.akkahttp.server; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import akka.http.scaladsl.model.HttpRequest; +import akka.http.scaladsl.model.HttpResponse; +import akka.stream.Materializer; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import scala.Function1; +import scala.concurrent.Future; + +public class HttpExtServerInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("akka.http.scaladsl.HttpExt"); + } + + @Override + public void transform(TypeTransformer transformer) { + // Instrumenting akka-streams bindAndHandle api was previously attempted. + // This proved difficult as there was no clean way to close the async scope + // in the graph logic after the user's request handler completes. + // + // Instead, we're instrumenting the bindAndHandle function helpers by + // wrapping the scala functions with our own handlers. + transformer.applyAdviceToMethod( + named("bindAndHandleSync").and(takesArgument(0, named("scala.Function1"))), + this.getClass().getName() + "$AkkaHttpSyncAdvice"); + transformer.applyAdviceToMethod( + named("bindAndHandleAsync").and(takesArgument(0, named("scala.Function1"))), + this.getClass().getName() + "$AkkaHttpAsyncAdvice"); + } + + public static class AkkaHttpSyncAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void wrapHandler( + @Advice.Argument(value = 0, readOnly = false) + Function1 handler) { + handler = new AkkaHttpServerInstrumentationModule.SyncWrapper(handler); + } + } + + public static class AkkaHttpAsyncAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void wrapHandler( + @Advice.Argument(value = 0, readOnly = false) + Function1> handler, + @Advice.Argument(7) Materializer materializer) { + handler = + new AkkaHttpServerInstrumentationModule.AsyncWrapper( + handler, materializer.executionContext()); + } + } +} diff --git a/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/ApacheCamelInstrumentationModule.java b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/ApacheCamelInstrumentationModule.java index 59f408505b..b6ab18ed0b 100644 --- a/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/ApacheCamelInstrumentationModule.java +++ b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/ApacheCamelInstrumentationModule.java @@ -5,22 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.apachecamel; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import org.apache.camel.CamelContext; @AutoService(InstrumentationModule.class) public class ApacheCamelInstrumentationModule extends InstrumentationModule { @@ -38,35 +28,4 @@ public class ApacheCamelInstrumentationModule extends InstrumentationModule { public boolean isHelperClass(String className) { return className.startsWith("io.opentelemetry.extension.aws."); } - - public static class CamelContextInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher classLoaderOptimization() { - return hasClassesNamed("org.apache.camel.CamelContext"); - } - - @Override - public ElementMatcher typeMatcher() { - return implementsInterface(named("org.apache.camel.CamelContext")); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("start").and(isPublic()).and(takesArguments(0)), - ApacheCamelInstrumentationModule.class.getName() + "$ContextAdvice"); - } - } - - public static class ContextAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onContextStart(@Advice.This final CamelContext context) throws Exception { - - if (context.hasService(CamelTracingService.class) == null) { - // start this service eager so we init before Camel is starting up - context.addService(new CamelTracingService(context), true, true); - } - } - } } diff --git a/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/CamelContextInstrumentation.java b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/CamelContextInstrumentation.java new file mode 100644 index 0000000000..26531b1de3 --- /dev/null +++ b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/CamelContextInstrumentation.java @@ -0,0 +1,50 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.apachecamel; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.camel.CamelContext; + +public class CamelContextInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("org.apache.camel.CamelContext"); + } + + @Override + public ElementMatcher typeMatcher() { + return implementsInterface(named("org.apache.camel.CamelContext")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("start").and(isPublic()).and(takesArguments(0)), + this.getClass().getName() + "$StartAdvice"); + } + + public static class StartAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onContextStart(@Advice.This final CamelContext context) throws Exception { + + if (context.hasService(CamelTracingService.class) == null) { + // start this service eager so we init before Camel is starting up + context.addService(new CamelTracingService(context), true, true); + } + } + } +} diff --git a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentation.java b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentation.java new file mode 100644 index 0000000000..8ea3abd287 --- /dev/null +++ b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentation.java @@ -0,0 +1,159 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.httpurlconnection; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static io.opentelemetry.javaagent.extension.matcher.NameMatchers.namedOneOf; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.httpurlconnection.HttpUrlConnectionTracer.tracer; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.tracer.HttpStatusConverter; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.CallDepth; +import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; +import io.opentelemetry.javaagent.instrumentation.api.ContextStore; +import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext; +import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import java.net.HttpURLConnection; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +public class HttpUrlConnectionInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return nameStartsWith("java.net.") + .or(ElementMatchers.nameStartsWith("sun.net")) + // In WebLogic, URL.openConnection() returns its own internal implementation of + // HttpURLConnection, which does not delegate the methods that have to be instrumented to + // the JDK superclass. Therefore it needs to be instrumented directly. + .or(named("weblogic.net.http.HttpURLConnection")) + // This class is a simple delegator. Skip because it does not update its `connected` + // field. + .and(not(named("sun.net.www.protocol.https.HttpsURLConnectionImpl"))) + .and(extendsClass(named("java.net.HttpURLConnection"))); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(isPublic()).and(namedOneOf("connect", "getOutputStream", "getInputStream")), + this.getClass().getName() + "$HttpUrlConnectionAdvice"); + transformer.applyAdviceToMethod( + isMethod().and(isPublic()).and(named("getResponseCode")), + this.getClass().getName() + "$GetResponseCodeAdvice"); + } + + public static class HttpUrlConnectionAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.This HttpURLConnection connection, + @Advice.FieldValue("connected") boolean connected, + @Advice.Local("otelHttpUrlState") HttpUrlState httpUrlState, + @Advice.Local("otelScope") Scope scope, + @Advice.Local("otelCallDepth") CallDepth callDepth) { + + callDepth = CallDepthThreadLocalMap.getCallDepth(HttpURLConnection.class); + if (callDepth.getAndIncrement() > 0) { + // only want the rest of the instrumentation rules (which are complex enough) to apply to + // top-level HttpURLConnection calls + return; + } + Context parentContext = currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } + + // using storage for a couple of reasons: + // - to start an operation in connect() and end it in getInputStream() + // - to avoid creating a new operation on multiple subsequent calls to getInputStream() + ContextStore storage = + InstrumentationContext.get(HttpURLConnection.class, HttpUrlState.class); + httpUrlState = storage.get(connection); + + if (httpUrlState != null) { + if (!httpUrlState.finished) { + scope = httpUrlState.context.makeCurrent(); + } + return; + } + + Context context = tracer().startSpan(parentContext, connection); + httpUrlState = new HttpUrlState(context); + storage.put(connection, httpUrlState); + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void methodExit( + @Advice.This HttpURLConnection connection, + @Advice.FieldValue("responseCode") int responseCode, + @Advice.Thrown Throwable throwable, + @Advice.Origin("#m") String methodName, + @Advice.Local("otelHttpUrlState") HttpUrlState httpUrlState, + @Advice.Local("otelScope") Scope scope, + @Advice.Local("otelCallDepth") CallDepth callDepth) { + if (callDepth.decrementAndGet() > 0) { + return; + } + if (scope == null) { + return; + } + scope.close(); + + if (throwable != null) { + if (responseCode >= 400) { + // HttpURLConnection unnecessarily throws exception on error response. + // None of the other http clients do this, so not recording the exception on the span + // to be consistent with the telemetry for other http clients. + tracer().end(httpUrlState.context, new HttpUrlResponse(connection, responseCode)); + } else { + tracer().endExceptionally(httpUrlState.context, throwable); + } + httpUrlState.finished = true; + } else if (methodName.equals("getInputStream") && responseCode > 0) { + // responseCode field is sometimes not populated. + // We can't call getResponseCode() due to some unwanted side-effects + // (e.g. breaks getOutputStream). + tracer().end(httpUrlState.context, new HttpUrlResponse(connection, responseCode)); + httpUrlState.finished = true; + } + } + } + + public static class GetResponseCodeAdvice { + + @Advice.OnMethodExit + public static void methodExit( + @Advice.This HttpURLConnection connection, @Advice.Return int returnValue) { + + ContextStore storage = + InstrumentationContext.get(HttpURLConnection.class, HttpUrlState.class); + HttpUrlState httpUrlState = storage.get(connection); + if (httpUrlState != null) { + Span span = Java8BytecodeBridge.spanFromContext(httpUrlState.context); + span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, returnValue); + StatusCode statusCode = HttpStatusConverter.statusFromHttpStatus(returnValue); + if (statusCode != StatusCode.UNSET) { + span.setStatus(statusCode); + } + } + } + } +} diff --git a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentationModule.java b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentationModule.java index c59291574d..33d574ae6d 100644 --- a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentationModule.java +++ b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentationModule.java @@ -5,38 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.httpurlconnection; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; -import static io.opentelemetry.javaagent.extension.matcher.NameMatchers.namedOneOf; -import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; -import static io.opentelemetry.javaagent.instrumentation.httpurlconnection.HttpUrlConnectionTracer.tracer; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.tracer.HttpStatusConverter; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.api.CallDepth; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; -import io.opentelemetry.javaagent.instrumentation.api.ContextStore; -import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; -import java.net.HttpURLConnection; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import net.bytebuddy.matcher.ElementMatchers; @AutoService(InstrumentationModule.class) public class HttpUrlConnectionInstrumentationModule extends InstrumentationModule { @@ -49,141 +23,4 @@ public class HttpUrlConnectionInstrumentationModule extends InstrumentationModul public List typeInstrumentations() { return singletonList(new HttpUrlConnectionInstrumentation()); } - - public static class HttpUrlConnectionInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return nameStartsWith("java.net.") - .or(ElementMatchers.nameStartsWith("sun.net")) - // In WebLogic, URL.openConnection() returns its own internal implementation of - // HttpURLConnection, which does not delegate the methods that have to be instrumented to - // the JDK superclass. Therefore it needs to be instrumented directly. - .or(named("weblogic.net.http.HttpURLConnection")) - // This class is a simple delegator. Skip because it does not update its `connected` - // field. - .and(not(named("sun.net.www.protocol.https.HttpsURLConnectionImpl"))) - .and(extendsClass(named("java.net.HttpURLConnection"))); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isMethod() - .and(isPublic()) - .and(namedOneOf("connect", "getOutputStream", "getInputStream")), - HttpUrlConnectionInstrumentationModule.class.getName() + "$HttpUrlConnectionAdvice"); - transformer.applyAdviceToMethod( - isMethod().and(isPublic()).and(named("getResponseCode")), - HttpUrlConnectionInstrumentationModule.class.getName() + "$GetResponseCodeAdvice"); - } - } - - public static class HttpUrlConnectionAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void methodEnter( - @Advice.This HttpURLConnection connection, - @Advice.FieldValue("connected") boolean connected, - @Advice.Local("otelHttpUrlState") HttpUrlState httpUrlState, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") CallDepth callDepth) { - - callDepth = CallDepthThreadLocalMap.getCallDepth(HttpURLConnection.class); - if (callDepth.getAndIncrement() > 0) { - // only want the rest of the instrumentation rules (which are complex enough) to apply to - // top-level HttpURLConnection calls - return; - } - Context parentContext = currentContext(); - if (!tracer().shouldStartSpan(parentContext)) { - return; - } - - // using storage for a couple of reasons: - // - to start an operation in connect() and end it in getInputStream() - // - to avoid creating a new operation on multiple subsequent calls to getInputStream() - ContextStore storage = - InstrumentationContext.get(HttpURLConnection.class, HttpUrlState.class); - httpUrlState = storage.get(connection); - - if (httpUrlState != null) { - if (!httpUrlState.finished) { - scope = httpUrlState.context.makeCurrent(); - } - return; - } - - Context context = tracer().startSpan(parentContext, connection); - httpUrlState = new HttpUrlState(context); - storage.put(connection, httpUrlState); - scope = context.makeCurrent(); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void methodExit( - @Advice.This HttpURLConnection connection, - @Advice.FieldValue("responseCode") int responseCode, - @Advice.Thrown Throwable throwable, - @Advice.Origin("#m") String methodName, - @Advice.Local("otelHttpUrlState") HttpUrlState httpUrlState, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelCallDepth") CallDepth callDepth) { - if (callDepth.decrementAndGet() > 0) { - return; - } - if (scope == null) { - return; - } - scope.close(); - - if (throwable != null) { - if (responseCode >= 400) { - // HttpURLConnection unnecessarily throws exception on error response. - // None of the other http clients do this, so not recording the exception on the span - // to be consistent with the telemetry for other http clients. - tracer().end(httpUrlState.context, new HttpUrlResponse(connection, responseCode)); - } else { - tracer().endExceptionally(httpUrlState.context, throwable); - } - httpUrlState.finished = true; - } else if (methodName.equals("getInputStream") && responseCode > 0) { - // responseCode field is sometimes not populated. - // We can't call getResponseCode() due to some unwanted side-effects - // (e.g. breaks getOutputStream). - tracer().end(httpUrlState.context, new HttpUrlResponse(connection, responseCode)); - httpUrlState.finished = true; - } - } - } - - public static class GetResponseCodeAdvice { - - @Advice.OnMethodExit - public static void methodExit( - @Advice.This HttpURLConnection connection, @Advice.Return int returnValue) { - - ContextStore storage = - InstrumentationContext.get(HttpURLConnection.class, HttpUrlState.class); - HttpUrlState httpUrlState = storage.get(connection); - if (httpUrlState != null) { - Span span = Java8BytecodeBridge.spanFromContext(httpUrlState.context); - span.setAttribute(SemanticAttributes.HTTP_STATUS_CODE, returnValue); - StatusCode statusCode = HttpStatusConverter.statusFromHttpStatus(returnValue); - if (statusCode != StatusCode.UNSET) { - span.setStatus(statusCode); - } - } - } - } - - // everything is public since called directly from advice code - // (which is inlined into other packages) - public static class HttpUrlState { - public final Context context; - public boolean finished; - - public HttpUrlState(Context context) { - this.context = context; - } - } } diff --git a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlState.java b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlState.java new file mode 100644 index 0000000000..c0e095cff6 --- /dev/null +++ b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlState.java @@ -0,0 +1,19 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.httpurlconnection; + +import io.opentelemetry.context.Context; + +// everything is public since called directly from advice code +// (which is inlined into other packages) +public class HttpUrlState { + public final Context context; + public boolean finished; + + public HttpUrlState(Context context) { + this.context = context; + } +} diff --git a/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixCommandInstrumentation.java b/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixCommandInstrumentation.java new file mode 100644 index 0000000000..2bc1807f36 --- /dev/null +++ b/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixCommandInstrumentation.java @@ -0,0 +1,69 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hystrix; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; +import static io.opentelemetry.javaagent.extension.matcher.NameMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; + +import com.netflix.hystrix.HystrixInvokableInfo; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import rx.Observable; + +public class HystrixCommandInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed( + "com.netflix.hystrix.HystrixCommand", "com.netflix.hystrix.HystrixObservableCommand"); + } + + @Override + public ElementMatcher typeMatcher() { + return extendsClass( + namedOneOf( + "com.netflix.hystrix.HystrixCommand", "com.netflix.hystrix.HystrixObservableCommand")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("getExecutionObservable").and(returns(named("rx.Observable"))), + this.getClass().getName() + "$ExecuteAdvice"); + transformer.applyAdviceToMethod( + named("getFallbackObservable").and(returns(named("rx.Observable"))), + this.getClass().getName() + "$FallbackAdvice"); + } + + public static class ExecuteAdvice { + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.This HystrixInvokableInfo command, + @Advice.Return(readOnly = false) Observable result, + @Advice.Thrown Throwable throwable) { + + result = Observable.create(new HystrixOnSubscribe<>(result, command, "execute")); + } + } + + public static class FallbackAdvice { + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.This HystrixInvokableInfo command, + @Advice.Return(readOnly = false) Observable result, + @Advice.Thrown Throwable throwable) { + + result = Observable.create(new HystrixOnSubscribe<>(result, command, "fallback")); + } + } +} diff --git a/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixInstrumentationModule.java b/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixInstrumentationModule.java index 8bdca5c030..e60c6cc0e8 100644 --- a/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixInstrumentationModule.java +++ b/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixInstrumentationModule.java @@ -5,33 +5,16 @@ package io.opentelemetry.javaagent.instrumentation.hystrix; -import static io.opentelemetry.api.trace.SpanKind.INTERNAL; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; -import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; -import static io.opentelemetry.javaagent.extension.matcher.NameMatchers.namedOneOf; -import static io.opentelemetry.javaagent.instrumentation.hystrix.HystrixTracer.tracer; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.returns; import com.google.auto.service.AutoService; -import com.netflix.hystrix.HystrixInvokableInfo; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.instrumentation.rxjava.TracedOnSubscribe; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import rx.Observable; @AutoService(InstrumentationModule.class) public class HystrixInstrumentationModule extends InstrumentationModule { - private static final String OPERATION_NAME = "hystrix.cmd"; - public HystrixInstrumentationModule() { super("hystrix", "hystrix-1.4"); } @@ -45,72 +28,4 @@ public class HystrixInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new HystrixCommandInstrumentation()); } - - public static class HystrixCommandInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher classLoaderOptimization() { - return hasClassesNamed( - "com.netflix.hystrix.HystrixCommand", "com.netflix.hystrix.HystrixObservableCommand"); - } - - @Override - public ElementMatcher typeMatcher() { - return extendsClass( - namedOneOf( - "com.netflix.hystrix.HystrixCommand", - "com.netflix.hystrix.HystrixObservableCommand")); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("getExecutionObservable").and(returns(named("rx.Observable"))), - HystrixInstrumentationModule.class.getName() + "$ExecuteAdvice"); - transformer.applyAdviceToMethod( - named("getFallbackObservable").and(returns(named("rx.Observable"))), - HystrixInstrumentationModule.class.getName() + "$FallbackAdvice"); - } - } - - public static class ExecuteAdvice { - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( - @Advice.This HystrixInvokableInfo command, - @Advice.Return(readOnly = false) Observable result, - @Advice.Thrown Throwable throwable) { - - result = Observable.create(new HystrixOnSubscribe<>(result, command, "execute")); - } - } - - public static class FallbackAdvice { - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( - @Advice.This HystrixInvokableInfo command, - @Advice.Return(readOnly = false) Observable result, - @Advice.Thrown Throwable throwable) { - - result = Observable.create(new HystrixOnSubscribe<>(result, command, "fallback")); - } - } - - public static class HystrixOnSubscribe extends TracedOnSubscribe { - private final HystrixInvokableInfo command; - private final String methodName; - - public HystrixOnSubscribe( - Observable originalObservable, HystrixInvokableInfo command, String methodName) { - super(originalObservable, OPERATION_NAME, tracer(), INTERNAL); - - this.command = command; - this.methodName = methodName; - } - - @Override - protected void decorateSpan(Span span) { - tracer().onCommand(span, command, methodName); - } - } } diff --git a/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixOnSubscribe.java b/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixOnSubscribe.java new file mode 100644 index 0000000000..27f20b166d --- /dev/null +++ b/instrumentation/hystrix-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hystrix/HystrixOnSubscribe.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hystrix; + +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; +import static io.opentelemetry.javaagent.instrumentation.hystrix.HystrixTracer.tracer; + +import com.netflix.hystrix.HystrixInvokableInfo; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.instrumentation.rxjava.TracedOnSubscribe; +import rx.Observable; + +public class HystrixOnSubscribe extends TracedOnSubscribe { + private static final String OPERATION_NAME = "hystrix.cmd"; + + private final HystrixInvokableInfo command; + private final String methodName; + + public HystrixOnSubscribe( + Observable originalObservable, HystrixInvokableInfo command, String methodName) { + super(originalObservable, OPERATION_NAME, tracer(), INTERNAL); + + this.command = command; + this.methodName = methodName; + } + + @Override + protected void decorateSpan(Span span) { + tracer().onCommand(span, command, methodName); + } +} diff --git a/instrumentation/internal/internal-eclipse-osgi-3.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/osgi/EclipseOsgiInstrumentation.java b/instrumentation/internal/internal-eclipse-osgi-3.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/osgi/EclipseOsgiInstrumentation.java new file mode 100644 index 0000000000..7540767da0 --- /dev/null +++ b/instrumentation/internal/internal-eclipse-osgi-3.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/osgi/EclipseOsgiInstrumentation.java @@ -0,0 +1,60 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.internal.osgi; + +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.internal.InClassLoaderMatcher; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * The ClassLoaderMatcher's call to ClassLoader.getResource() causes the Eclipse OSGi class loader + * to "dynamically import" a bundle for the package if such a bundle is not found, which can lead to + * application failure later on due to the bundle hierarchy no longer being "consistent". + * + *

Any side-effect of the ClassLoaderMatcher's call to ClassLoader.getResource() is generally + * undesirable, and so this instrumentation patches the behavior and suppresses the "dynamic import" + * of the missing package/bundle when the call is originating from ClassLoaderMatcher.. + */ +class EclipseOsgiInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.eclipse.osgi.internal.loader.BundleLoader"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("isDynamicallyImported")).and(returns(boolean.class)), + this.getClass().getName() + "$IsDynamicallyImportedAdvice"); + } + + public static class IsDynamicallyImportedAdvice { + + // "skipOn" is used to skip execution of the instrumented method when a ClassLoaderMatcher is + // currently executing, since we will be returning false regardless in onExit below + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class, suppress = Throwable.class) + public static boolean onEnter() { + return InClassLoaderMatcher.get(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.Return(readOnly = false) boolean result, + @Advice.Enter boolean inClassLoaderMatcher) { + if (inClassLoaderMatcher) { + result = false; + } + } + } +} diff --git a/instrumentation/internal/internal-eclipse-osgi-3.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/osgi/EclipseOsgiInstrumentationModule.java b/instrumentation/internal/internal-eclipse-osgi-3.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/osgi/EclipseOsgiInstrumentationModule.java index 8d1bfe83c6..806653591b 100644 --- a/instrumentation/internal/internal-eclipse-osgi-3.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/osgi/EclipseOsgiInstrumentationModule.java +++ b/instrumentation/internal/internal-eclipse-osgi-3.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/osgi/EclipseOsgiInstrumentationModule.java @@ -6,29 +6,12 @@ package io.opentelemetry.javaagent.instrumentation.internal.osgi; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.returns; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.api.internal.InClassLoaderMatcher; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -/** - * The ClassLoaderMatcher's call to ClassLoader.getResource() causes the Eclipse OSGi class loader - * to "dynamically import" a bundle for the package if such a bundle is not found, which can lead to - * application failure later on due to the bundle hierarchy no longer being "consistent". - * - *

Any side-effect of the ClassLoaderMatcher's call to ClassLoader.getResource() is generally - * undesirable, and so this instrumentation patches the behavior and suppresses the "dynamic import" - * of the missing package/bundle when the call is originating from ClassLoaderMatcher.. - */ @AutoService(InstrumentationModule.class) public class EclipseOsgiInstrumentationModule extends InstrumentationModule { public EclipseOsgiInstrumentationModule() { @@ -39,38 +22,4 @@ public class EclipseOsgiInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new EclipseOsgiInstrumentation()); } - - private static class EclipseOsgiInstrumentation implements TypeInstrumentation { - - @Override - public ElementMatcher typeMatcher() { - return named("org.eclipse.osgi.internal.loader.BundleLoader"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isMethod().and(named("isDynamicallyImported")).and(returns(boolean.class)), - EclipseOsgiInstrumentation.class.getName() + "$IsDynamicallyImportedAdvice"); - } - - public static class IsDynamicallyImportedAdvice { - - // "skipOn" is used to skip execution of the instrumented method when a ClassLoaderMatcher is - // currently executing, since we will be returning false regardless in onExit below - @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class, suppress = Throwable.class) - public static boolean onEnter() { - return InClassLoaderMatcher.get(); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit( - @Advice.Return(readOnly = false) boolean result, - @Advice.Enter boolean inClassLoaderMatcher) { - if (inClassLoaderMatcher) { - result = false; - } - } - } - } } diff --git a/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/ClientHandlerInstrumentation.java b/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/ClientHandlerInstrumentation.java new file mode 100644 index 0000000000..3055c68664 --- /dev/null +++ b/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/ClientHandlerInstrumentation.java @@ -0,0 +1,82 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v1_1; + +import static io.opentelemetry.instrumentation.api.tracer.HttpServerTracer.CONTEXT_ATTRIBUTE; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v1_1.JaxRsClientV1Tracer.tracer; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.sun.jersey.api.client.ClientRequest; +import com.sun.jersey.api.client.ClientResponse; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class ClientHandlerInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("com.sun.jersey.api.client.ClientHandler"); + } + + @Override + public ElementMatcher typeMatcher() { + return implementsInterface(named("com.sun.jersey.api.client.ClientHandler")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("handle") + .and(takesArgument(0, extendsClass(named("com.sun.jersey.api.client.ClientRequest")))) + .and(returns(extendsClass(named("com.sun.jersey.api.client.ClientResponse")))), + this.getClass().getName() + "$HandleAdvice"); + } + + public static class HandleAdvice { + + @Advice.OnMethodEnter + public static void onEnter( + @Advice.Argument(0) ClientRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + // WARNING: this might be a chain...so we only have to trace the first in the chain. + boolean isRootClientHandler = null == request.getProperties().get(CONTEXT_ATTRIBUTE); + Context parentContext = currentContext(); + if (isRootClientHandler && tracer().shouldStartSpan(parentContext)) { + context = tracer().startSpan(parentContext, request, request); + scope = context.makeCurrent(); + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.Return ClientResponse response, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + if (throwable != null) { + tracer().endExceptionally(context, throwable); + } else { + tracer().end(context, response); + } + } + } +} diff --git a/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/JaxRsClientInstrumentationModule.java b/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/JaxRsClientInstrumentationModule.java index 1d0ede60ba..86c731c99a 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/JaxRsClientInstrumentationModule.java +++ b/instrumentation/jaxrs-client/jaxrs-client-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v1_1/JaxRsClientInstrumentationModule.java @@ -5,29 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v1_1; -import static io.opentelemetry.instrumentation.api.tracer.HttpServerTracer.CONTEXT_ATTRIBUTE; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; -import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; -import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v1_1.JaxRsClientV1Tracer.tracer; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.returns; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import com.sun.jersey.api.client.ClientRequest; -import com.sun.jersey.api.client.ClientResponse; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class JaxRsClientInstrumentationModule extends InstrumentationModule { @@ -40,60 +23,4 @@ public class JaxRsClientInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new ClientHandlerInstrumentation()); } - - public static class ClientHandlerInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher classLoaderOptimization() { - return hasClassesNamed("com.sun.jersey.api.client.ClientHandler"); - } - - @Override - public ElementMatcher typeMatcher() { - return implementsInterface(named("com.sun.jersey.api.client.ClientHandler")); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("handle") - .and(takesArgument(0, extendsClass(named("com.sun.jersey.api.client.ClientRequest")))) - .and(returns(extendsClass(named("com.sun.jersey.api.client.ClientResponse")))), - JaxRsClientInstrumentationModule.class.getName() + "$HandleAdvice"); - } - } - - public static class HandleAdvice { - - @Advice.OnMethodEnter - public static void onEnter( - @Advice.Argument(0) ClientRequest request, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - // WARNING: this might be a chain...so we only have to trace the first in the chain. - boolean isRootClientHandler = null == request.getProperties().get(CONTEXT_ATTRIBUTE); - Context parentContext = currentContext(); - if (isRootClientHandler && tracer().shouldStartSpan(parentContext)) { - context = tracer().startSpan(parentContext, request, request); - scope = context.makeCurrent(); - } - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit( - @Advice.Return ClientResponse response, - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - if (scope == null) { - return; - } - - scope.close(); - if (throwable != null) { - tracer().endExceptionally(context, throwable); - } else { - tracer().end(context, response); - } - } - } } diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ClientBuilderInstrumentation.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ClientBuilderInstrumentation.java new file mode 100644 index 0000000000..30b7fff033 --- /dev/null +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/ClientBuilderInstrumentation.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import javax.ws.rs.client.Client; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; + +public class ClientBuilderInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("javax.ws.rs.client.ClientBuilder"); + } + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named("javax.ws.rs.client.ClientBuilder")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("build").and(returns(implementsInterface(named("javax.ws.rs.client.Client")))), + this.getClass().getName() + "$BuildAdvice"); + } + + public static class BuildAdvice { + + @Advice.OnMethodExit + public static void registerFeature( + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Client client) { + // Register on the generated client instead of the builder + // The build() can be called multiple times and is not thread safe + // A client is only created once + client.register(ClientTracingFeature.class); + } + } +} diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JaxRsClientInstrumentationModule.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JaxRsClientInstrumentationModule.java index e437592e9a..c51dd61637 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JaxRsClientInstrumentationModule.java +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JaxRsClientInstrumentationModule.java @@ -5,23 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.returns; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import javax.ws.rs.client.Client; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.implementation.bytecode.assign.Assigner; -import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class JaxRsClientInstrumentationModule extends InstrumentationModule { @@ -34,35 +23,4 @@ public class JaxRsClientInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new ClientBuilderInstrumentation()); } - - public static class ClientBuilderInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher classLoaderOptimization() { - return hasClassesNamed("javax.ws.rs.client.ClientBuilder"); - } - - @Override - public ElementMatcher typeMatcher() { - return extendsClass(named("javax.ws.rs.client.ClientBuilder")); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("build").and(returns(implementsInterface(named("javax.ws.rs.client.Client")))), - JaxRsClientInstrumentationModule.class.getName() + "$ClientBuilderAdvice"); - } - } - - public static class ClientBuilderAdvice { - - @Advice.OnMethodExit - public static void registerFeature( - @Advice.Return(typing = Assigner.Typing.DYNAMIC) Client client) { - // Register on the generated client instead of the builder - // The build() can be called multiple times and is not thread safe - // A client is only created once - client.register(ClientTracingFeature.class); - } - } } diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfAsyncClientConnectionErrorInstrumentation.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfAsyncClientConnectionErrorInstrumentation.java new file mode 100644 index 0000000000..1264121f36 --- /dev/null +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfAsyncClientConnectionErrorInstrumentation.java @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import java.util.Map; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.cxf.message.Message; + +public class CxfAsyncClientConnectionErrorInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.cxf.jaxrs.client.JaxrsClientCallback"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("handleException") + .and( + takesArgument(0, named(Map.class.getName())) + .and(takesArgument(1, named(Throwable.class.getName())))), + this.getClass().getName() + "$HandleExceptionAdvice"); + } + + public static class HandleExceptionAdvice { + + @Advice.OnMethodExit(suppress = Throwable.class) + public static void handleError( + @Advice.Argument(0) Map map, @Advice.Argument(1) Throwable throwable) { + if (throwable != null && map instanceof Message) { + CxfClientUtil.handleException((Message) map, throwable); + } + } + } +} diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfClientConnectionErrorInstrumentation.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfClientConnectionErrorInstrumentation.java new file mode 100644 index 0000000000..16e2f24206 --- /dev/null +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfClientConnectionErrorInstrumentation.java @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.cxf.message.Message; + +public class CxfClientConnectionErrorInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.cxf.jaxrs.client.AbstractClient"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("preProcessResult").and(takesArgument(0, named("org.apache.cxf.message.Message"))), + this.getClass().getName() + "$PreProcessResultAdvice"); + } + + public static class PreProcessResultAdvice { + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void handleError( + @Advice.Argument(0) Message message, @Advice.Thrown Throwable throwable) { + if (throwable != null) { + CxfClientUtil.handleException(message, throwable); + } + } + } +} diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfClientInstrumentationModule.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfClientInstrumentationModule.java index 8859050ae9..9b36cfc012 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfClientInstrumentationModule.java +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-cxf-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/CxfClientInstrumentationModule.java @@ -6,19 +6,11 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; import static java.util.Arrays.asList; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import java.util.Map; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import org.apache.cxf.message.Message; /** * JAX-RS Client API doesn't define a good point where we can handle connection failures, so we must @@ -37,57 +29,4 @@ public class CxfClientInstrumentationModule extends InstrumentationModule { new CxfClientConnectionErrorInstrumentation(), new CxfAsyncClientConnectionErrorInstrumentation()); } - - public static class CxfClientConnectionErrorInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("org.apache.cxf.jaxrs.client.AbstractClient"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("preProcessResult").and(takesArgument(0, named("org.apache.cxf.message.Message"))), - CxfClientInstrumentationModule.class.getName() + "$ErrorAdvice"); - } - } - - public static class CxfAsyncClientConnectionErrorInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("org.apache.cxf.jaxrs.client.JaxrsClientCallback"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("handleException") - .and( - takesArgument(0, named(Map.class.getName())) - .and(takesArgument(1, named(Throwable.class.getName())))), - CxfClientInstrumentationModule.class.getName() + "$AsyncErrorAdvice"); - } - } - - public static class ErrorAdvice { - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void handleError( - @Advice.Argument(0) Message message, @Advice.Thrown Throwable throwable) { - if (throwable != null) { - CxfClientUtil.handleException(message, throwable); - } - } - } - - public static class AsyncErrorAdvice { - - @Advice.OnMethodExit(suppress = Throwable.class) - public static void handleError( - @Advice.Argument(0) Map map, @Advice.Argument(1) Throwable throwable) { - if (throwable != null && map instanceof Message) { - CxfClientUtil.handleException((Message) map, throwable); - } - } - } } diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientConnectionErrorInstrumentation.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientConnectionErrorInstrumentation.java new file mode 100644 index 0000000000..b889f045e4 --- /dev/null +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientConnectionErrorInstrumentation.java @@ -0,0 +1,66 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; + +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; +import org.glassfish.jersey.client.ClientRequest; +import org.glassfish.jersey.client.OpenTelemetryResponseCallbackWrapper; + +public class JerseyClientConnectionErrorInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("org.glassfish.jersey.client.ClientRuntime"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod() + .and(isPublic()) + .and(named("invoke")) + .and(takesArgument(0, named("org.glassfish.jersey.client.ClientRequest"))), + this.getClass().getName() + "$InvokeAdvice"); + transformer.applyAdviceToMethod( + isMethod() + .and(named("submit").or(named("createRunnableForAsyncProcessing"))) + .and(takesArgument(0, named("org.glassfish.jersey.client.ClientRequest"))) + .and(takesArgument(1, named("org.glassfish.jersey.client.ResponseCallback"))), + this.getClass().getName() + "$SubmitAdvice"); + } + + public static class InvokeAdvice { + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void handleError( + @Advice.Argument(0) ClientRequest context, @Advice.Thrown Throwable throwable) { + if (throwable != null) { + JerseyClientUtil.handleException(context, throwable); + } + } + } + + public static class SubmitAdvice { + + // using dynamic typing because parameter type is package private + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void handleError( + @Advice.Argument(0) ClientRequest context, + @Advice.Argument(value = 1, readOnly = false, typing = Assigner.Typing.DYNAMIC) + Object callback) { + callback = OpenTelemetryResponseCallbackWrapper.wrap(context, callback); + } + } +} diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientInstrumentationModule.java b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientInstrumentationModule.java index 3f51b80d00..30cd390124 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientInstrumentationModule.java +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrsclient/v2_0/JerseyClientInstrumentationModule.java @@ -5,23 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static java.util.Collections.singletonList; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import java.util.Collections; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.implementation.bytecode.assign.Assigner; -import net.bytebuddy.matcher.ElementMatcher; -import org.glassfish.jersey.client.ClientRequest; -import org.glassfish.jersey.client.OpenTelemetryResponseCallbackWrapper; /** * JAX-RS Client API doesn't define a good point where we can handle connection failures, so we must @@ -41,52 +30,6 @@ public class JerseyClientInstrumentationModule extends InstrumentationModule { @Override public List typeInstrumentations() { - return Collections.singletonList(new JerseyClientConnectionErrorInstrumentation()); - } - - public static class JerseyClientConnectionErrorInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("org.glassfish.jersey.client.ClientRuntime"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isMethod() - .and(isPublic()) - .and(named("invoke")) - .and(takesArgument(0, named("org.glassfish.jersey.client.ClientRequest"))), - JerseyClientInstrumentationModule.class.getName() + "$InvokeAdvice"); - transformer.applyAdviceToMethod( - isMethod() - .and(named("submit").or(named("createRunnableForAsyncProcessing"))) - .and(takesArgument(0, named("org.glassfish.jersey.client.ClientRequest"))) - .and(takesArgument(1, named("org.glassfish.jersey.client.ResponseCallback"))), - JerseyClientInstrumentationModule.class.getName() + "$SubmitAdvice"); - } - } - - public static class InvokeAdvice { - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void handleError( - @Advice.Argument(0) ClientRequest context, @Advice.Thrown Throwable throwable) { - if (throwable != null) { - JerseyClientUtil.handleException(context, throwable); - } - } - } - - public static class SubmitAdvice { - - // using dynamic typing because parameter type is package private - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void handleError( - @Advice.Argument(0) ClientRequest context, - @Advice.Argument(value = 1, readOnly = false, typing = Assigner.Typing.DYNAMIC) - Object callback) { - callback = OpenTelemetryResponseCallbackWrapper.wrap(context, callback); - } + return singletonList(new JerseyClientConnectionErrorInstrumentation()); } } diff --git a/instrumentation/jetty/jetty-8.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/v8_0/Jetty8InstrumentationModule.java b/instrumentation/jetty/jetty-8.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/v8_0/Jetty8InstrumentationModule.java index e2dccfc76a..88b9106a9d 100644 --- a/instrumentation/jetty/jetty-8.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/v8_0/Jetty8InstrumentationModule.java +++ b/instrumentation/jetty/jetty-8.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/v8_0/Jetty8InstrumentationModule.java @@ -5,26 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.jetty.v8_0; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; - import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.api.ContextStore; -import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; -import io.opentelemetry.javaagent.instrumentation.api.concurrent.ExecutorInstrumentationUtils; -import io.opentelemetry.javaagent.instrumentation.api.concurrent.RunnableWrapper; -import io.opentelemetry.javaagent.instrumentation.api.concurrent.State; import io.opentelemetry.javaagent.instrumentation.jetty.common.JettyHandlerInstrumentation; import java.util.Arrays; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class Jetty8InstrumentationModule extends InstrumentationModule { @@ -41,42 +27,4 @@ public class Jetty8InstrumentationModule extends InstrumentationModule { Jetty8InstrumentationModule.class.getPackage().getName() + ".Jetty8HandlerAdvice"), new JettyQueuedThreadPoolInstrumentation()); } - - public static class JettyQueuedThreadPoolInstrumentation implements TypeInstrumentation { - - @Override - public ElementMatcher typeMatcher() { - return named("org.eclipse.jetty.util.thread.QueuedThreadPool"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("dispatch").and(takesArguments(1)).and(takesArgument(0, Runnable.class)), - Jetty8InstrumentationModule.class.getName() + "$SetExecuteRunnableStateAdvice"); - } - } - - public static class SetExecuteRunnableStateAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static State enterJobSubmit( - @Advice.Argument(value = 0, readOnly = false) Runnable task) { - Runnable newTask = RunnableWrapper.wrapIfNeeded(task); - if (ExecutorInstrumentationUtils.shouldAttachStateToTask(newTask)) { - task = newTask; - ContextStore contextStore = - InstrumentationContext.get(Runnable.class, State.class); - return ExecutorInstrumentationUtils.setupState( - contextStore, newTask, Java8BytecodeBridge.currentContext()); - } - return null; - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void exitJobSubmit( - @Advice.Enter State state, @Advice.Thrown Throwable throwable) { - ExecutorInstrumentationUtils.cleanUpOnMethodExit(state, throwable); - } - } } diff --git a/instrumentation/jetty/jetty-8.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/v8_0/JettyQueuedThreadPoolInstrumentation.java b/instrumentation/jetty/jetty-8.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/v8_0/JettyQueuedThreadPoolInstrumentation.java new file mode 100644 index 0000000000..0e17dad96a --- /dev/null +++ b/instrumentation/jetty/jetty-8.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/v8_0/JettyQueuedThreadPoolInstrumentation.java @@ -0,0 +1,60 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jetty.v8_0; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.ContextStore; +import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext; +import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; +import io.opentelemetry.javaagent.instrumentation.api.concurrent.ExecutorInstrumentationUtils; +import io.opentelemetry.javaagent.instrumentation.api.concurrent.RunnableWrapper; +import io.opentelemetry.javaagent.instrumentation.api.concurrent.State; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class JettyQueuedThreadPoolInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.eclipse.jetty.util.thread.QueuedThreadPool"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("dispatch").and(takesArguments(1)).and(takesArgument(0, Runnable.class)), + this.getClass().getName() + "$DispatchAdvice"); + } + + public static class DispatchAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static State enterJobSubmit( + @Advice.Argument(value = 0, readOnly = false) Runnable task) { + Runnable newTask = RunnableWrapper.wrapIfNeeded(task); + if (ExecutorInstrumentationUtils.shouldAttachStateToTask(newTask)) { + task = newTask; + ContextStore contextStore = + InstrumentationContext.get(Runnable.class, State.class); + return ExecutorInstrumentationUtils.setupState( + contextStore, newTask, Java8BytecodeBridge.currentContext()); + } + return null; + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void exitJobSubmit( + @Advice.Enter State state, @Advice.Thrown Throwable throwable) { + ExecutorInstrumentationUtils.cleanUpOnMethodExit(state, throwable); + } + } +} diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentation.java new file mode 100644 index 0000000000..b9acda4245 --- /dev/null +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentation.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import kotlin.coroutines.CoroutineContext; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class KotlinCoroutinesInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("kotlinx.coroutines.BuildersKt"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("launch") + .or(named("launch$default")) + .and(takesArgument(1, named("kotlin.coroutines.CoroutineContext"))), + this.getClass().getName() + "$LaunchAdvice"); + transformer.applyAdviceToMethod( + named("runBlocking") + .or(named("runBlocking$default")) + .and(takesArgument(0, named("kotlin.coroutines.CoroutineContext"))), + this.getClass().getName() + "$RunBlockingAdvice"); + } + + public static class LaunchAdvice { + @Advice.OnMethodEnter + public static void enter( + @Advice.Argument(value = 1, readOnly = false) CoroutineContext coroutineContext) { + coroutineContext = + KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); + } + } + + public static class RunBlockingAdvice { + @Advice.OnMethodEnter + public static void enter( + @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext) { + coroutineContext = + KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); + } + } +} diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java index 6997895439..c572763552 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java @@ -6,18 +6,11 @@ package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import kotlin.coroutines.CoroutineContext; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class KotlinCoroutinesInstrumentationModule extends InstrumentationModule { @@ -33,45 +26,6 @@ public class KotlinCoroutinesInstrumentationModule extends InstrumentationModule @Override public List typeInstrumentations() { - return singletonList(new CoroutineScopeLaunchInstrumentation()); - } - - public static class CoroutineScopeLaunchInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("kotlinx.coroutines.BuildersKt"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("launch") - .or(named("launch$default")) - .and(takesArgument(1, named("kotlin.coroutines.CoroutineContext"))), - KotlinCoroutinesInstrumentationModule.class.getName() + "$LaunchAdvice"); - transformer.applyAdviceToMethod( - named("runBlocking") - .or(named("runBlocking$default")) - .and(takesArgument(0, named("kotlin.coroutines.CoroutineContext"))), - KotlinCoroutinesInstrumentationModule.class.getName() + "$RunBlockingAdvice"); - } - } - - public static class LaunchAdvice { - @Advice.OnMethodEnter - public static void enter( - @Advice.Argument(value = 1, readOnly = false) CoroutineContext coroutineContext) { - coroutineContext = - KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); - } - } - - public static class RunBlockingAdvice { - @Advice.OnMethodEnter - public static void enter( - @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext) { - coroutineContext = - KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); - } + return singletonList(new KotlinCoroutinesInstrumentation()); } } diff --git a/instrumentation/kubernetes-client-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kubernetesclient/ApiClientInstrumentation.java b/instrumentation/kubernetes-client-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kubernetesclient/ApiClientInstrumentation.java new file mode 100644 index 0000000000..5b4b4d657c --- /dev/null +++ b/instrumentation/kubernetes-client-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kubernetesclient/ApiClientInstrumentation.java @@ -0,0 +1,116 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.kubernetesclient; + +import static io.opentelemetry.javaagent.instrumentation.kubernetesclient.KubernetesClientTracer.tracer; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import io.kubernetes.client.openapi.ApiCallback; +import io.kubernetes.client.openapi.ApiResponse; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import okhttp3.Call; +import okhttp3.Request; + +public class ApiClientInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("io.kubernetes.client.openapi.ApiClient"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isPublic().and(named("buildRequest")).and(takesArguments(10)), + this.getClass().getName() + "$BuildRequestAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(named("execute")) + .and(takesArguments(2)) + .and(takesArgument(0, named("okhttp3.Call"))), + this.getClass().getName() + "$ExecuteAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(named("executeAsync")) + .and(takesArguments(3)) + .and(takesArgument(0, named("okhttp3.Call"))) + .and(takesArgument(2, named("io.kubernetes.client.openapi.ApiCallback"))), + this.getClass().getName() + "$ExecuteAsyncAdvice"); + } + + public static class BuildRequestAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit(@Advice.Return(readOnly = false) Request request) { + Context parentContext = Java8BytecodeBridge.currentContext(); + if (!tracer().shouldStartSpan(parentContext)) { + return; + } + + Request.Builder requestWithPropagation = request.newBuilder(); + Context context = tracer().startSpan(parentContext, request, requestWithPropagation); + CurrentContextAndScope.set(parentContext, context); + request = requestWithPropagation.build(); + } + } + + public static class ExecuteAdvice { + @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class) + public static void onExit( + @Advice.Return ApiResponse response, @Advice.Thrown Throwable throwable) { + Context context = CurrentContextAndScope.removeAndClose(); + if (context == null) { + return; + } + if (throwable == null) { + tracer().end(context, response); + } else { + tracer().endExceptionally(context, response, throwable); + } + } + } + + public static class ExecuteAsyncAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(0) Call httpCall, + @Advice.Argument(value = 2, readOnly = false) ApiCallback callback, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + + CurrentContextAndScope current = CurrentContextAndScope.remove(); + if (current != null) { + context = current.getContext(); + scope = current.getScope(); + callback = new TracingApiCallback<>(callback, current.getParentContext(), context); + } + } + + @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class) + public static void onExit( + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + scope.close(); + + if (throwable != null) { + tracer().endExceptionally(context, throwable); + } + // else span will be ended in the TracingApiCallback + } + } +} diff --git a/instrumentation/kubernetes-client-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kubernetesclient/KubernetesClientInstrumentationModule.java b/instrumentation/kubernetes-client-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kubernetesclient/KubernetesClientInstrumentationModule.java index 641391e095..ea00adef7e 100644 --- a/instrumentation/kubernetes-client-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kubernetesclient/KubernetesClientInstrumentationModule.java +++ b/instrumentation/kubernetes-client-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kubernetesclient/KubernetesClientInstrumentationModule.java @@ -5,28 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.kubernetesclient; -import static io.opentelemetry.javaagent.instrumentation.kubernetesclient.KubernetesClientTracer.tracer; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import io.kubernetes.client.openapi.ApiCallback; -import io.kubernetes.client.openapi.ApiResponse; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import okhttp3.Call; -import okhttp3.Request; @AutoService(InstrumentationModule.class) public class KubernetesClientInstrumentationModule extends InstrumentationModule { @@ -39,95 +23,4 @@ public class KubernetesClientInstrumentationModule extends InstrumentationModule public List typeInstrumentations() { return singletonList(new ApiClientInstrumentation()); } - - public static class ApiClientInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("io.kubernetes.client.openapi.ApiClient"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isPublic().and(named("buildRequest")).and(takesArguments(10)), - KubernetesClientInstrumentationModule.class.getName() + "$BuildRequestAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(named("execute")) - .and(takesArguments(2)) - .and(takesArgument(0, named("okhttp3.Call"))), - KubernetesClientInstrumentationModule.class.getName() + "$ExecuteAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(named("executeAsync")) - .and(takesArguments(3)) - .and(takesArgument(0, named("okhttp3.Call"))) - .and(takesArgument(2, named("io.kubernetes.client.openapi.ApiCallback"))), - KubernetesClientInstrumentationModule.class.getName() + "$ExecuteAsyncAdvice"); - } - } - - public static class BuildRequestAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - public static void onExit(@Advice.Return(readOnly = false) Request request) { - Context parentContext = Java8BytecodeBridge.currentContext(); - if (!tracer().shouldStartSpan(parentContext)) { - return; - } - - Request.Builder requestWithPropagation = request.newBuilder(); - Context context = tracer().startSpan(parentContext, request, requestWithPropagation); - CurrentContextAndScope.set(parentContext, context); - request = requestWithPropagation.build(); - } - } - - public static class ExecuteAdvice { - @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class) - public static void onExit( - @Advice.Return ApiResponse response, @Advice.Thrown Throwable throwable) { - Context context = CurrentContextAndScope.removeAndClose(); - if (context == null) { - return; - } - if (throwable == null) { - tracer().end(context, response); - } else { - tracer().endExceptionally(context, response, throwable); - } - } - } - - public static class ExecuteAsyncAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) Call httpCall, - @Advice.Argument(value = 2, readOnly = false) ApiCallback callback, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - - CurrentContextAndScope current = CurrentContextAndScope.remove(); - if (current != null) { - context = current.getContext(); - scope = current.getScope(); - callback = new TracingApiCallback<>(callback, current.getParentContext(), context); - } - } - - @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class) - public static void onExit( - @Advice.Thrown Throwable throwable, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - if (scope == null) { - return; - } - scope.close(); - - if (throwable != null) { - tracer().endExceptionally(context, throwable); - } - // else span will be ended in the TracingApiCallback - } - } } diff --git a/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/DefaultClientResourcesInstrumentation.java b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/DefaultClientResourcesInstrumentation.java new file mode 100644 index 0000000000..33fd9f268f --- /dev/null +++ b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/DefaultClientResourcesInstrumentation.java @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.lettuce.v5_1; + +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.lettuce.core.resource.DefaultClientResources; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class DefaultClientResourcesInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("io.lettuce.core.resource.DefaultClientResources"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(isPublic()).and(isStatic()).and(named("builder")), + this.getClass().getName() + "$BuilderAdvice"); + } + + public static class BuilderAdvice { + + @Advice.OnMethodExit(suppress = Throwable.class) + public static void methodEnter(@Advice.Return DefaultClientResources.Builder builder) { + builder.tracing(TracingHolder.TRACING); + } + } +} diff --git a/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceInstrumentationModule.java b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceInstrumentationModule.java index e0cef2efae..c790c386cb 100644 --- a/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceInstrumentationModule.java +++ b/instrumentation/lettuce/lettuce-5.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_1/LettuceInstrumentationModule.java @@ -7,19 +7,11 @@ package io.opentelemetry.javaagent.instrumentation.lettuce.v5_1; import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.isStatic; -import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; -import io.lettuce.core.resource.DefaultClientResources; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) @@ -38,26 +30,4 @@ public class LettuceInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new DefaultClientResourcesInstrumentation()); } - - public static class DefaultClientResourcesInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("io.lettuce.core.resource.DefaultClientResources"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isMethod().and(isPublic()).and(isStatic()).and(named("builder")), - LettuceInstrumentationModule.class.getName() + "$DefaultClientResourcesAdvice"); - } - } - - public static class DefaultClientResourcesAdvice { - - @Advice.OnMethodExit(suppress = Throwable.class) - public static void methodEnter(@Advice.Return DefaultClientResources.Builder builder) { - builder.tracing(TracingHolder.TRACING); - } - } } diff --git a/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyHandleRequestAdvice.java b/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyHandleRequestAdvice.java deleted file mode 100644 index 123f69cd1c..0000000000 --- a/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyHandleRequestAdvice.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.liberty; - -import static io.opentelemetry.javaagent.instrumentation.liberty.LibertyHttpServerTracer.tracer; - -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import io.opentelemetry.javaagent.instrumentation.servlet.common.service.ServletAndFilterAdviceHelper; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.bytebuddy.asm.Advice; - -@SuppressWarnings("unused") -public class LibertyHandleRequestAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0) ServletRequest request, - @Advice.Argument(value = 1) ServletResponse response) { - - if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { - return; - } - - HttpServletRequest httpServletRequest = (HttpServletRequest) request; - // it is a bit too early to start span at this point because calling - // some methods on HttpServletRequest will give a NPE - // just remember the request and use it a bit later to start the span - ThreadLocalContext.startRequest(httpServletRequest, (HttpServletResponse) response); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( - @Advice.Argument(0) ServletRequest servletRequest, - @Advice.Argument(1) ServletResponse servletResponse, - @Advice.Thrown Throwable throwable) { - ThreadLocalContext ctx = ThreadLocalContext.endRequest(); - if (ctx == null) { - return; - } - - Context context = ctx.getContext(); - Scope scope = ctx.getScope(); - if (scope == null) { - return; - } - scope.close(); - - if (context == null) { - // an existing span was found - return; - } - - HttpServletRequest request = (HttpServletRequest) servletRequest; - HttpServletResponse response = (HttpServletResponse) servletResponse; - - tracer().setPrincipal(context, request); - - if (throwable != null) { - tracer().endExceptionally(context, throwable, response); - return; - } - - if (ServletAndFilterAdviceHelper.mustEndOnHandlerMethodExit(tracer(), request)) { - tracer().end(context, response); - } - } -} diff --git a/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyInstrumentationModule.java b/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyInstrumentationModule.java index 281e8766e6..cb9b0b100f 100644 --- a/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyInstrumentationModule.java +++ b/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyInstrumentationModule.java @@ -6,26 +6,23 @@ package io.opentelemetry.javaagent.instrumentation.liberty; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; /** * Instrumenting request handling in Liberty. * *

    - *
  • On entry to WebApp.handleRequest remember request. {@link LibertyHandleRequestAdvice} + *
  • On entry to WebApp.handleRequest remember request. {@link + * LibertyWebAppInstrumentation.HandleRequestAdvice} *
  • On call to WebApp.isForbidden (called from WebApp.handleRequest) start span based on * remembered request. We don't start span immediately at the start or handleRequest because - * HttpServletRequest isn't usable yet. {@link LibertyStartSpanAdvice} - *
  • On exit from WebApp.handleRequest close the span. {@link LibertyHandleRequestAdvice} + * HttpServletRequest isn't usable yet. {@link LibertyWebAppInstrumentation.IsForbiddenAdvice} + *
  • On exit from WebApp.handleRequest close the span. {@link + * LibertyWebAppInstrumentation.HandleRequestAdvice} *
*/ @AutoService(InstrumentationModule.class) @@ -37,30 +34,6 @@ public class LibertyInstrumentationModule extends InstrumentationModule { @Override public List typeInstrumentations() { - return singletonList(new WebAppInstrumentation()); - } - - public static class WebAppInstrumentation implements TypeInstrumentation { - - @Override - public ElementMatcher typeMatcher() { - return named("com.ibm.ws.webcontainer.webapp.WebApp"); - } - - @Override - public void transform(TypeTransformer transformer) { - // https://github.com/OpenLiberty/open-liberty/blob/master/dev/com.ibm.ws.webcontainer/src/com/ibm/ws/webcontainer/webapp/WebApp.java - transformer.applyAdviceToMethod( - named("handleRequest") - .and(takesArgument(0, named("javax.servlet.ServletRequest"))) - .and(takesArgument(1, named("javax.servlet.ServletResponse"))) - .and(takesArgument(2, named("com.ibm.wsspi.http.HttpInboundConnection"))), - LibertyHandleRequestAdvice.class.getName()); - - // isForbidden is called from handleRequest - transformer.applyAdviceToMethod( - named("isForbidden").and(takesArgument(0, named(String.class.getName()))), - LibertyStartSpanAdvice.class.getName()); - } + return singletonList(new LibertyWebAppInstrumentation()); } } diff --git a/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyStartSpanAdvice.java b/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyStartSpanAdvice.java deleted file mode 100644 index 017a528342..0000000000 --- a/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyStartSpanAdvice.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.liberty; - -import static io.opentelemetry.javaagent.instrumentation.liberty.LibertyHttpServerTracer.tracer; - -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import net.bytebuddy.asm.Advice; - -@SuppressWarnings("unused") -public class LibertyStartSpanAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter() { - ThreadLocalContext ctx = ThreadLocalContext.get(); - if (ctx == null || !ctx.startSpan()) { - return; - } - - Context context = tracer().startSpan(ctx.getRequest()); - Scope scope = context.makeCurrent(); - - ctx.setContext(context); - ctx.setScope(scope); - - // Must be set here since Liberty RequestProcessors can use startAsync outside of servlet scope. - tracer().setAsyncListenerResponse(ctx.getRequest(), ctx.getResponse()); - } -} diff --git a/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyWebAppInstrumentation.java b/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyWebAppInstrumentation.java new file mode 100644 index 0000000000..437874aac1 --- /dev/null +++ b/instrumentation/liberty/liberty/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/liberty/LibertyWebAppInstrumentation.java @@ -0,0 +1,126 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.liberty; + +import static io.opentelemetry.javaagent.instrumentation.liberty.LibertyHttpServerTracer.tracer; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.servlet.common.service.ServletAndFilterAdviceHelper; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class LibertyWebAppInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.ibm.ws.webcontainer.webapp.WebApp"); + } + + @Override + public void transform(TypeTransformer transformer) { + // https://github.com/OpenLiberty/open-liberty/blob/master/dev/com.ibm.ws.webcontainer/src/com/ibm/ws/webcontainer/webapp/WebApp.java + transformer.applyAdviceToMethod( + named("handleRequest") + .and(takesArgument(0, named("javax.servlet.ServletRequest"))) + .and(takesArgument(1, named("javax.servlet.ServletResponse"))) + .and(takesArgument(2, named("com.ibm.wsspi.http.HttpInboundConnection"))), + this.getClass().getName() + "$HandleRequestAdvice"); + + // isForbidden is called from handleRequest + transformer.applyAdviceToMethod( + named("isForbidden").and(takesArgument(0, named(String.class.getName()))), + this.getClass().getName() + "$IsForbiddenAdvice"); + } + + @SuppressWarnings("unused") + public static class HandleRequestAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0) ServletRequest request, + @Advice.Argument(value = 1) ServletResponse response) { + + if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { + return; + } + + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + // it is a bit too early to start span at this point because calling + // some methods on HttpServletRequest will give a NPE + // just remember the request and use it a bit later to start the span + ThreadLocalContext.startRequest(httpServletRequest, (HttpServletResponse) response); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Argument(0) ServletRequest servletRequest, + @Advice.Argument(1) ServletResponse servletResponse, + @Advice.Thrown Throwable throwable) { + ThreadLocalContext ctx = ThreadLocalContext.endRequest(); + if (ctx == null) { + return; + } + + Context context = ctx.getContext(); + Scope scope = ctx.getScope(); + if (scope == null) { + return; + } + scope.close(); + + if (context == null) { + // an existing span was found + return; + } + + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + tracer().setPrincipal(context, request); + + if (throwable != null) { + tracer().endExceptionally(context, throwable, response); + return; + } + + if (ServletAndFilterAdviceHelper.mustEndOnHandlerMethodExit(tracer(), request)) { + tracer().end(context, response); + } + } + } + + @SuppressWarnings("unused") + public static class IsForbiddenAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter() { + ThreadLocalContext ctx = ThreadLocalContext.get(); + if (ctx == null || !ctx.startSpan()) { + return; + } + + Context context = tracer().startSpan(ctx.getRequest()); + Scope scope = context.makeCurrent(); + + ctx.setContext(context); + ctx.setScope(scope); + + // Must be set here since Liberty RequestProcessors can use startAsync outside of servlet + // scope. + tracer().setAsyncListenerResponse(ctx.getRequest(), ctx.getResponse()); + } + } +} diff --git a/instrumentation/log4j/log4j-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/v2_7/ContextDataInjectorFactoryInstrumentation.java b/instrumentation/log4j/log4j-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/v2_7/ContextDataInjectorFactoryInstrumentation.java new file mode 100644 index 0000000000..a3872a20fd --- /dev/null +++ b/instrumentation/log4j/log4j-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/v2_7/ContextDataInjectorFactoryInstrumentation.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.log4j.v2_7; + +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.logging.log4j.core.ContextDataInjector; + +public class ContextDataInjectorFactoryInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.logging.log4j.core.impl.ContextDataInjectorFactory"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod() + .and(isPublic()) + .and(isStatic()) + .and(named("createInjector")) + .and(returns(named("org.apache.logging.log4j.core.ContextDataInjector"))), + this.getClass().getName() + "$CreateInjectorAdvice"); + } + + public static class CreateInjectorAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit( + @Advice.Return(typing = Assigner.Typing.DYNAMIC, readOnly = false) + ContextDataInjector injector) { + injector = new SpanDecoratingContextDataInjector(injector); + } + } +} diff --git a/instrumentation/log4j/log4j-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/v2_7/Log4j27InstrumentationModule.java b/instrumentation/log4j/log4j-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/v2_7/Log4j27InstrumentationModule.java index 6006a4b675..9ba59a79f0 100644 --- a/instrumentation/log4j/log4j-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/v2_7/Log4j27InstrumentationModule.java +++ b/instrumentation/log4j/log4j-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/v2_7/Log4j27InstrumentationModule.java @@ -7,23 +7,13 @@ package io.opentelemetry.javaagent.instrumentation.log4j.v2_7; import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.isStatic; -import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; -import static net.bytebuddy.matcher.ElementMatchers.returns; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.implementation.bytecode.assign.Assigner.Typing; import net.bytebuddy.matcher.ElementMatcher; -import org.apache.logging.log4j.core.ContextDataInjector; @AutoService(InstrumentationModule.class) public class Log4j27InstrumentationModule extends InstrumentationModule { @@ -41,30 +31,4 @@ public class Log4j27InstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new ContextDataInjectorFactoryInstrumentation()); } - - public static class ContextDataInjectorFactoryInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("org.apache.logging.log4j.core.impl.ContextDataInjectorFactory"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isMethod() - .and(isPublic()) - .and(isStatic()) - .and(named("createInjector")) - .and(returns(named("org.apache.logging.log4j.core.ContextDataInjector"))), - Log4j27InstrumentationModule.class.getName() + "$CreateInjectorAdvice"); - } - } - - public static class CreateInjectorAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - public static void onExit( - @Advice.Return(typing = Typing.DYNAMIC, readOnly = false) ContextDataInjector injector) { - injector = new SpanDecoratingContextDataInjector(injector); - } - } } diff --git a/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/OkHttp2InstrumentationModule.java b/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/OkHttp2InstrumentationModule.java index 98c755bbbe..6a7a0b1413 100644 --- a/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/OkHttp2InstrumentationModule.java +++ b/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/OkHttp2InstrumentationModule.java @@ -6,19 +6,11 @@ package io.opentelemetry.javaagent.instrumentation.okhttp.v2_2; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; -import com.squareup.okhttp.Interceptor; -import com.squareup.okhttp.OkHttpClient; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class OkHttp2InstrumentationModule extends InstrumentationModule { @@ -30,30 +22,4 @@ public class OkHttp2InstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new OkHttpClientInstrumentation()); } - - public static class OkHttpClientInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("com.squareup.okhttp.OkHttpClient"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isConstructor(), OkHttp2InstrumentationModule.class.getName() + "$OkHttp2ClientAdvice"); - } - } - - public static class OkHttp2ClientAdvice { - @Advice.OnMethodExit - public static void addTracingInterceptor(@Advice.This OkHttpClient client) { - for (Interceptor interceptor : client.interceptors()) { - if (interceptor instanceof TracingInterceptor) { - return; - } - } - - client.interceptors().add(new TracingInterceptor()); - } - } } diff --git a/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/OkHttpClientInstrumentation.java b/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/OkHttpClientInstrumentation.java new file mode 100644 index 0000000000..c5bd8d00c8 --- /dev/null +++ b/instrumentation/okhttp/okhttp-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v2_2/OkHttpClientInstrumentation.java @@ -0,0 +1,43 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.okhttp.v2_2; + +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.OkHttpClient; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class OkHttpClientInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("com.squareup.okhttp.OkHttpClient"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor(), this.getClass().getName() + "$ConstructorAdvice"); + } + + public static class ConstructorAdvice { + @Advice.OnMethodExit + public static void addTracingInterceptor(@Advice.This OkHttpClient client) { + for (Interceptor interceptor : client.interceptors()) { + if (interceptor instanceof TracingInterceptor) { + return; + } + } + + client.interceptors().add(new TracingInterceptor()); + } + } +} diff --git a/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3Instrumentation.java b/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3Instrumentation.java new file mode 100644 index 0000000000..ab0810c88d --- /dev/null +++ b/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3Instrumentation.java @@ -0,0 +1,52 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.okhttp.v3_0; + +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import okhttp3.OkHttpClient; + +public class OkHttp3Instrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("okhttp3.OkHttpClient$Builder"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor(), this.getClass().getName() + "$ConstructorAdvice"); + } + + public static class ConstructorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void trackCallDepth(@Advice.Local("callDepth") int callDepth) { + callDepth = CallDepthThreadLocalMap.incrementCallDepth(OkHttpClient.Builder.class); + } + + @Advice.OnMethodExit(suppress = Throwable.class) + public static void addTracingInterceptor( + @Advice.This OkHttpClient.Builder builder, @Advice.Local("callDepth") int callDepth) { + // No-args constructor is automatically called by constructors with args, but we only want to + // run once from the constructor with args because that is where the dedupe needs to happen. + if (callDepth > 0) { + return; + } + CallDepthThreadLocalMap.reset(OkHttpClient.Builder.class); + if (builder.interceptors().contains(OkHttp3Interceptors.TRACING_INTERCEPTOR)) { + return; + } + builder.addInterceptor(OkHttp3Interceptors.TRACING_INTERCEPTOR); + } + } +} diff --git a/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3InstrumentationModule.java b/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3InstrumentationModule.java index 987fb54f37..a28865a436 100644 --- a/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3InstrumentationModule.java +++ b/instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3InstrumentationModule.java @@ -6,19 +6,11 @@ package io.opentelemetry.javaagent.instrumentation.okhttp.v3_0; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import okhttp3.OkHttpClient; @AutoService(InstrumentationModule.class) public class OkHttp3InstrumentationModule extends InstrumentationModule { @@ -29,41 +21,6 @@ public class OkHttp3InstrumentationModule extends InstrumentationModule { @Override public List typeInstrumentations() { - return singletonList(new OkHttpClientInstrumentation()); - } - - public static class OkHttpClientInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("okhttp3.OkHttpClient$Builder"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isConstructor(), OkHttp3InstrumentationModule.class.getName() + "$OkHttp3Advice"); - } - } - - public static class OkHttp3Advice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void trackCallDepth(@Advice.Local("callDepth") int callDepth) { - callDepth = CallDepthThreadLocalMap.incrementCallDepth(OkHttpClient.Builder.class); - } - - @Advice.OnMethodExit(suppress = Throwable.class) - public static void addTracingInterceptor( - @Advice.This OkHttpClient.Builder builder, @Advice.Local("callDepth") int callDepth) { - // No-args constructor is automatically called by constructors with args, but we only want to - // run once from the constructor with args because that is where the dedupe needs to happen. - if (callDepth > 0) { - return; - } - CallDepthThreadLocalMap.reset(OkHttpClient.Builder.class); - if (builder.interceptors().contains(OkHttp3Interceptors.TRACING_INTERCEPTOR)) { - return; - } - builder.addInterceptor(OkHttp3Interceptors.TRACING_INTERCEPTOR); - } + return singletonList(new OkHttp3Instrumentation()); } } diff --git a/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/OshiInstrumentationModule.java b/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/OshiInstrumentationModule.java index 8b3f650f47..c600460d9b 100644 --- a/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/OshiInstrumentationModule.java +++ b/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/OshiInstrumentationModule.java @@ -5,22 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.oshi; -import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.isStatic; -import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; -import io.opentelemetry.instrumentation.oshi.SystemMetrics; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class OshiInstrumentationModule extends InstrumentationModule { @@ -33,30 +23,4 @@ public class OshiInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new SystemInfoInstrumentation()); } - - public static class SystemInfoInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher classLoaderOptimization() { - return hasClassesNamed("oshi.SystemInfo"); - } - - @Override - public ElementMatcher typeMatcher() { - return named("oshi.SystemInfo"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isMethod().and(isPublic()).and(isStatic()).and(named("getCurrentPlatformEnum")), - OshiInstrumentationModule.class.getName() + "$OshiInstrumentationAdvice"); - } - } - - public static class OshiInstrumentationAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter() { - SystemMetrics.registerObservers(); - } - } } diff --git a/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/SystemInfoInstrumentation.java b/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/SystemInfoInstrumentation.java new file mode 100644 index 0000000000..0844498357 --- /dev/null +++ b/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/SystemInfoInstrumentation.java @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.oshi; + +import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.instrumentation.oshi.SystemMetrics; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class SystemInfoInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("oshi.SystemInfo"); + } + + @Override + public ElementMatcher typeMatcher() { + return named("oshi.SystemInfo"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(isPublic()).and(isStatic()).and(named("getCurrentPlatformEnum")), + this.getClass().getName() + "$GetCurrentPlatformEnumAdvice"); + } + + public static class GetCurrentPlatformEnumAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter() { + SystemMetrics.registerObservers(); + } + } +} diff --git a/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/ActionInstrumentation.java b/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/ActionInstrumentation.java new file mode 100644 index 0000000000..b192e5045f --- /dev/null +++ b/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/ActionInstrumentation.java @@ -0,0 +1,92 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.play.v2_4; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; +import static io.opentelemetry.javaagent.instrumentation.play.v2_4.PlayTracer.tracer; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.tracer.ServerSpan; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import play.api.mvc.Action; +import play.api.mvc.Headers; +import play.api.mvc.Request; +import play.api.mvc.Result; +import scala.concurrent.Future; + +public class ActionInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("play.api.mvc.Action"); + } + + @Override + public ElementMatcher typeMatcher() { + return implementsInterface(named("play.api.mvc.Action")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("apply") + .and(takesArgument(0, named("play.api.mvc.Request"))) + .and(returns(named("scala.concurrent.Future"))), + this.getClass().getName() + "$ApplyAdvice"); + } + + public static class ApplyAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(0) Request req, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + context = tracer().startSpan("play.request", SpanKind.INTERNAL); + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopTraceOnResponse( + @Advice.This Object thisAction, + @Advice.Thrown Throwable throwable, + @Advice.Argument(0) Request req, + @Advice.Return(readOnly = false) Future responseFuture, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + // Call onRequest on return after tags are populated. + tracer().updateSpanName(Java8BytecodeBridge.spanFromContext(context), req); + // set the span name on the upstream akka/netty span + tracer().updateSpanName(ServerSpan.fromContextOrNull(context), req); + + scope.close(); + // span finished in RequestCompleteCallback + if (throwable == null) { + responseFuture.onComplete( + new RequestCompleteCallback(context), ((Action) thisAction).executionContext()); + } else { + tracer().endExceptionally(context, throwable); + } + } + + // Unused method for muzzle + public static void muzzleCheck(Headers headers) { + // This distinguishes between 2.3 and 2.4, excluding the former + headers.get("aKey"); + // system() method was removed in 2.6, so this line prevents from applying in play 2.6 + play.libs.Akka.system(); + } + } +} diff --git a/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayAdvice.java b/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayAdvice.java deleted file mode 100644 index 11acd7c138..0000000000 --- a/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayAdvice.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.play.v2_4; - -import static io.opentelemetry.javaagent.instrumentation.play.v2_4.PlayTracer.tracer; - -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.tracer.ServerSpan; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; -import net.bytebuddy.asm.Advice; -import play.api.mvc.Action; -import play.api.mvc.Headers; -import play.api.mvc.Request; -import play.api.mvc.Result; -import scala.concurrent.Future; - -public class PlayAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) Request req, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - context = tracer().startSpan("play.request", SpanKind.INTERNAL); - scope = context.makeCurrent(); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopTraceOnResponse( - @Advice.This Object thisAction, - @Advice.Thrown Throwable throwable, - @Advice.Argument(0) Request req, - @Advice.Return(readOnly = false) Future responseFuture, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - // Call onRequest on return after tags are populated. - tracer().updateSpanName(Java8BytecodeBridge.spanFromContext(context), req); - // set the span name on the upstream akka/netty span - tracer().updateSpanName(ServerSpan.fromContextOrNull(context), req); - - scope.close(); - // span finished in RequestCompleteCallback - if (throwable == null) { - responseFuture.onComplete( - new RequestCompleteCallback(context), ((Action) thisAction).executionContext()); - } else { - tracer().endExceptionally(context, throwable); - } - } - - // Unused method for muzzle - public static void muzzleCheck(Headers headers) { - // This distinguishes between 2.3 and 2.4, excluding the former - headers.get("aKey"); - // system() method was removed in 2.6, so this line prevents from applying in play 2.6 - play.libs.Akka.system(); - } -} diff --git a/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayInstrumentationModule.java b/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayInstrumentationModule.java index 70d45ed348..ff2e7b5b83 100644 --- a/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayInstrumentationModule.java +++ b/instrumentation/play/play-2.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_4/PlayInstrumentationModule.java @@ -5,20 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.play.v2_4; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.returns; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class PlayInstrumentationModule extends InstrumentationModule { @@ -31,25 +23,4 @@ public class PlayInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new ActionInstrumentation()); } - - public static class ActionInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher classLoaderOptimization() { - return hasClassesNamed("play.api.mvc.Action"); - } - - @Override - public ElementMatcher typeMatcher() { - return implementsInterface(named("play.api.mvc.Action")); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("apply") - .and(takesArgument(0, named("play.api.mvc.Request"))) - .and(returns(named("scala.concurrent.Future"))), - PlayAdvice.class.getName()); - } - } } diff --git a/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/ActionInstrumentation.java b/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/ActionInstrumentation.java new file mode 100644 index 0000000000..fc884d2c91 --- /dev/null +++ b/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/ActionInstrumentation.java @@ -0,0 +1,83 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.play.v2_6; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; +import static io.opentelemetry.javaagent.instrumentation.play.v2_6.PlayTracer.tracer; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.tracer.ServerSpan; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import play.api.mvc.Action; +import play.api.mvc.Request; +import play.api.mvc.Result; +import scala.concurrent.Future; + +public class ActionInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("play.api.mvc.Action"); + } + + @Override + public ElementMatcher typeMatcher() { + return implementsInterface(named("play.api.mvc.Action")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("apply") + .and(takesArgument(0, named("play.api.mvc.Request"))) + .and(returns(named("scala.concurrent.Future"))), + this.getClass().getName() + "$ApplyAdvice"); + } + + public static class ApplyAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(0) Request req, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + context = tracer().startSpan("play.request", SpanKind.INTERNAL); + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopTraceOnResponse( + @Advice.This Object thisAction, + @Advice.Thrown Throwable throwable, + @Advice.Argument(0) Request req, + @Advice.Return(readOnly = false) Future responseFuture, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + // Call onRequest on return after tags are populated. + tracer().updateSpanName(Java8BytecodeBridge.spanFromContext(context), req); + // set the span name on the upstream akka/netty span + tracer().updateSpanName(ServerSpan.fromContextOrNull(context), req); + + scope.close(); + // span finished in RequestCompleteCallback + if (throwable == null) { + responseFuture.onComplete( + new RequestCompleteCallback(context), ((Action) thisAction).executionContext()); + } else { + tracer().endExceptionally(context, throwable); + } + } + } +} diff --git a/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayAdvice.java b/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayAdvice.java deleted file mode 100644 index d644e5a8e7..0000000000 --- a/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayAdvice.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.play.v2_6; - -import static io.opentelemetry.javaagent.instrumentation.play.v2_6.PlayTracer.tracer; - -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.tracer.ServerSpan; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; -import net.bytebuddy.asm.Advice; -import play.api.mvc.Action; -import play.api.mvc.Request; -import play.api.mvc.Result; -import scala.concurrent.Future; - -public class PlayAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) Request req, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - context = tracer().startSpan("play.request", SpanKind.INTERNAL); - scope = context.makeCurrent(); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopTraceOnResponse( - @Advice.This Object thisAction, - @Advice.Thrown Throwable throwable, - @Advice.Argument(0) Request req, - @Advice.Return(readOnly = false) Future responseFuture, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - // Call onRequest on return after tags are populated. - tracer().updateSpanName(Java8BytecodeBridge.spanFromContext(context), req); - // set the span name on the upstream akka/netty span - tracer().updateSpanName(ServerSpan.fromContextOrNull(context), req); - - scope.close(); - // span finished in RequestCompleteCallback - if (throwable == null) { - responseFuture.onComplete( - new RequestCompleteCallback(context), ((Action) thisAction).executionContext()); - } else { - tracer().endExceptionally(context, throwable); - } - } -} diff --git a/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayInstrumentationModule.java b/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayInstrumentationModule.java index cbf62c17ae..2bbcbbb7de 100644 --- a/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayInstrumentationModule.java +++ b/instrumentation/play/play-2.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/play/v2_6/PlayInstrumentationModule.java @@ -5,20 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.play.v2_6; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.returns; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class PlayInstrumentationModule extends InstrumentationModule { @@ -31,25 +23,4 @@ public class PlayInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new ActionInstrumentation()); } - - public static class ActionInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher classLoaderOptimization() { - return hasClassesNamed("play.api.mvc.Action"); - } - - @Override - public ElementMatcher typeMatcher() { - return implementsInterface(named("play.api.mvc.Action")); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - named("apply") - .and(takesArgument(0, named("play.api.mvc.Request"))) - .and(returns(named("scala.concurrent.Future"))), - PlayAdvice.class.getName()); - } - } } diff --git a/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/HooksInstrumentation.java b/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/HooksInstrumentation.java new file mode 100644 index 0000000000..425f6b3552 --- /dev/null +++ b/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/HooksInstrumentation.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactor; + +import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.instrumentation.reactor.TracingOperator; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class HooksInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("reactor.core.publisher.Hooks"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isTypeInitializer().or(named("resetOnEachOperator")), + this.getClass().getName() + "$ResetOnEachOperatorAdvice"); + } + + public static class ResetOnEachOperatorAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void postStaticInitializer() { + TracingOperator.registerOnEachOperator(); + } + } +} diff --git a/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/ReactorHooksAdvice.java b/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/ReactorHooksAdvice.java deleted file mode 100644 index 9caa5e8e66..0000000000 --- a/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/ReactorHooksAdvice.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.reactor; - -import io.opentelemetry.instrumentation.reactor.TracingOperator; -import net.bytebuddy.asm.Advice; - -public class ReactorHooksAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - public static void postStaticInitializer() { - TracingOperator.registerOnEachOperator(); - } -} diff --git a/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/ReactorInstrumentationModule.java b/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/ReactorInstrumentationModule.java index a181aa41fa..2c39d17186 100644 --- a/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/ReactorInstrumentationModule.java +++ b/instrumentation/reactor-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactor/ReactorInstrumentationModule.java @@ -6,16 +6,11 @@ package io.opentelemetry.javaagent.instrumentation.reactor; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer; -import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class ReactorInstrumentationModule extends InstrumentationModule { @@ -28,17 +23,4 @@ public class ReactorInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new HooksInstrumentation()); } - - public static class HooksInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("reactor.core.publisher.Hooks"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isTypeInitializer().or(named("resetOnEachOperator")), ReactorHooksAdvice.class.getName()); - } - } } diff --git a/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/DecoratorFunctions.java b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/DecoratorFunctions.java index 576983d11d..c3d92beaee 100644 --- a/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/DecoratorFunctions.java +++ b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/DecoratorFunctions.java @@ -136,8 +136,7 @@ public final class DecoratorFunctions { } } // otherwise use the parent span context - return reactorContext.getOrDefault( - ReactorNettyInstrumentationModule.MapConnect.CONTEXT_ATTRIBUTE, null); + return reactorContext.getOrDefault(MapConnect.CONTEXT_ATTRIBUTE, null); } private DecoratorFunctions() {} diff --git a/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/HttpClientInstrumentation.java b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/HttpClientInstrumentation.java new file mode 100644 index 0000000000..89eff80be8 --- /dev/null +++ b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/HttpClientInstrumentation.java @@ -0,0 +1,151 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactornetty.v0_9; + +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; +import java.util.function.BiConsumer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import reactor.netty.Connection; +import reactor.netty.http.client.HttpClient; +import reactor.netty.http.client.HttpClientRequest; +import reactor.netty.http.client.HttpClientResponse; + +public class HttpClientInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("reactor.netty.http.client.HttpClient"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isStatic().and(namedOneOf("create", "newConnection", "from")), + this.getClass().getName() + "$CreateAdvice"); + + // advice classes below expose current context in doOn*/doAfter* callbacks + transformer.applyAdviceToMethod( + isPublic() + .and(namedOneOf("doOnRequest", "doAfterRequest")) + .and(takesArguments(1)) + .and(takesArgument(0, BiConsumer.class)), + this.getClass().getName() + "$OnRequestAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(named("doOnRequestError")) + .and(takesArguments(1)) + .and(takesArgument(0, BiConsumer.class)), + this.getClass().getName() + "$OnRequestErrorAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(namedOneOf("doOnResponse", "doAfterResponse")) + .and(takesArguments(1)) + .and(takesArgument(0, BiConsumer.class)), + this.getClass().getName() + "$OnResponseAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(named("doOnResponseError")) + .and(takesArguments(1)) + .and(takesArgument(0, BiConsumer.class)), + this.getClass().getName() + "$OnResponseErrorAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(named("doOnError")) + .and(takesArguments(2)) + .and(takesArgument(0, BiConsumer.class)) + .and(takesArgument(1, BiConsumer.class)), + this.getClass().getName() + "$OnErrorAdvice"); + } + + public static class CreateAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter() { + CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Thrown Throwable throwable, @Advice.Return(readOnly = false) HttpClient client) { + + if (CallDepthThreadLocalMap.decrementCallDepth(HttpClient.class) == 0 && throwable == null) { + client = client.doOnRequest(new OnRequest()).mapConnect(new MapConnect()); + } + } + } + + public static class OnRequestAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer callback) { + if (DecoratorFunctions.shouldDecorate(callback.getClass())) { + callback = new DecoratorFunctions.OnRequestDecorator(callback); + } + } + } + + public static class OnRequestErrorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer callback) { + if (DecoratorFunctions.shouldDecorate(callback.getClass())) { + callback = new DecoratorFunctions.OnRequestErrorDecorator(callback); + } + } + } + + public static class OnResponseAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer callback, + @Advice.Origin("#m") String methodName) { + if (DecoratorFunctions.shouldDecorate(callback.getClass())) { + boolean forceParentContext = methodName.equals("doAfterResponse"); + callback = new DecoratorFunctions.OnResponseDecorator(callback, forceParentContext); + } + } + } + + public static class OnResponseErrorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer callback) { + if (DecoratorFunctions.shouldDecorate(callback.getClass())) { + callback = new DecoratorFunctions.OnResponseErrorDecorator(callback); + } + } + } + + public static class OnErrorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer requestCallback, + @Advice.Argument(value = 1, readOnly = false) + BiConsumer responseCallback) { + if (DecoratorFunctions.shouldDecorate(requestCallback.getClass())) { + requestCallback = new DecoratorFunctions.OnRequestErrorDecorator(requestCallback); + } + if (DecoratorFunctions.shouldDecorate(responseCallback.getClass())) { + responseCallback = new DecoratorFunctions.OnResponseErrorDecorator(responseCallback); + } + } + } +} diff --git a/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/MapConnect.java b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/MapConnect.java new file mode 100644 index 0000000000..f8e2de8cfd --- /dev/null +++ b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/MapConnect.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactornetty.v0_9; + +import io.netty.bootstrap.Bootstrap; +import io.opentelemetry.context.Context; +import java.util.function.BiFunction; +import reactor.core.publisher.Mono; +import reactor.netty.Connection; + +public class MapConnect + implements BiFunction, Bootstrap, Mono> { + + static final String CONTEXT_ATTRIBUTE = MapConnect.class.getName() + ".Context"; + + @Override + public Mono apply(Mono m, Bootstrap b) { + return m.subscriberContext(s -> s.put(CONTEXT_ATTRIBUTE, Context.current())); + } +} diff --git a/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/OnRequest.java b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/OnRequest.java new file mode 100644 index 0000000000..706f01be62 --- /dev/null +++ b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/OnRequest.java @@ -0,0 +1,20 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactornetty.v0_9; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.netty.v4_1.AttributeKeys; +import java.util.function.BiConsumer; +import reactor.netty.Connection; +import reactor.netty.http.client.HttpClientRequest; + +public class OnRequest implements BiConsumer { + @Override + public void accept(HttpClientRequest r, Connection c) { + Context context = r.currentContext().get(MapConnect.CONTEXT_ATTRIBUTE); + c.channel().attr(AttributeKeys.WRITE_CONTEXT).set(context); + } +} diff --git a/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/ReactorNettyInstrumentationModule.java b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/ReactorNettyInstrumentationModule.java index e126dbf000..f6c6f56193 100644 --- a/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/ReactorNettyInstrumentationModule.java +++ b/instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/ReactorNettyInstrumentationModule.java @@ -7,32 +7,15 @@ package io.opentelemetry.javaagent.instrumentation.reactornetty.v0_9; import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.isStatic; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import io.netty.bootstrap.Bootstrap; -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.netty.v4_1.AttributeKeys; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; -import reactor.core.publisher.Mono; -import reactor.netty.Connection; import reactor.netty.http.client.HttpClient; -import reactor.netty.http.client.HttpClientRequest; -import reactor.netty.http.client.HttpClientResponse; /** * This instrumentation solves the problem of the correct context propagation through the roller @@ -57,149 +40,4 @@ public class ReactorNettyInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new HttpClientInstrumentation()); } - - public static class HttpClientInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("reactor.netty.http.client.HttpClient"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isStatic().and(namedOneOf("create", "newConnection", "from")), - ReactorNettyInstrumentationModule.class.getName() + "$CreateAdvice"); - - // advice classes below expose current context in doOn*/doAfter* callbacks - transformer.applyAdviceToMethod( - isPublic() - .and(namedOneOf("doOnRequest", "doAfterRequest")) - .and(takesArguments(1)) - .and(takesArgument(0, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnRequestAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(named("doOnRequestError")) - .and(takesArguments(1)) - .and(takesArgument(0, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnRequestErrorAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(namedOneOf("doOnResponse", "doAfterResponse")) - .and(takesArguments(1)) - .and(takesArgument(0, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnResponseAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(named("doOnResponseError")) - .and(takesArguments(1)) - .and(takesArgument(0, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnResponseErrorAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(named("doOnError")) - .and(takesArguments(2)) - .and(takesArgument(0, BiConsumer.class)) - .and(takesArgument(1, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnErrorAdvice"); - } - } - - public static class CreateAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter() { - CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( - @Advice.Thrown Throwable throwable, @Advice.Return(readOnly = false) HttpClient client) { - - if (CallDepthThreadLocalMap.decrementCallDepth(HttpClient.class) == 0 && throwable == null) { - client = client.doOnRequest(new OnRequest()).mapConnect(new MapConnect()); - } - } - } - - public static class MapConnect - implements BiFunction, Bootstrap, Mono> { - - static final String CONTEXT_ATTRIBUTE = MapConnect.class.getName() + ".Context"; - - @Override - public Mono apply(Mono m, Bootstrap b) { - return m.subscriberContext(s -> s.put(CONTEXT_ATTRIBUTE, Context.current())); - } - } - - public static class OnRequest implements BiConsumer { - @Override - public void accept(HttpClientRequest r, Connection c) { - Context context = r.currentContext().get(MapConnect.CONTEXT_ATTRIBUTE); - c.channel().attr(AttributeKeys.WRITE_CONTEXT).set(context); - } - } - - public static class OnRequestAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer callback) { - if (DecoratorFunctions.shouldDecorate(callback.getClass())) { - callback = new DecoratorFunctions.OnRequestDecorator(callback); - } - } - } - - public static class OnRequestErrorAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer callback) { - if (DecoratorFunctions.shouldDecorate(callback.getClass())) { - callback = new DecoratorFunctions.OnRequestErrorDecorator(callback); - } - } - } - - public static class OnResponseAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer callback, - @Advice.Origin("#m") String methodName) { - if (DecoratorFunctions.shouldDecorate(callback.getClass())) { - boolean forceParentContext = methodName.equals("doAfterResponse"); - callback = new DecoratorFunctions.OnResponseDecorator(callback, forceParentContext); - } - } - } - - public static class OnResponseErrorAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer callback) { - if (DecoratorFunctions.shouldDecorate(callback.getClass())) { - callback = new DecoratorFunctions.OnResponseErrorDecorator(callback); - } - } - } - - public static class OnErrorAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer requestCallback, - @Advice.Argument(value = 1, readOnly = false) - BiConsumer responseCallback) { - if (DecoratorFunctions.shouldDecorate(requestCallback.getClass())) { - requestCallback = new DecoratorFunctions.OnRequestErrorDecorator(requestCallback); - } - if (DecoratorFunctions.shouldDecorate(responseCallback.getClass())) { - responseCallback = new DecoratorFunctions.OnResponseErrorDecorator(responseCallback); - } - } - } } diff --git a/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/DecoratorFunctions.java b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/DecoratorFunctions.java index 9de088b3df..0236b676d0 100644 --- a/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/DecoratorFunctions.java +++ b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/DecoratorFunctions.java @@ -74,8 +74,7 @@ public final class DecoratorFunctions { } } // otherwise use the parent span context - return contextView.getOrDefault( - ReactorNettyInstrumentationModule.MapConnect.CONTEXT_ATTRIBUTE, null); + return contextView.getOrDefault(MapConnect.CONTEXT_ATTRIBUTE, null); } private DecoratorFunctions() {} diff --git a/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/HttpClientInstrumentation.java b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/HttpClientInstrumentation.java new file mode 100644 index 0000000000..a62fc195a6 --- /dev/null +++ b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/HttpClientInstrumentation.java @@ -0,0 +1,149 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0; + +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; +import java.util.function.BiConsumer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import reactor.netty.Connection; +import reactor.netty.http.client.HttpClient; +import reactor.netty.http.client.HttpClientRequest; +import reactor.netty.http.client.HttpClientResponse; + +public class HttpClientInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("reactor.netty.http.client.HttpClient"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isStatic().and(namedOneOf("create", "newConnection", "from")), + this.getClass().getName() + "$CreateAdvice"); + + // advice classes below expose current context in doOn*/doAfter* callbacks + transformer.applyAdviceToMethod( + isPublic() + .and(namedOneOf("doOnRequest", "doAfterRequest")) + .and(takesArguments(1)) + .and(takesArgument(0, BiConsumer.class)), + this.getClass().getName() + "$OnRequestAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(named("doOnRequestError")) + .and(takesArguments(1)) + .and(takesArgument(0, BiConsumer.class)), + this.getClass().getName() + "$OnRequestErrorAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(namedOneOf("doOnResponse", "doAfterResponseSuccess", "doOnRedirect")) + .and(takesArguments(1)) + .and(takesArgument(0, BiConsumer.class)), + this.getClass().getName() + "$OnResponseAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(named("doOnResponseError")) + .and(takesArguments(1)) + .and(takesArgument(0, BiConsumer.class)), + this.getClass().getName() + "$OnResponseErrorAdvice"); + transformer.applyAdviceToMethod( + isPublic() + .and(named("doOnError")) + .and(takesArguments(2)) + .and(takesArgument(0, BiConsumer.class)) + .and(takesArgument(1, BiConsumer.class)), + this.getClass().getName() + "$OnErrorAdvice"); + } + + public static class CreateAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter() { + CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Thrown Throwable throwable, @Advice.Return(readOnly = false) HttpClient client) { + + if (CallDepthThreadLocalMap.decrementCallDepth(HttpClient.class) == 0 && throwable == null) { + client = client.doOnRequest(new OnRequest()).mapConnect(new MapConnect()); + } + } + } + + public static class OnRequestAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer callback) { + if (DecoratorFunctions.shouldDecorate(callback.getClass())) { + callback = new DecoratorFunctions.OnMessageDecorator<>(callback); + } + } + } + + public static class OnRequestErrorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer callback) { + if (DecoratorFunctions.shouldDecorate(callback.getClass())) { + callback = new DecoratorFunctions.OnMessageErrorDecorator<>(callback); + } + } + } + + public static class OnResponseAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer callback) { + if (DecoratorFunctions.shouldDecorate(callback.getClass())) { + callback = new DecoratorFunctions.OnMessageDecorator<>(callback); + } + } + } + + public static class OnResponseErrorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer callback) { + if (DecoratorFunctions.shouldDecorate(callback.getClass())) { + callback = new DecoratorFunctions.OnMessageErrorDecorator<>(callback); + } + } + } + + public static class OnErrorAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) + BiConsumer requestCallback, + @Advice.Argument(value = 1, readOnly = false) + BiConsumer responseCallback) { + if (DecoratorFunctions.shouldDecorate(requestCallback.getClass())) { + requestCallback = new DecoratorFunctions.OnMessageErrorDecorator<>(requestCallback); + } + if (DecoratorFunctions.shouldDecorate(responseCallback.getClass())) { + responseCallback = new DecoratorFunctions.OnMessageErrorDecorator<>(responseCallback); + } + } + } +} diff --git a/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/MapConnect.java b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/MapConnect.java new file mode 100644 index 0000000000..10031575a3 --- /dev/null +++ b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/MapConnect.java @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0; + +import io.opentelemetry.context.Context; +import java.util.function.Function; +import reactor.core.publisher.Mono; +import reactor.netty.Connection; + +public class MapConnect + implements Function, Mono> { + + static final String CONTEXT_ATTRIBUTE = MapConnect.class.getName() + ".Context"; + + @Override + public Mono apply(Mono m) { + return m.contextWrite(s -> s.put(CONTEXT_ATTRIBUTE, Context.current())); + } +} diff --git a/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/OnRequest.java b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/OnRequest.java new file mode 100644 index 0000000000..adff05db75 --- /dev/null +++ b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/OnRequest.java @@ -0,0 +1,20 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.netty.v4_1.AttributeKeys; +import java.util.function.BiConsumer; +import reactor.netty.Connection; +import reactor.netty.http.client.HttpClientRequest; + +public class OnRequest implements BiConsumer { + @Override + public void accept(HttpClientRequest r, Connection c) { + Context context = r.currentContextView().get(MapConnect.CONTEXT_ATTRIBUTE); + c.channel().attr(AttributeKeys.WRITE_CONTEXT).set(context); + } +} diff --git a/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ReactorNettyInstrumentationModule.java b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ReactorNettyInstrumentationModule.java index 54cc6810d1..d758e23d9f 100644 --- a/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ReactorNettyInstrumentationModule.java +++ b/instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/ReactorNettyInstrumentationModule.java @@ -7,31 +7,15 @@ package io.opentelemetry.javaagent.instrumentation.reactornetty.v1_0; import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.isStatic; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.netty.v4_1.AttributeKeys; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap; import java.util.List; import java.util.function.BiConsumer; import java.util.function.Function; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; -import reactor.core.publisher.Mono; -import reactor.netty.Connection; import reactor.netty.http.client.HttpClient; -import reactor.netty.http.client.HttpClientRequest; -import reactor.netty.http.client.HttpClientResponse; /** * This instrumentation solves the problem of the correct context propagation through the roller @@ -56,147 +40,4 @@ public class ReactorNettyInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new HttpClientInstrumentation()); } - - public static class HttpClientInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("reactor.netty.http.client.HttpClient"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isStatic().and(namedOneOf("create", "newConnection", "from")), - ReactorNettyInstrumentationModule.class.getName() + "$CreateAdvice"); - - // advice classes below expose current context in doOn*/doAfter* callbacks - transformer.applyAdviceToMethod( - isPublic() - .and(namedOneOf("doOnRequest", "doAfterRequest")) - .and(takesArguments(1)) - .and(takesArgument(0, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnRequestAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(named("doOnRequestError")) - .and(takesArguments(1)) - .and(takesArgument(0, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnRequestErrorAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(namedOneOf("doOnResponse", "doAfterResponseSuccess", "doOnRedirect")) - .and(takesArguments(1)) - .and(takesArgument(0, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnResponseAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(named("doOnResponseError")) - .and(takesArguments(1)) - .and(takesArgument(0, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnResponseErrorAdvice"); - transformer.applyAdviceToMethod( - isPublic() - .and(named("doOnError")) - .and(takesArguments(2)) - .and(takesArgument(0, BiConsumer.class)) - .and(takesArgument(1, BiConsumer.class)), - ReactorNettyInstrumentationModule.class.getName() + "$OnErrorAdvice"); - } - } - - public static class CreateAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter() { - CallDepthThreadLocalMap.incrementCallDepth(HttpClient.class); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( - @Advice.Thrown Throwable throwable, @Advice.Return(readOnly = false) HttpClient client) { - - if (CallDepthThreadLocalMap.decrementCallDepth(HttpClient.class) == 0 && throwable == null) { - client = client.doOnRequest(new OnRequest()).mapConnect(new MapConnect()); - } - } - } - - public static class MapConnect - implements Function, Mono> { - - static final String CONTEXT_ATTRIBUTE = MapConnect.class.getName() + ".Context"; - - @Override - public Mono apply(Mono m) { - return m.contextWrite(s -> s.put(CONTEXT_ATTRIBUTE, Context.current())); - } - } - - public static class OnRequest implements BiConsumer { - @Override - public void accept(HttpClientRequest r, Connection c) { - Context context = r.currentContextView().get(MapConnect.CONTEXT_ATTRIBUTE); - c.channel().attr(AttributeKeys.WRITE_CONTEXT).set(context); - } - } - - public static class OnRequestAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer callback) { - if (DecoratorFunctions.shouldDecorate(callback.getClass())) { - callback = new DecoratorFunctions.OnMessageDecorator<>(callback); - } - } - } - - public static class OnRequestErrorAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer callback) { - if (DecoratorFunctions.shouldDecorate(callback.getClass())) { - callback = new DecoratorFunctions.OnMessageErrorDecorator<>(callback); - } - } - } - - public static class OnResponseAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer callback) { - if (DecoratorFunctions.shouldDecorate(callback.getClass())) { - callback = new DecoratorFunctions.OnMessageDecorator<>(callback); - } - } - } - - public static class OnResponseErrorAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer callback) { - if (DecoratorFunctions.shouldDecorate(callback.getClass())) { - callback = new DecoratorFunctions.OnMessageErrorDecorator<>(callback); - } - } - } - - public static class OnErrorAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0, readOnly = false) - BiConsumer requestCallback, - @Advice.Argument(value = 1, readOnly = false) - BiConsumer responseCallback) { - if (DecoratorFunctions.shouldDecorate(requestCallback.getClass())) { - requestCallback = new DecoratorFunctions.OnMessageErrorDecorator<>(requestCallback); - } - if (DecoratorFunctions.shouldDecorate(responseCallback.getClass())) { - responseCallback = new DecoratorFunctions.OnMessageErrorDecorator<>(responseCallback); - } - } - } } diff --git a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/OnCompleteHandler.java b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/OnCompleteHandler.java new file mode 100644 index 0000000000..a43c8e2301 --- /dev/null +++ b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/OnCompleteHandler.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.rediscala; + +import static io.opentelemetry.javaagent.instrumentation.rediscala.RediscalaClientTracer.tracer; + +import io.opentelemetry.context.Context; +import scala.runtime.AbstractFunction1; +import scala.util.Try; + +public class OnCompleteHandler extends AbstractFunction1, Void> { + private final Context context; + + public OnCompleteHandler(Context context) { + this.context = context; + } + + @Override + public Void apply(Try result) { + if (result.isFailure()) { + tracer().endExceptionally(context, result.failed().get()); + } else { + tracer().end(context); + } + return null; + } +} diff --git a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaInstrumentationModule.java b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaInstrumentationModule.java index 83eb6d4a52..fec134a088 100644 --- a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaInstrumentationModule.java +++ b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RediscalaInstrumentationModule.java @@ -5,33 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.rediscala; -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.safeHasSuperType; -import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; -import static io.opentelemetry.javaagent.extension.matcher.NameMatchers.namedOneOf; -import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; -import static io.opentelemetry.javaagent.instrumentation.rediscala.RediscalaClientTracer.tracer; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.returns; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import redis.RedisCommand; -import scala.concurrent.ExecutionContext; -import scala.concurrent.Future; -import scala.runtime.AbstractFunction1; -import scala.util.Try; @AutoService(InstrumentationModule.class) public class RediscalaInstrumentationModule extends InstrumentationModule { @@ -44,78 +23,4 @@ public class RediscalaInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new RequestInstrumentation()); } - - public static class RequestInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher classLoaderOptimization() { - return hasClassesNamed("redis.Request"); - } - - @Override - public ElementMatcher typeMatcher() { - return safeHasSuperType( - namedOneOf( - "redis.ActorRequest", - "redis.Request", - "redis.BufferedRequest", - "redis.RoundRobinPoolRequest")); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isMethod() - .and(isPublic()) - .and(named("send")) - .and(takesArgument(0, named("redis.RedisCommand"))) - .and(returns(named("scala.concurrent.Future"))), - RediscalaInstrumentationModule.class.getName() + "$RediscalaAdvice"); - } - } - - public static class RediscalaAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(0) RedisCommand cmd, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - context = tracer().startSpan(currentContext(), cmd, cmd); - scope = context.makeCurrent(); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Thrown Throwable throwable, - @Advice.FieldValue("executionContext") ExecutionContext ctx, - @Advice.Return(readOnly = false) Future responseFuture) { - scope.close(); - - if (throwable != null) { - tracer().endExceptionally(context, throwable); - } else { - responseFuture.onComplete(new OnCompleteHandler(context), ctx); - } - } - } - - public static class OnCompleteHandler extends AbstractFunction1, Void> { - private final Context context; - - public OnCompleteHandler(Context context) { - this.context = context; - } - - @Override - public Void apply(Try result) { - if (result.isFailure()) { - tracer().endExceptionally(context, result.failed().get()); - } else { - tracer().end(context); - } - return null; - } - } } diff --git a/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RequestInstrumentation.java b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RequestInstrumentation.java new file mode 100644 index 0000000000..3f56d49ed2 --- /dev/null +++ b/instrumentation/rediscala-1.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rediscala/RequestInstrumentation.java @@ -0,0 +1,84 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.rediscala; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.safeHasSuperType; +import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; +import static io.opentelemetry.javaagent.extension.matcher.NameMatchers.namedOneOf; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.rediscala.RediscalaClientTracer.tracer; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import redis.RedisCommand; +import scala.concurrent.ExecutionContext; +import scala.concurrent.Future; + +public class RequestInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("redis.Request"); + } + + @Override + public ElementMatcher typeMatcher() { + return safeHasSuperType( + namedOneOf( + "redis.ActorRequest", + "redis.Request", + "redis.BufferedRequest", + "redis.RoundRobinPoolRequest")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod() + .and(isPublic()) + .and(named("send")) + .and(takesArgument(0, named("redis.RedisCommand"))) + .and(returns(named("scala.concurrent.Future"))), + this.getClass().getName() + "$SendAdvice"); + } + + public static class SendAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(0) RedisCommand cmd, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + context = tracer().startSpan(currentContext(), cmd, cmd); + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope, + @Advice.Thrown Throwable throwable, + @Advice.FieldValue("executionContext") ExecutionContext ctx, + @Advice.Return(readOnly = false) Future responseFuture) { + scope.close(); + + if (throwable != null) { + tracer().endExceptionally(context, throwable); + } else { + responseFuture.onComplete(new OnCompleteHandler(context), ctx); + } + } + } +} diff --git a/instrumentation/redisson-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedisConnectionInstrumentation.java b/instrumentation/redisson-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedisConnectionInstrumentation.java new file mode 100644 index 0000000000..fb7df3077a --- /dev/null +++ b/instrumentation/redisson-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedisConnectionInstrumentation.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.redisson; + +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.redisson.RedissonInstrumenters.instrumenter; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import java.net.InetSocketAddress; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.redisson.client.RedisConnection; + +public class RedisConnectionInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("org.redisson.client.RedisConnection"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("send")), this.getClass().getName() + "$SendAdvice"); + } + + public static class SendAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.This RedisConnection connection, + @Advice.Argument(0) Object arg, + @Advice.Local("otelRedissonRequest") RedissonRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = currentContext(); + InetSocketAddress remoteAddress = (InetSocketAddress) connection.getChannel().remoteAddress(); + request = RedissonRequest.create(remoteAddress, arg); + if (!instrumenter().shouldStart(parentContext, request)) { + return; + } + + context = instrumenter().start(parentContext, request); + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Thrown Throwable throwable, + @Advice.Local("otelRedissonRequest") RedissonRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + scope.close(); + instrumenter().end(context, request, null, throwable); + } + } +} diff --git a/instrumentation/redisson-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedissonInstrumentationModule.java b/instrumentation/redisson-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedissonInstrumentationModule.java index 1f27f33812..0e9fe1fa94 100644 --- a/instrumentation/redisson-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedissonInstrumentationModule.java +++ b/instrumentation/redisson-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedissonInstrumentationModule.java @@ -5,24 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.redisson; -import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; -import static io.opentelemetry.javaagent.instrumentation.redisson.RedissonInstrumenters.instrumenter; import static java.util.Collections.singletonList; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import java.net.InetSocketAddress; import java.util.List; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import org.redisson.client.RedisConnection; @AutoService(InstrumentationModule.class) public class RedissonInstrumentationModule extends InstrumentationModule { @@ -35,49 +23,4 @@ public class RedissonInstrumentationModule extends InstrumentationModule { public List typeInstrumentations() { return singletonList(new RedisConnectionInstrumentation()); } - - public static class RedisConnectionInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("org.redisson.client.RedisConnection"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isMethod().and(named("send")), - RedissonInstrumentationModule.class.getName() + "$RedissonAdvice"); - } - } - - public static class RedissonAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.This RedisConnection connection, - @Advice.Argument(0) Object arg, - @Advice.Local("otelRedissonRequest") RedissonRequest request, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - Context parentContext = currentContext(); - InetSocketAddress remoteAddress = (InetSocketAddress) connection.getChannel().remoteAddress(); - request = RedissonRequest.create(remoteAddress, arg); - if (!instrumenter().shouldStart(parentContext, request)) { - return; - } - - context = instrumenter().start(parentContext, request); - scope = context.makeCurrent(); - } - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void stopSpan( - @Advice.Thrown Throwable throwable, - @Advice.Local("otelRedissonRequest") RedissonRequest request, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope) { - scope.close(); - instrumenter().end(context, request, null, throwable); - } - } }