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
|
* 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.javadsl.model.HttpHeader;
|
||||||
import akka.http.scaladsl.model.HttpRequest;
|
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.context.propagation.TextMapSetter;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
|
import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
|
||||||
import io.opentelemetry.javaagent.instrumentation.akkahttp.AkkaHttpClientInstrumentationModule.AkkaHttpHeaders;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
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
|
* 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.javadsl.model.HttpHeader;
|
||||||
import akka.http.scaladsl.model.HttpRequest;
|
import akka.http.scaladsl.model.HttpRequest;
|
|
@ -3,26 +3,19 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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 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.HttpRequest;
|
||||||
import akka.http.scaladsl.model.HttpResponse;
|
import akka.http.scaladsl.model.HttpResponse;
|
||||||
import akka.stream.Materializer;
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
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.Function1;
|
||||||
import scala.concurrent.ExecutionContext;
|
import scala.concurrent.ExecutionContext;
|
||||||
import scala.concurrent.Future;
|
import scala.concurrent.Future;
|
||||||
|
@ -36,49 +29,7 @@ public class AkkaHttpServerInstrumentationModule extends InstrumentationModule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new HttpExtInstrumentation());
|
return singletonList(new HttpExtServerInstrumentation());
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SyncWrapper extends AbstractFunction1<HttpRequest, HttpResponse> {
|
public static class SyncWrapper extends AbstractFunction1<HttpRequest, HttpResponse> {
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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.javadsl.model.HttpHeader;
|
||||||
import akka.http.scaladsl.model.HttpRequest;
|
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;
|
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 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 com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
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)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class ApacheCamelInstrumentationModule extends InstrumentationModule {
|
public class ApacheCamelInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -38,35 +28,4 @@ public class ApacheCamelInstrumentationModule extends InstrumentationModule {
|
||||||
public boolean isHelperClass(String className) {
|
public boolean isHelperClass(String className) {
|
||||||
return className.startsWith("io.opentelemetry.extension.aws.");
|
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;
|
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 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 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.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
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 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)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class HttpUrlConnectionInstrumentationModule extends InstrumentationModule {
|
public class HttpUrlConnectionInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -49,141 +23,4 @@ public class HttpUrlConnectionInstrumentationModule extends InstrumentationModul
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new HttpUrlConnectionInstrumentation());
|
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;
|
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 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.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.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
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)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class HystrixInstrumentationModule extends InstrumentationModule {
|
public class HystrixInstrumentationModule extends InstrumentationModule {
|
||||||
|
|
||||||
private static final String OPERATION_NAME = "hystrix.cmd";
|
|
||||||
|
|
||||||
public HystrixInstrumentationModule() {
|
public HystrixInstrumentationModule() {
|
||||||
super("hystrix", "hystrix-1.4");
|
super("hystrix", "hystrix-1.4");
|
||||||
}
|
}
|
||||||
|
@ -45,72 +28,4 @@ public class HystrixInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new HystrixCommandInstrumentation());
|
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;
|
package io.opentelemetry.javaagent.instrumentation.internal.osgi;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
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 com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
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 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)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class EclipseOsgiInstrumentationModule extends InstrumentationModule {
|
public class EclipseOsgiInstrumentationModule extends InstrumentationModule {
|
||||||
public EclipseOsgiInstrumentationModule() {
|
public EclipseOsgiInstrumentationModule() {
|
||||||
|
@ -39,38 +22,4 @@ public class EclipseOsgiInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new EclipseOsgiInstrumentation());
|
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;
|
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 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.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.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class JaxRsClientInstrumentationModule extends InstrumentationModule {
|
public class JaxRsClientInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -40,60 +23,4 @@ public class JaxRsClientInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new ClientHandlerInstrumentation());
|
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;
|
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 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.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
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)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class JaxRsClientInstrumentationModule extends InstrumentationModule {
|
public class JaxRsClientInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -34,35 +23,4 @@ public class JaxRsClientInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new ClientBuilderInstrumentation());
|
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;
|
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
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 com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
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
|
* 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 CxfClientConnectionErrorInstrumentation(),
|
||||||
new CxfAsyncClientConnectionErrorInstrumentation());
|
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;
|
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
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 com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
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
|
* 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
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return Collections.singletonList(new JerseyClientConnectionErrorInstrumentation());
|
return 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,12 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jetty.v8_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 com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
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 io.opentelemetry.javaagent.instrumentation.jetty.common.JettyHandlerInstrumentation;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class Jetty8InstrumentationModule extends InstrumentationModule {
|
public class Jetty8InstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -41,42 +27,4 @@ public class Jetty8InstrumentationModule extends InstrumentationModule {
|
||||||
Jetty8InstrumentationModule.class.getPackage().getName() + ".Jetty8HandlerAdvice"),
|
Jetty8InstrumentationModule.class.getPackage().getName() + ".Jetty8HandlerAdvice"),
|
||||||
new JettyQueuedThreadPoolInstrumentation());
|
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;
|
package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
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 com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
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)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class KotlinCoroutinesInstrumentationModule extends InstrumentationModule {
|
public class KotlinCoroutinesInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -33,45 +26,6 @@ public class KotlinCoroutinesInstrumentationModule extends InstrumentationModule
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new CoroutineScopeLaunchInstrumentation());
|
return singletonList(new KotlinCoroutinesInstrumentation());
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package io.opentelemetry.javaagent.instrumentation.kubernetesclient;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.kubernetesclient.KubernetesClientTracer.tracer;
|
|
||||||
import static java.util.Collections.singletonList;
|
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 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.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
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 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)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class KubernetesClientInstrumentationModule extends InstrumentationModule {
|
public class KubernetesClientInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -39,95 +23,4 @@ public class KubernetesClientInstrumentationModule extends InstrumentationModule
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new ApiClientInstrumentation());
|
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 io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed;
|
||||||
import static java.util.Collections.singletonList;
|
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 com.google.auto.service.AutoService;
|
||||||
import io.lettuce.core.resource.DefaultClientResources;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
|
@ -38,26 +30,4 @@ public class LettuceInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new DefaultClientResourcesInstrumentation());
|
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;
|
package io.opentelemetry.javaagent.instrumentation.liberty;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
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 com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instrumenting request handling in Liberty.
|
* Instrumenting request handling in Liberty.
|
||||||
*
|
*
|
||||||
* <ul>
|
* <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
|
* <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
|
* remembered request. We don't start span immediately at the start or handleRequest because
|
||||||
* HttpServletRequest isn't usable yet. {@link LibertyStartSpanAdvice}
|
* HttpServletRequest isn't usable yet. {@link LibertyWebAppInstrumentation.IsForbiddenAdvice}
|
||||||
* <li>On exit from WebApp.handleRequest close the span. {@link LibertyHandleRequestAdvice}
|
* <li>On exit from WebApp.handleRequest close the span. {@link
|
||||||
|
* LibertyWebAppInstrumentation.HandleRequestAdvice}
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
|
@ -37,30 +34,6 @@ public class LibertyInstrumentationModule extends InstrumentationModule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new WebAppInstrumentation());
|
return singletonList(new LibertyWebAppInstrumentation());
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed;
|
||||||
import static java.util.Collections.singletonList;
|
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.not;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
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 net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.apache.logging.log4j.core.ContextDataInjector;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class Log4j27InstrumentationModule extends InstrumentationModule {
|
public class Log4j27InstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -41,30 +31,4 @@ public class Log4j27InstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new ContextDataInjectorFactoryInstrumentation());
|
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;
|
package io.opentelemetry.javaagent.instrumentation.okhttp.v2_2;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
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.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.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class OkHttp2InstrumentationModule extends InstrumentationModule {
|
public class OkHttp2InstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -30,30 +22,4 @@ public class OkHttp2InstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new OkHttpClientInstrumentation());
|
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;
|
package io.opentelemetry.javaagent.instrumentation.okhttp.v3_0;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
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.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
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.List;
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class OkHttp3InstrumentationModule extends InstrumentationModule {
|
public class OkHttp3InstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -29,41 +21,6 @@ public class OkHttp3InstrumentationModule extends InstrumentationModule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new OkHttpClientInstrumentation());
|
return singletonList(new OkHttp3Instrumentation());
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,22 +5,12 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.oshi;
|
package io.opentelemetry.javaagent.instrumentation.oshi;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed;
|
|
||||||
import static java.util.Collections.singletonList;
|
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 com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.instrumentation.oshi.SystemMetrics;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class OshiInstrumentationModule extends InstrumentationModule {
|
public class OshiInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -33,30 +23,4 @@ public class OshiInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new SystemInfoInstrumentation());
|
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;
|
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 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.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class PlayInstrumentationModule extends InstrumentationModule {
|
public class PlayInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -31,25 +23,4 @@ public class PlayInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new ActionInstrumentation());
|
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;
|
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 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.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class PlayInstrumentationModule extends InstrumentationModule {
|
public class PlayInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -31,25 +23,4 @@ public class PlayInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new ActionInstrumentation());
|
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;
|
package io.opentelemetry.javaagent.instrumentation.reactor;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
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 com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class ReactorInstrumentationModule extends InstrumentationModule {
|
public class ReactorInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -28,17 +23,4 @@ public class ReactorInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new HooksInstrumentation());
|
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
|
// otherwise use the parent span context
|
||||||
return reactorContext.getOrDefault(
|
return reactorContext.getOrDefault(MapConnect.CONTEXT_ATTRIBUTE, null);
|
||||||
ReactorNettyInstrumentationModule.MapConnect.CONTEXT_ATTRIBUTE, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DecoratorFunctions() {}
|
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 io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed;
|
||||||
import static java.util.Collections.singletonList;
|
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 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.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
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.List;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
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.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
|
* 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() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new HttpClientInstrumentation());
|
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
|
// otherwise use the parent span context
|
||||||
return contextView.getOrDefault(
|
return contextView.getOrDefault(MapConnect.CONTEXT_ATTRIBUTE, null);
|
||||||
ReactorNettyInstrumentationModule.MapConnect.CONTEXT_ATTRIBUTE, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DecoratorFunctions() {}
|
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 io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed;
|
||||||
import static java.util.Collections.singletonList;
|
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 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.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
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.List;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
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.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
|
* 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() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new HttpClientInstrumentation());
|
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;
|
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 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 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.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
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)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class RediscalaInstrumentationModule extends InstrumentationModule {
|
public class RediscalaInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -44,78 +23,4 @@ public class RediscalaInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new RequestInstrumentation());
|
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;
|
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 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 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.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.List;
|
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)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class RedissonInstrumentationModule extends InstrumentationModule {
|
public class RedissonInstrumentationModule extends InstrumentationModule {
|
||||||
|
@ -35,49 +23,4 @@ public class RedissonInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new RedisConnectionInstrumentation());
|
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