Move more type instrumentations to top-level classes (#3118)
This commit is contained in:
parent
ca5b792f95
commit
c1c052318b
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return Collections.singletonList(new HttpExtInstrumentation());
|
||||
}
|
||||
|
||||
public static class HttpExtInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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<HttpResponse> 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<Try<HttpResponse>, Void> {
|
||||
private final Context context;
|
||||
|
||||
public OnCompleteHandler(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void apply(Try<HttpResponse> 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<AkkaHttpHeaders> {
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new HttpExtClientInstrumentation());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<TypeDescription> 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<HttpResponse> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<AkkaHttpHeaders> {
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Try<HttpResponse>, Void> {
|
||||
private final Context context;
|
||||
|
||||
public OnCompleteHandler(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void apply(Try<HttpResponse> result) {
|
||||
if (result.isSuccess()) {
|
||||
tracer().end(context, result.get());
|
||||
} else {
|
||||
tracer().endExceptionally(context, result.failed().get());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new HttpExtInstrumentation());
|
||||
}
|
||||
|
||||
public static class HttpExtInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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<HttpRequest, HttpResponse> 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<HttpRequest, Future<HttpResponse>> handler,
|
||||
@Advice.Argument(7) Materializer materializer) {
|
||||
handler = new AsyncWrapper(handler, materializer.executionContext());
|
||||
}
|
||||
return singletonList(new HttpExtServerInstrumentation());
|
||||
}
|
||||
|
||||
public static class SyncWrapper extends AbstractFunction1<HttpRequest, HttpResponse> {
|
|
@ -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;
|
|
@ -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<TypeDescription> 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<HttpRequest, HttpResponse> 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<HttpRequest, Future<HttpResponse>> handler,
|
||||
@Advice.Argument(7) Materializer materializer) {
|
||||
handler =
|
||||
new AkkaHttpServerInstrumentationModule.AsyncWrapper(
|
||||
handler, materializer.executionContext());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("org.apache.camel.CamelContext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("org.apache.camel.CamelContext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeDescription> typeMatcher() {
|
||||
return nameStartsWith("java.net.")
|
||||
.or(ElementMatchers.<TypeDescription>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<HttpURLConnection, HttpUrlState> 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<HttpURLConnection, HttpUrlState> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new HttpUrlConnectionInstrumentation());
|
||||
}
|
||||
|
||||
public static class HttpUrlConnectionInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||
return nameStartsWith("java.net.")
|
||||
.or(ElementMatchers.<TypeDescription>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<HttpURLConnection, HttpUrlState> 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<HttpURLConnection, HttpUrlState> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed(
|
||||
"com.netflix.hystrix.HystrixCommand", "com.netflix.hystrix.HystrixObservableCommand");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new HystrixCommandInstrumentation());
|
||||
}
|
||||
|
||||
public static class HystrixCommandInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed(
|
||||
"com.netflix.hystrix.HystrixCommand", "com.netflix.hystrix.HystrixObservableCommand");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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<T> extends TracedOnSubscribe<T> {
|
||||
private final HystrixInvokableInfo<?> command;
|
||||
private final String methodName;
|
||||
|
||||
public HystrixOnSubscribe(
|
||||
Observable<T> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T> extends TracedOnSubscribe<T> {
|
||||
private static final String OPERATION_NAME = "hystrix.cmd";
|
||||
|
||||
private final HystrixInvokableInfo<?> command;
|
||||
private final String methodName;
|
||||
|
||||
public HystrixOnSubscribe(
|
||||
Observable<T> 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);
|
||||
}
|
||||
}
|
|
@ -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".
|
||||
*
|
||||
* <p>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<TypeDescription> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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".
|
||||
*
|
||||
* <p>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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new EclipseOsgiInstrumentation());
|
||||
}
|
||||
|
||||
private static class EclipseOsgiInstrumentation implements TypeInstrumentation {
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("com.sun.jersey.api.client.ClientHandler");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new ClientHandlerInstrumentation());
|
||||
}
|
||||
|
||||
public static class ClientHandlerInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("com.sun.jersey.api.client.ClientHandler");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("javax.ws.rs.client.ClientBuilder");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new ClientBuilderInstrumentation());
|
||||
}
|
||||
|
||||
public static class ClientBuilderInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("javax.ws.rs.client.ClientBuilder");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeDescription> 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<String, Object> map, @Advice.Argument(1) Throwable throwable) {
|
||||
if (throwable != null && map instanceof Message) {
|
||||
CxfClientUtil.handleException((Message) map, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeDescription> 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<TypeDescription> 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<String, Object> map, @Advice.Argument(1) Throwable throwable) {
|
||||
if (throwable != null && map instanceof Message) {
|
||||
CxfClientUtil.handleException((Message) map, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return Collections.singletonList(new JerseyClientConnectionErrorInstrumentation());
|
||||
}
|
||||
|
||||
public static class JerseyClientConnectionErrorInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeDescription> 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<Runnable, State> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeDescription> 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<Runnable, State> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new CoroutineScopeLaunchInstrumentation());
|
||||
}
|
||||
|
||||
public static class CoroutineScopeLaunchInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeDescription> 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new ApiClientInstrumentation());
|
||||
}
|
||||
|
||||
public static class ApiClientInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new DefaultClientResourcesInstrumentation());
|
||||
}
|
||||
|
||||
public static class DefaultClientResourcesInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
*
|
||||
* <ul>
|
||||
* <li>On entry to WebApp.handleRequest remember request. {@link LibertyHandleRequestAdvice}
|
||||
* <li>On entry to WebApp.handleRequest remember request. {@link
|
||||
* LibertyWebAppInstrumentation.HandleRequestAdvice}
|
||||
* <li>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}
|
||||
* <li>On exit from WebApp.handleRequest close the span. {@link LibertyHandleRequestAdvice}
|
||||
* HttpServletRequest isn't usable yet. {@link LibertyWebAppInstrumentation.IsForbiddenAdvice}
|
||||
* <li>On exit from WebApp.handleRequest close the span. {@link
|
||||
* LibertyWebAppInstrumentation.HandleRequestAdvice}
|
||||
* </ul>
|
||||
*/
|
||||
@AutoService(InstrumentationModule.class)
|
||||
|
@ -37,30 +34,6 @@ public class LibertyInstrumentationModule extends InstrumentationModule {
|
|||
|
||||
@Override
|
||||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new WebAppInstrumentation());
|
||||
}
|
||||
|
||||
public static class WebAppInstrumentation implements TypeInstrumentation {
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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<TypeDescription> 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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new ContextDataInjectorFactoryInstrumentation());
|
||||
}
|
||||
|
||||
public static class ContextDataInjectorFactoryInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new OkHttpClientInstrumentation());
|
||||
}
|
||||
|
||||
public static class OkHttpClientInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeDescription> 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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new OkHttpClientInstrumentation());
|
||||
}
|
||||
|
||||
public static class OkHttpClientInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new SystemInfoInstrumentation());
|
||||
}
|
||||
|
||||
public static class SystemInfoInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("oshi.SystemInfo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("oshi.SystemInfo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("play.api.mvc.Action");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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<Result> 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Result> 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();
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new ActionInstrumentation());
|
||||
}
|
||||
|
||||
public static class ActionInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("play.api.mvc.Action");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("play.api.mvc.Action");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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<Result> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Result> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new ActionInstrumentation());
|
||||
}
|
||||
|
||||
public static class ActionInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("play.api.mvc.Action");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TypeDescription> 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new HooksInstrumentation());
|
||||
}
|
||||
|
||||
public static class HooksInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||
return named("reactor.core.publisher.Hooks");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(TypeTransformer transformer) {
|
||||
transformer.applyAdviceToMethod(
|
||||
isTypeInitializer().or(named("resetOnEachOperator")), ReactorHooksAdvice.class.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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<TypeDescription> 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<? super HttpClientRequest, ? super Connection> 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<? super HttpClientRequest, ? super Throwable> 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<? super HttpClientResponse, ? super Connection> 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<? super HttpClientResponse, ? super Throwable> 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<? super HttpClientRequest, ? super Throwable> requestCallback,
|
||||
@Advice.Argument(value = 1, readOnly = false)
|
||||
BiConsumer<? super HttpClientResponse, ? super Throwable> responseCallback) {
|
||||
if (DecoratorFunctions.shouldDecorate(requestCallback.getClass())) {
|
||||
requestCallback = new DecoratorFunctions.OnRequestErrorDecorator(requestCallback);
|
||||
}
|
||||
if (DecoratorFunctions.shouldDecorate(responseCallback.getClass())) {
|
||||
responseCallback = new DecoratorFunctions.OnResponseErrorDecorator(responseCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Mono<? extends Connection>, Bootstrap, Mono<? extends Connection>> {
|
||||
|
||||
static final String CONTEXT_ATTRIBUTE = MapConnect.class.getName() + ".Context";
|
||||
|
||||
@Override
|
||||
public Mono<? extends Connection> apply(Mono<? extends Connection> m, Bootstrap b) {
|
||||
return m.subscriberContext(s -> s.put(CONTEXT_ATTRIBUTE, Context.current()));
|
||||
}
|
||||
}
|
|
@ -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<HttpClientRequest, Connection> {
|
||||
@Override
|
||||
public void accept(HttpClientRequest r, Connection c) {
|
||||
Context context = r.currentContext().get(MapConnect.CONTEXT_ATTRIBUTE);
|
||||
c.channel().attr(AttributeKeys.WRITE_CONTEXT).set(context);
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new HttpClientInstrumentation());
|
||||
}
|
||||
|
||||
public static class HttpClientInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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<Mono<? extends Connection>, Bootstrap, Mono<? extends Connection>> {
|
||||
|
||||
static final String CONTEXT_ATTRIBUTE = MapConnect.class.getName() + ".Context";
|
||||
|
||||
@Override
|
||||
public Mono<? extends Connection> apply(Mono<? extends Connection> m, Bootstrap b) {
|
||||
return m.subscriberContext(s -> s.put(CONTEXT_ATTRIBUTE, Context.current()));
|
||||
}
|
||||
}
|
||||
|
||||
public static class OnRequest implements BiConsumer<HttpClientRequest, Connection> {
|
||||
@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<? super HttpClientRequest, ? super Connection> 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<? super HttpClientRequest, ? super Throwable> 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<? super HttpClientResponse, ? super Connection> 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<? super HttpClientResponse, ? super Throwable> 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<? super HttpClientRequest, ? super Throwable> requestCallback,
|
||||
@Advice.Argument(value = 1, readOnly = false)
|
||||
BiConsumer<? super HttpClientResponse, ? super Throwable> responseCallback) {
|
||||
if (DecoratorFunctions.shouldDecorate(requestCallback.getClass())) {
|
||||
requestCallback = new DecoratorFunctions.OnRequestErrorDecorator(requestCallback);
|
||||
}
|
||||
if (DecoratorFunctions.shouldDecorate(responseCallback.getClass())) {
|
||||
responseCallback = new DecoratorFunctions.OnResponseErrorDecorator(responseCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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<TypeDescription> 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<? super HttpClientRequest, ? super Connection> 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<? super HttpClientRequest, ? super Throwable> 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<? super HttpClientResponse, ? super Connection> 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<? super HttpClientResponse, ? super Throwable> 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<? super HttpClientRequest, ? super Throwable> requestCallback,
|
||||
@Advice.Argument(value = 1, readOnly = false)
|
||||
BiConsumer<? super HttpClientResponse, ? super Throwable> responseCallback) {
|
||||
if (DecoratorFunctions.shouldDecorate(requestCallback.getClass())) {
|
||||
requestCallback = new DecoratorFunctions.OnMessageErrorDecorator<>(requestCallback);
|
||||
}
|
||||
if (DecoratorFunctions.shouldDecorate(responseCallback.getClass())) {
|
||||
responseCallback = new DecoratorFunctions.OnMessageErrorDecorator<>(responseCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<? extends Connection>, Mono<? extends Connection>> {
|
||||
|
||||
static final String CONTEXT_ATTRIBUTE = MapConnect.class.getName() + ".Context";
|
||||
|
||||
@Override
|
||||
public Mono<? extends Connection> apply(Mono<? extends Connection> m) {
|
||||
return m.contextWrite(s -> s.put(CONTEXT_ATTRIBUTE, Context.current()));
|
||||
}
|
||||
}
|
|
@ -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<HttpClientRequest, Connection> {
|
||||
@Override
|
||||
public void accept(HttpClientRequest r, Connection c) {
|
||||
Context context = r.currentContextView().get(MapConnect.CONTEXT_ATTRIBUTE);
|
||||
c.channel().attr(AttributeKeys.WRITE_CONTEXT).set(context);
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new HttpClientInstrumentation());
|
||||
}
|
||||
|
||||
public static class HttpClientInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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<? extends Connection>, Mono<? extends Connection>> {
|
||||
|
||||
static final String CONTEXT_ATTRIBUTE = MapConnect.class.getName() + ".Context";
|
||||
|
||||
@Override
|
||||
public Mono<? extends Connection> apply(Mono<? extends Connection> m) {
|
||||
return m.contextWrite(s -> s.put(CONTEXT_ATTRIBUTE, Context.current()));
|
||||
}
|
||||
}
|
||||
|
||||
public static class OnRequest implements BiConsumer<HttpClientRequest, Connection> {
|
||||
@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<? super HttpClientRequest, ? super Connection> 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<? super HttpClientRequest, ? super Throwable> 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<? super HttpClientResponse, ? super Connection> 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<? super HttpClientResponse, ? super Throwable> 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<? super HttpClientRequest, ? super Throwable> requestCallback,
|
||||
@Advice.Argument(value = 1, readOnly = false)
|
||||
BiConsumer<? super HttpClientResponse, ? super Throwable> responseCallback) {
|
||||
if (DecoratorFunctions.shouldDecorate(requestCallback.getClass())) {
|
||||
requestCallback = new DecoratorFunctions.OnMessageErrorDecorator<>(requestCallback);
|
||||
}
|
||||
if (DecoratorFunctions.shouldDecorate(responseCallback.getClass())) {
|
||||
responseCallback = new DecoratorFunctions.OnMessageErrorDecorator<>(responseCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Try<Object>, Void> {
|
||||
private final Context context;
|
||||
|
||||
public OnCompleteHandler(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void apply(Try<Object> result) {
|
||||
if (result.isFailure()) {
|
||||
tracer().endExceptionally(context, result.failed().get());
|
||||
} else {
|
||||
tracer().end(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new RequestInstrumentation());
|
||||
}
|
||||
|
||||
public static class RequestInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("redis.Request");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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<Object> responseFuture) {
|
||||
scope.close();
|
||||
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(context, throwable);
|
||||
} else {
|
||||
responseFuture.onComplete(new OnCompleteHandler(context), ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class OnCompleteHandler extends AbstractFunction1<Try<Object>, Void> {
|
||||
private final Context context;
|
||||
|
||||
public OnCompleteHandler(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void apply(Try<Object> result) {
|
||||
if (result.isFailure()) {
|
||||
tracer().endExceptionally(context, result.failed().get());
|
||||
} else {
|
||||
tracer().end(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ClassLoader> classLoaderOptimization() {
|
||||
return hasClassesNamed("redis.Request");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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<Object> responseFuture) {
|
||||
scope.close();
|
||||
|
||||
if (throwable != null) {
|
||||
tracer().endExceptionally(context, throwable);
|
||||
} else {
|
||||
responseFuture.onComplete(new OnCompleteHandler(context), ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new RedisConnectionInstrumentation());
|
||||
}
|
||||
|
||||
public static class RedisConnectionInstrumentation implements TypeInstrumentation {
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue