make netty-* indy compatible (#11559)
Co-authored-by: Jonas Kunz <jonas.kunz@elastic.co> Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
parent
d47289a4b2
commit
d0d39b8698
|
@ -34,16 +34,16 @@ public class ChannelTransportInstrumentation implements TypeInstrumentation {
|
|||
public static class WriteAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void methodEnter(@Advice.Local("otelScope") Scope scope) {
|
||||
public static Scope methodEnter() {
|
||||
Option<Context> ref = Helpers.CONTEXT_LOCAL.apply();
|
||||
if (ref.isDefined()) {
|
||||
scope = ref.get().makeCurrent();
|
||||
return ref.get().makeCurrent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||
public static void methodExit(
|
||||
@Advice.Local("otelScope") Scope scope, @Advice.Thrown Throwable thrown) {
|
||||
public static void methodExit(@Advice.Enter Scope scope, @Advice.Thrown Throwable thrown) {
|
||||
if (scope != null) {
|
||||
scope.close();
|
||||
}
|
||||
|
|
|
@ -8,11 +8,13 @@ package io.opentelemetry.javaagent.instrumentation.finaglehttp.v23_11;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class FinagleHttpInstrumentationModule extends InstrumentationModule {
|
||||
public class FinagleHttpInstrumentationModule extends InstrumentationModule
|
||||
implements ExperimentalInstrumentationModule {
|
||||
|
||||
public FinagleHttpInstrumentationModule() {
|
||||
super("finagle-http", "finagle-http-23.11");
|
||||
|
@ -27,9 +29,17 @@ public class FinagleHttpInstrumentationModule extends InstrumentationModule {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndyModule() {
|
||||
// injects helpers to access package-private members
|
||||
return false;
|
||||
public String getModuleGroup() {
|
||||
// relies on netty and needs access to common netty instrumentation classes
|
||||
return "netty";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> injectedClassNames() {
|
||||
// these are injected so that they can access package-private members
|
||||
return Arrays.asList(
|
||||
"com.twitter.finagle.ChannelTransportHelpers",
|
||||
"io.netty.channel.OpenTelemetryChannelInitializerDelegate");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -42,9 +42,10 @@ public class H2StreamChannelInitInstrumentation implements TypeInstrumentation {
|
|||
public static class InitServerAdvice {
|
||||
|
||||
@Advice.OnMethodExit
|
||||
public static void handleExit(
|
||||
@Advice.Return(readOnly = false) ChannelInitializer<Channel> initializer) {
|
||||
initializer = Helpers.wrapServer(initializer);
|
||||
@Advice.AssignReturned.ToReturned
|
||||
public static ChannelInitializer<Channel> handleExit(
|
||||
@Advice.Return ChannelInitializer<Channel> initializer) {
|
||||
return Helpers.wrapServer(initializer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,9 +53,10 @@ public class H2StreamChannelInitInstrumentation implements TypeInstrumentation {
|
|||
public static class InitClientAdvice {
|
||||
|
||||
@Advice.OnMethodExit
|
||||
public static void handleExit(
|
||||
@Advice.Return(readOnly = false) ChannelInitializer<Channel> initializer) {
|
||||
initializer = Helpers.wrapClient(initializer);
|
||||
@Advice.AssignReturned.ToReturned
|
||||
public static ChannelInitializer<Channel> handleExit(
|
||||
@Advice.Return ChannelInitializer<Channel> initializer) {
|
||||
return Helpers.wrapClient(initializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import io.opentelemetry.javaagent.bootstrap.executors.ContextPropagatingRunnable
|
|||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
|
@ -35,13 +36,14 @@ public class LocalSchedulerActivationInstrumentation implements TypeInstrumentat
|
|||
public static class WrapRunnableAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void wrap(@Advice.Argument(value = 0, readOnly = false) Runnable task) {
|
||||
@Advice.AssignReturned.ToArguments(@ToArgument(0))
|
||||
public static Runnable wrap(@Advice.Argument(value = 0) Runnable task) {
|
||||
if (task == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
Context context = Java8BytecodeBridge.currentContext();
|
||||
task = ContextPropagatingRunnable.propagateContext(task, context);
|
||||
return ContextPropagatingRunnable.propagateContext(task, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ 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.asm.Advice.AssignReturned.ToArguments.ToArgument;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import scala.Function1;
|
||||
|
@ -34,13 +35,13 @@ public class PromiseMonitoredInstrumentation implements TypeInstrumentation {
|
|||
public static class WrapFunctionAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void wrap(
|
||||
@Advice.Argument(value = 1, readOnly = false) Function1<?, ?> function1) {
|
||||
@Advice.AssignReturned.ToArguments(@ToArgument(1))
|
||||
public static Function1<?, ?> wrap(@Advice.Argument(value = 1) Function1<?, ?> function1) {
|
||||
if (function1 == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
function1 = Function1Wrapper.wrap(function1);
|
||||
return Function1Wrapper.wrap(function1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,15 +10,22 @@ import static java.util.Arrays.asList;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import java.util.List;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class TwitterUtilCoreInstrumentationModule extends InstrumentationModule {
|
||||
public class TwitterUtilCoreInstrumentationModule extends InstrumentationModule
|
||||
implements ExperimentalInstrumentationModule {
|
||||
|
||||
public TwitterUtilCoreInstrumentationModule() {
|
||||
super("twitter-util-core");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleGroup() {
|
||||
return "netty";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return asList(
|
||||
|
|
|
@ -56,55 +56,54 @@ public class NettyChannelInstrumentation implements TypeInstrumentation {
|
|||
public static class ChannelConnectAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void onEnter(
|
||||
@Advice.This Channel channel,
|
||||
@Advice.Argument(0) SocketAddress remoteAddress,
|
||||
@Advice.Local("otelParentContext") Context parentContext,
|
||||
@Advice.Local("otelRequest") NettyConnectionRequest request,
|
||||
@Advice.Local("otelTimer") Timer timer) {
|
||||
public static NettyScope onEnter(
|
||||
@Advice.This Channel channel, @Advice.Argument(0) SocketAddress remoteAddress) {
|
||||
|
||||
parentContext = Java8BytecodeBridge.currentContext();
|
||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||
Span span = Java8BytecodeBridge.spanFromContext(parentContext);
|
||||
if (!span.getSpanContext().isValid()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
VirtualField<Channel, NettyConnectionContext> virtualField =
|
||||
VirtualField.find(Channel.class, NettyConnectionContext.class);
|
||||
if (virtualField.get(channel) != null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
virtualField.set(channel, new NettyConnectionContext(parentContext));
|
||||
|
||||
request = NettyConnectionRequest.connect(remoteAddress);
|
||||
timer = Timer.start();
|
||||
NettyConnectionRequest request = NettyConnectionRequest.connect(remoteAddress);
|
||||
Timer timer = Timer.start();
|
||||
|
||||
return new NettyScope(parentContext, request, timer);
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||
public static void onExit(
|
||||
@Advice.Return ChannelFuture channelFuture,
|
||||
@Advice.Thrown Throwable error,
|
||||
@Advice.Local("otelParentContext") Context parentContext,
|
||||
@Advice.Local("otelRequest") NettyConnectionRequest request,
|
||||
@Advice.Local("otelTimer") Timer timer) {
|
||||
@Advice.Enter NettyScope nettyScope) {
|
||||
|
||||
if (request == null) {
|
||||
if (nettyScope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (error != null) {
|
||||
if (connectionInstrumenter().shouldStart(parentContext, request)) {
|
||||
if (connectionInstrumenter()
|
||||
.shouldStart(nettyScope.getParentContext(), nettyScope.getRequest())) {
|
||||
InstrumenterUtil.startAndEnd(
|
||||
connectionInstrumenter(),
|
||||
parentContext,
|
||||
request,
|
||||
nettyScope.getParentContext(),
|
||||
nettyScope.getRequest(),
|
||||
null,
|
||||
error,
|
||||
timer.startTime(),
|
||||
timer.now());
|
||||
nettyScope.getTimer().startTime(),
|
||||
nettyScope.getTimer().now());
|
||||
}
|
||||
} else {
|
||||
channelFuture.addListener(new ConnectionListener(parentContext, request, timer));
|
||||
channelFuture.addListener(
|
||||
new ConnectionListener(
|
||||
nettyScope.getParentContext(), nettyScope.getRequest(), nettyScope.getTimer()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,25 +51,25 @@ public class NettyChannelPipelineInstrumentation implements TypeInstrumentation
|
|||
public static class ChannelPipelineAdd2ArgsAdvice {
|
||||
|
||||
@Advice.OnMethodEnter
|
||||
public static void checkDepth(
|
||||
@Advice.This ChannelPipeline pipeline,
|
||||
@Advice.Argument(1) ChannelHandler handler,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
public static CallDepth checkDepth(
|
||||
@Advice.This ChannelPipeline pipeline, @Advice.Argument(1) ChannelHandler handler) {
|
||||
// Pipelines are created once as a factory and then copied multiple times using the same add
|
||||
// methods as we are hooking. If our handler has already been added we need to remove it so we
|
||||
// don't end up with duplicates (this throws an exception)
|
||||
if (pipeline.get(handler.getClass().getName()) != null) {
|
||||
pipeline.remove(handler.getClass().getName());
|
||||
}
|
||||
callDepth = CallDepth.forClass(ChannelPipeline.class);
|
||||
CallDepth callDepth = CallDepth.forClass(ChannelPipeline.class);
|
||||
callDepth.getAndIncrement();
|
||||
return callDepth;
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void addHandler(
|
||||
@Advice.This ChannelPipeline pipeline,
|
||||
@Advice.Argument(1) ChannelHandler handler,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
@Advice.Enter CallDepth callDepth) {
|
||||
|
||||
if (callDepth.decrementAndGet() > 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -82,29 +82,28 @@ public class NettyChannelPipelineInstrumentation implements TypeInstrumentation
|
|||
public static class ChannelPipelineAdd3ArgsAdvice {
|
||||
|
||||
@Advice.OnMethodEnter
|
||||
public static void checkDepth(
|
||||
@Advice.This ChannelPipeline pipeline,
|
||||
@Advice.Argument(2) ChannelHandler handler,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
public static CallDepth checkDepth(
|
||||
@Advice.This ChannelPipeline pipeline, @Advice.Argument(2) ChannelHandler handler) {
|
||||
// Pipelines are created once as a factory and then copied multiple times using the same add
|
||||
// methods as we are hooking. If our handler has already been added we need to remove it so we
|
||||
// don't end up with duplicates (this throws an exception)
|
||||
if (pipeline.get(handler.getClass().getName()) != null) {
|
||||
pipeline.remove(handler.getClass().getName());
|
||||
}
|
||||
callDepth = CallDepth.forClass(ChannelPipeline.class);
|
||||
CallDepth callDepth = CallDepth.forClass(ChannelPipeline.class);
|
||||
callDepth.getAndIncrement();
|
||||
return callDepth;
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void addHandler(
|
||||
@Advice.This ChannelPipeline pipeline,
|
||||
@Advice.Argument(2) ChannelHandler handler,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
@Advice.Enter CallDepth callDepth) {
|
||||
|
||||
if (callDepth.decrementAndGet() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelPipelineUtil.wrapHandler(pipeline, handler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,13 @@ import static java.util.Arrays.asList;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import java.util.List;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class NettyInstrumentationModule extends InstrumentationModule {
|
||||
public class NettyInstrumentationModule extends InstrumentationModule
|
||||
implements ExperimentalInstrumentationModule {
|
||||
public NettyInstrumentationModule() {
|
||||
super("netty", "netty-3.8");
|
||||
}
|
||||
|
@ -25,6 +27,11 @@ public class NettyInstrumentationModule extends InstrumentationModule {
|
|||
return hasClassesNamed("org.jboss.netty.handler.codec.http.HttpMessage");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleGroup() {
|
||||
return "netty";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return asList(
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.netty.v3_8;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.netty.common.internal.NettyConnectionRequest;
|
||||
import io.opentelemetry.instrumentation.netty.common.internal.Timer;
|
||||
|
||||
/** Container used to carry state between enter and exit advices */
|
||||
public class NettyScope {
|
||||
|
||||
private final Context parentContext;
|
||||
private final NettyConnectionRequest request;
|
||||
private final Timer timer;
|
||||
|
||||
public NettyScope(Context parentContext, NettyConnectionRequest request, Timer timer) {
|
||||
this.parentContext = parentContext;
|
||||
this.request = request;
|
||||
this.timer = timer;
|
||||
}
|
||||
|
||||
public Context getParentContext() {
|
||||
return parentContext;
|
||||
}
|
||||
|
||||
public NettyConnectionRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public Timer getTimer() {
|
||||
return timer;
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
|
@ -154,11 +155,13 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
|
|||
public static class RemoveLastAdvice {
|
||||
|
||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||
public static void removeHandler(
|
||||
@Advice.This ChannelPipeline pipeline,
|
||||
@Advice.Return(readOnly = false) ChannelHandler handler) {
|
||||
@Advice.AssignReturned.ToReturned
|
||||
public static ChannelHandler removeHandler(
|
||||
@Advice.This ChannelPipeline pipeline, @Advice.Return ChannelHandler returnHandler) {
|
||||
VirtualField<ChannelHandler, ChannelHandler> virtualField =
|
||||
VirtualField.find(ChannelHandler.class, ChannelHandler.class);
|
||||
// TODO remove this extra variable when migrating to "indy only" instrumentation.
|
||||
ChannelHandler handler = returnHandler;
|
||||
ChannelHandler ourHandler = virtualField.get(handler);
|
||||
if (ourHandler != null) {
|
||||
// Context is null when our handler has already been removed. This happens when calling
|
||||
|
@ -176,6 +179,7 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
|
|||
handler = pipeline.removeLast();
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,9 +187,14 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
|
|||
public static class AddAfterAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void addAfterHandler(
|
||||
@Advice.This ChannelPipeline pipeline,
|
||||
@Advice.Argument(value = 1, readOnly = false) String name) {
|
||||
@Advice.AssignReturned.ToArguments(@ToArgument(1))
|
||||
public static String addAfterHandler(
|
||||
@Advice.This ChannelPipeline pipeline, @Advice.Argument(value = 1) String nameArg) {
|
||||
// TODO remove this extra variable when migrating to "indy only" instrumentation.
|
||||
// using an intermediate variable is required to keep the advice work with "inlined" and
|
||||
// "indy" this is probably a minor side-effect of using @Advice.AssignReturned.ToArguments
|
||||
// with and inlined advice.
|
||||
String name = nameArg;
|
||||
ChannelHandler handler = pipeline.get(name);
|
||||
if (handler != null) {
|
||||
VirtualField<ChannelHandler, ChannelHandler> virtualField =
|
||||
|
@ -195,6 +204,7 @@ public abstract class AbstractNettyChannelPipelineInstrumentation implements Typ
|
|||
name = ourHandler.getClass().getName();
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
|||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
|
@ -58,22 +59,30 @@ public class NettyFutureInstrumentation implements TypeInstrumentation {
|
|||
public static class AddListenerAdvice {
|
||||
|
||||
@Advice.OnMethodEnter
|
||||
public static void wrapListener(
|
||||
@Advice.Argument(value = 0, readOnly = false)
|
||||
GenericFutureListener<? extends Future<?>> listener) {
|
||||
@Advice.AssignReturned.ToArguments(@ToArgument(0))
|
||||
public static GenericFutureListener<? extends Future<?>> wrapListener(
|
||||
@Advice.Argument(value = 0) GenericFutureListener<? extends Future<?>> listenerArg) {
|
||||
|
||||
// TODO remove this extra variable when migrating to "indy only" instrumentation.
|
||||
GenericFutureListener<? extends Future<?>> listener = listenerArg;
|
||||
if (FutureListenerWrappers.shouldWrap(listener)) {
|
||||
listener = FutureListenerWrappers.wrap(Java8BytecodeBridge.currentContext(), listener);
|
||||
}
|
||||
return listener;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class AddListenersAdvice {
|
||||
|
||||
// here the AsScalar allows to assign the value of the returned array to the argument value,
|
||||
// otherwise it's considered to be an Object[] that contains the arguments/return value/thrown
|
||||
// exception assignments that bytebuddy has to do after the advice is invoked.
|
||||
@Advice.OnMethodEnter
|
||||
public static void wrapListener(
|
||||
@Advice.Argument(value = 0, readOnly = false)
|
||||
GenericFutureListener<? extends Future<?>>[] listeners) {
|
||||
@Advice.AssignReturned.AsScalar
|
||||
@Advice.AssignReturned.ToArguments(@ToArgument(0))
|
||||
public static Object[] wrapListener(
|
||||
@Advice.Argument(value = 0) GenericFutureListener<? extends Future<?>>[] listeners) {
|
||||
|
||||
Context context = Java8BytecodeBridge.currentContext();
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
|
@ -86,7 +95,7 @@ public class NettyFutureInstrumentation implements TypeInstrumentation {
|
|||
wrappedListeners[i] = listeners[i];
|
||||
}
|
||||
}
|
||||
listeners = wrappedListeners;
|
||||
return wrappedListeners;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,20 +103,24 @@ public class NettyFutureInstrumentation implements TypeInstrumentation {
|
|||
public static class RemoveListenerAdvice {
|
||||
|
||||
@Advice.OnMethodEnter
|
||||
public static void wrapListener(
|
||||
@Advice.Argument(value = 0, readOnly = false)
|
||||
GenericFutureListener<? extends Future<?>> listener) {
|
||||
listener = FutureListenerWrappers.getWrapper(listener);
|
||||
@Advice.AssignReturned.ToArguments(@ToArgument(0))
|
||||
public static GenericFutureListener<? extends Future<?>> wrapListener(
|
||||
@Advice.Argument(value = 0) GenericFutureListener<? extends Future<?>> listener) {
|
||||
return FutureListenerWrappers.getWrapper(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class RemoveListenersAdvice {
|
||||
|
||||
// here the AsScalar allows to assign the value of the returned array to the argument value,
|
||||
// otherwise it's considered to be an Object[] that contains the arguments/return value/thrown
|
||||
// exception assignments that bytebuddy has to do after the advice is invoked.
|
||||
@Advice.OnMethodEnter
|
||||
public static void wrapListener(
|
||||
@Advice.Argument(value = 0, readOnly = false)
|
||||
GenericFutureListener<? extends Future<?>>[] listeners) {
|
||||
@Advice.AssignReturned.AsScalar
|
||||
@Advice.AssignReturned.ToArguments(@ToArgument(0))
|
||||
public static Object[] wrapListener(
|
||||
@Advice.Argument(value = 0) GenericFutureListener<? extends Future<?>>[] listeners) {
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
GenericFutureListener<? extends Future<?>>[] wrappedListeners =
|
||||
|
@ -115,7 +128,7 @@ public class NettyFutureInstrumentation implements TypeInstrumentation {
|
|||
for (int i = 0; i < listeners.length; ++i) {
|
||||
wrappedListeners[i] = FutureListenerWrappers.getWrapper(listeners[i]);
|
||||
}
|
||||
listeners = wrappedListeners;
|
||||
return wrappedListeners;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.netty.v4.common;
|
||||
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.netty.common.internal.NettyConnectionRequest;
|
||||
import io.opentelemetry.instrumentation.netty.v4.common.internal.client.ConnectionCompleteListener;
|
||||
import io.opentelemetry.instrumentation.netty.v4.common.internal.client.NettyConnectionInstrumenter;
|
||||
|
||||
/** Container used to carry state between enter and exit advices */
|
||||
public class NettyScope {
|
||||
|
||||
private final Context context;
|
||||
private final NettyConnectionRequest request;
|
||||
private final Scope scope;
|
||||
|
||||
private NettyScope(Context context, NettyConnectionRequest request, Scope scope) {
|
||||
this.context = context;
|
||||
this.request = request;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public static NettyScope startNew(
|
||||
NettyConnectionInstrumenter instrumenter,
|
||||
Context parentContext,
|
||||
NettyConnectionRequest request) {
|
||||
Context context = instrumenter.start(parentContext, request);
|
||||
return new NettyScope(context, request, context.makeCurrent());
|
||||
}
|
||||
|
||||
public static void end(
|
||||
NettyScope nettyScope,
|
||||
NettyConnectionInstrumenter instrumenter,
|
||||
ChannelPromise channelPromise,
|
||||
Throwable throwable) {
|
||||
|
||||
if (nettyScope == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
nettyScope.scope.close();
|
||||
|
||||
if (throwable != null) {
|
||||
instrumenter.end(nettyScope.context, nettyScope.request, null, throwable);
|
||||
} else {
|
||||
channelPromise.addListener(
|
||||
new ConnectionCompleteListener(instrumenter, nettyScope.context, nettyScope.request));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,12 +11,11 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.netty.common.internal.NettyConnectionRequest;
|
||||
import io.opentelemetry.instrumentation.netty.v4.common.internal.client.ConnectionCompleteListener;
|
||||
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
import io.opentelemetry.javaagent.instrumentation.netty.v4.common.NettyScope;
|
||||
import java.net.SocketAddress;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
|
@ -40,42 +39,24 @@ public class BootstrapInstrumentation implements TypeInstrumentation {
|
|||
@SuppressWarnings("unused")
|
||||
public static class ConnectAdvice {
|
||||
@Advice.OnMethodEnter
|
||||
public static void startConnect(
|
||||
@Advice.Argument(2) SocketAddress remoteAddress,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelRequest") NettyConnectionRequest request,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
public static NettyScope startConnect(@Advice.Argument(2) SocketAddress remoteAddress) {
|
||||
|
||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||
request = NettyConnectionRequest.connect(remoteAddress);
|
||||
NettyConnectionRequest request = NettyConnectionRequest.connect(remoteAddress);
|
||||
|
||||
if (!connectionInstrumenter().shouldStart(parentContext, request)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
context = connectionInstrumenter().start(parentContext, request);
|
||||
scope = context.makeCurrent();
|
||||
return NettyScope.startNew(connectionInstrumenter(), parentContext, request);
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void endConnect(
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Argument(4) ChannelPromise channelPromise,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelRequest") NettyConnectionRequest request,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
@Advice.Enter NettyScope enterScope) {
|
||||
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
scope.close();
|
||||
|
||||
if (throwable != null) {
|
||||
connectionInstrumenter().end(context, request, null, throwable);
|
||||
} else {
|
||||
channelPromise.addListener(
|
||||
new ConnectionCompleteListener(connectionInstrumenter(), context, request));
|
||||
}
|
||||
NettyScope.end(enterScope, connectionInstrumenter(), channelPromise, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,16 +54,18 @@ public class NettyChannelPipelineInstrumentation
|
|||
public static class ChannelPipelineAddAdvice {
|
||||
|
||||
@Advice.OnMethodEnter
|
||||
public static void trackCallDepth(@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
callDepth = CallDepth.forClass(ChannelPipeline.class);
|
||||
public static CallDepth trackCallDepth() {
|
||||
CallDepth callDepth = CallDepth.forClass(ChannelPipeline.class);
|
||||
callDepth.getAndIncrement();
|
||||
return callDepth;
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void addHandler(
|
||||
@Advice.This ChannelPipeline pipeline,
|
||||
@Advice.Argument(2) ChannelHandler handler,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
@Advice.Enter CallDepth callDepth) {
|
||||
|
||||
if (callDepth.decrementAndGet() > 0) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -12,12 +12,14 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import io.opentelemetry.javaagent.instrumentation.netty.v4.common.NettyFutureInstrumentation;
|
||||
import java.util.List;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class NettyInstrumentationModule extends InstrumentationModule {
|
||||
public class NettyInstrumentationModule extends InstrumentationModule
|
||||
implements ExperimentalInstrumentationModule {
|
||||
public NettyInstrumentationModule() {
|
||||
super("netty", "netty-4.0");
|
||||
}
|
||||
|
@ -31,6 +33,11 @@ public class NettyInstrumentationModule extends InstrumentationModule {
|
|||
not(hasClassesNamed("io.netty.handler.codec.http.CombinedHttpHeaders")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleGroup() {
|
||||
return "netty";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return asList(
|
||||
|
|
|
@ -16,14 +16,14 @@ import io.netty.channel.ChannelPromise;
|
|||
import io.netty.resolver.AddressResolverGroup;
|
||||
import io.netty.resolver.DefaultAddressResolverGroup;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.netty.common.internal.NettyConnectionRequest;
|
||||
import io.opentelemetry.instrumentation.netty.v4.common.internal.client.ConnectionCompleteListener;
|
||||
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
import io.opentelemetry.javaagent.instrumentation.netty.v4.common.NettyScope;
|
||||
import java.net.SocketAddress;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
|
@ -66,50 +66,34 @@ public class BootstrapInstrumentation implements TypeInstrumentation {
|
|||
public static class SetResolverAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void onEnter(
|
||||
@Advice.Argument(value = 0, readOnly = false) AddressResolverGroup<?> resolver) {
|
||||
resolver = InstrumentedAddressResolverGroup.wrap(connectionInstrumenter(), resolver);
|
||||
@Advice.AssignReturned.ToArguments(@ToArgument(0))
|
||||
public static AddressResolverGroup<?> onEnter(
|
||||
@Advice.Argument(value = 0) AddressResolverGroup<?> resolver) {
|
||||
return InstrumentedAddressResolverGroup.wrap(connectionInstrumenter(), resolver);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class ConnectAdvice {
|
||||
@Advice.OnMethodEnter
|
||||
public static void startConnect(
|
||||
@Advice.Argument(0) SocketAddress remoteAddress,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelRequest") NettyConnectionRequest request,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
public static NettyScope startConnect(@Advice.Argument(0) SocketAddress remoteAddress) {
|
||||
|
||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||
request = NettyConnectionRequest.connect(remoteAddress);
|
||||
NettyConnectionRequest request = NettyConnectionRequest.connect(remoteAddress);
|
||||
if (!connectionInstrumenter().shouldStart(parentContext, request)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
context = connectionInstrumenter().start(parentContext, request);
|
||||
scope = context.makeCurrent();
|
||||
return NettyScope.startNew(connectionInstrumenter(), parentContext, request);
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void endConnect(
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Argument(2) ChannelPromise channelPromise,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelRequest") NettyConnectionRequest request,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
@Advice.Enter NettyScope enterScope) {
|
||||
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
scope.close();
|
||||
|
||||
if (throwable != null) {
|
||||
connectionInstrumenter().end(context, request, null, throwable);
|
||||
} else {
|
||||
channelPromise.addListener(
|
||||
new ConnectionCompleteListener(connectionInstrumenter(), context, request));
|
||||
}
|
||||
NettyScope.end(enterScope, connectionInstrumenter(), channelPromise, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,9 +52,7 @@ public class NettyChannelPipelineInstrumentation
|
|||
public static class ChannelPipelineAddAdvice {
|
||||
|
||||
@Advice.OnMethodEnter
|
||||
public static void trackCallDepth(
|
||||
@Advice.Argument(2) ChannelHandler handler,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
public static CallDepth trackCallDepth(@Advice.Argument(2) ChannelHandler handler) {
|
||||
// Previously we used one unique call depth tracker for all handlers, using
|
||||
// ChannelPipeline.class as a key.
|
||||
// The problem with this approach is that it does not work with netty's
|
||||
|
@ -64,8 +62,9 @@ public class NettyChannelPipelineInstrumentation
|
|||
// Using the specific handler key instead of the generic ChannelPipeline.class will help us
|
||||
// both to handle such cases and avoid adding our additional handlers in case of internal
|
||||
// calls of `addLast` to other method overloads with a compatible signature.
|
||||
callDepth = CallDepth.forClass(handler.getClass());
|
||||
CallDepth callDepth = CallDepth.forClass(handler.getClass());
|
||||
callDepth.getAndIncrement();
|
||||
return callDepth;
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
|
@ -73,7 +72,8 @@ public class NettyChannelPipelineInstrumentation
|
|||
@Advice.This ChannelPipeline pipeline,
|
||||
@Advice.Argument(1) String handlerName,
|
||||
@Advice.Argument(2) ChannelHandler handler,
|
||||
@Advice.Local("otelCallDepth") CallDepth callDepth) {
|
||||
@Advice.Enter CallDepth callDepth) {
|
||||
|
||||
if (callDepth.decrementAndGet() > 0) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -11,12 +11,14 @@ import static java.util.Arrays.asList;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import io.opentelemetry.javaagent.instrumentation.netty.v4.common.NettyFutureInstrumentation;
|
||||
import java.util.List;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class NettyInstrumentationModule extends InstrumentationModule {
|
||||
public class NettyInstrumentationModule extends InstrumentationModule
|
||||
implements ExperimentalInstrumentationModule {
|
||||
public NettyInstrumentationModule() {
|
||||
super("netty", "netty-4.1");
|
||||
}
|
||||
|
@ -29,10 +31,8 @@ public class NettyInstrumentationModule extends InstrumentationModule {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndyModule() {
|
||||
// netty instrumentation classes are used in other instrumentations which causes class cast
|
||||
// exceptions
|
||||
return false;
|
||||
public String getModuleGroup() {
|
||||
return "netty";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,22 +10,20 @@ import static java.util.Arrays.asList;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import java.util.List;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class RatpackInstrumentationModule extends InstrumentationModule {
|
||||
public class RatpackInstrumentationModule extends InstrumentationModule
|
||||
implements ExperimentalInstrumentationModule {
|
||||
public RatpackInstrumentationModule() {
|
||||
super("ratpack", "ratpack-1.4");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndyModule() {
|
||||
// java.lang.ClassCastException: class
|
||||
// io.opentelemetry.javaagent.shaded.instrumentation.netty.v4_1.internal.AutoValue_ServerContext
|
||||
// cannot be cast to class
|
||||
// io.opentelemetry.javaagent.shaded.instrumentation.netty.v4_1.internal.ServerContext
|
||||
// (io.opentelemetry.javaagent.shaded.instrumentation.netty.v4_1.internal.AutoValue_ServerContext is in unnamed module of loader 'app'; io.opentelemetry.javaagent.shaded.instrumentation.netty.v4_1.internal.ServerContext is in unnamed module of loader io.opentelemetry.javaagent.tooling.instrumentation.indy.InstrumentationModuleClassLoader @7f088b5c)
|
||||
return false;
|
||||
public String getModuleGroup() {
|
||||
// relies on netty
|
||||
return "netty";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,10 +10,12 @@ import static java.util.Arrays.asList;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import java.util.List;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class GatewayInstrumentationModule extends InstrumentationModule {
|
||||
public class GatewayInstrumentationModule extends InstrumentationModule
|
||||
implements ExperimentalInstrumentationModule {
|
||||
|
||||
public GatewayInstrumentationModule() {
|
||||
super("spring-cloud-gateway");
|
||||
|
@ -24,6 +26,12 @@ public class GatewayInstrumentationModule extends InstrumentationModule {
|
|||
return asList(new HandlerAdapterInstrumentation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleGroup() {
|
||||
// relies on netty
|
||||
return "netty";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int order() {
|
||||
// Later than Spring Webflux.
|
||||
|
|
|
@ -8,20 +8,22 @@ package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.re
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class ReactorNettyInstrumentationModule extends InstrumentationModule {
|
||||
public class ReactorNettyInstrumentationModule extends InstrumentationModule
|
||||
implements ExperimentalInstrumentationModule {
|
||||
|
||||
public ReactorNettyInstrumentationModule() {
|
||||
super("reactor-netty", "reactor-netty-server");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndyModule() {
|
||||
// uses classes from netty instrumentation that are now in a different class loader
|
||||
return false;
|
||||
public String getModuleGroup() {
|
||||
// relies on netty
|
||||
return "netty";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue