Refactor Instrumenters into InstrumentationModules - R, S, T, V (#1576)

This commit is contained in:
Mateusz Rzeszutek 2020-11-10 03:48:52 +01:00 committed by GitHub
parent 087a9cbc4e
commit 9d2db827b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 896 additions and 734 deletions

View File

@ -22,7 +22,6 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import com.google.auto.service.AutoService;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Consumer;
@ -34,7 +33,7 @@ import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
@ -44,12 +43,7 @@ import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public class RabbitChannelInstrumentation extends Instrumenter.Default {
public RabbitChannelInstrumentation() {
super("amqp", "rabbitmq");
}
final class RabbitChannelInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
@ -62,17 +56,6 @@ public class RabbitChannelInstrumentation extends Instrumenter.Default {
return implementsInterface(named("com.rabbitmq.client.Channel"));
}
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".RabbitTracer",
packageName + ".TextMapInjectAdapter",
packageName + ".TextMapExtractAdapter",
packageName + ".TracedDelegatingConsumer",
RabbitCommandInstrumentation.class.getName() + "$SpanHolder",
};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
// We want the advice applied in a specific order, so use an ordered map.

View File

@ -13,22 +13,16 @@ import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService;
import com.rabbitmq.client.Command;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public class RabbitCommandInstrumentation extends Instrumenter.Default {
public RabbitCommandInstrumentation() {
super("amqp", "rabbitmq");
}
final class RabbitCommandInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
@ -41,17 +35,6 @@ public class RabbitCommandInstrumentation extends Instrumenter.Default {
return implementsInterface(named("com.rabbitmq.client.Command"));
}
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".RabbitTracer",
// These are only used by muzzleCheck:
packageName + ".TextMapExtractAdapter",
packageName + ".TracedDelegatingConsumer",
RabbitCommandInstrumentation.class.getName() + "$SpanHolder"
};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
@ -72,14 +55,5 @@ public class RabbitCommandInstrumentation extends Instrumenter.Default {
tracer().onCommand(span, command);
}
}
/**
* This instrumentation will match with 2.6, but the channel instrumentation only matches with
* 2.7 because of TracedDelegatingConsumer. This unused method is added to ensure consistent
* muzzle validation by preventing match with 2.6.
*/
public static void muzzleCheck(TracedDelegatingConsumer consumer) {
consumer.handleRecoverOk(null);
}
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.rabbitmq.amqp;
import static java.util.Arrays.asList;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
@AutoService(InstrumentationModule.class)
public class RabbitMqInstrumentationModule extends InstrumentationModule {
public RabbitMqInstrumentationModule() {
super("amqp", "rabbitmq");
}
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".RabbitTracer",
packageName + ".TextMapInjectAdapter",
packageName + ".TextMapExtractAdapter",
packageName + ".TracedDelegatingConsumer",
RabbitCommandInstrumentation.class.getName() + "$SpanHolder",
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new RabbitChannelInstrumentation(), new RabbitCommandInstrumentation());
}
}

View File

@ -12,22 +12,15 @@ import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import ratpack.func.Block;
import ratpack.path.PathBinding;
@AutoService(Instrumenter.class)
public final class ContinuationInstrumentation extends Instrumenter.Default {
public ContinuationInstrumentation() {
super("ratpack");
}
final class ContinuationInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
@ -41,11 +34,6 @@ public final class ContinuationInstrumentation extends Instrumenter.Default {
.<TypeDescription>and(implementsInterface(named("ratpack.exec.internal.Continuation")));
}
@Override
public String[] helperClassNames() {
return new String[] {packageName + ".BlockWrapper"};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
@ -59,10 +47,5 @@ public final class ContinuationInstrumentation extends Instrumenter.Default {
public static void wrap(@Advice.Argument(value = 0, readOnly = false) Block block) {
block = BlockWrapper.wrapIfNeeded(block);
}
public void muzzleCheck(PathBinding binding) {
// This was added in 1.4. Added here to ensure consistency with other instrumentation.
binding.getDescription();
}
}
}

View File

@ -10,8 +10,7 @@ import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
@ -19,25 +18,14 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import ratpack.exec.internal.Continuation;
import ratpack.func.Action;
import ratpack.path.PathBinding;
@AutoService(Instrumenter.class)
public final class DefaultExecutionInstrumentation extends Instrumenter.Default {
public DefaultExecutionInstrumentation() {
super("ratpack");
}
final class DefaultExecutionInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<? super TypeDescription> typeMatcher() {
return named("ratpack.exec.internal.DefaultExecution");
}
@Override
public String[] helperClassNames() {
return new String[] {packageName + ".ActionWrapper"};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
@ -56,10 +44,5 @@ public final class DefaultExecutionInstrumentation extends Instrumenter.Default
onError = ActionWrapper.wrapIfNeeded(onError);
segment = ActionWrapper.wrapIfNeeded(segment);
}
public void muzzleCheck(PathBinding binding) {
// This was added in 1.4. Added here to ensure consistency with other instrumentation.
binding.getDescription();
}
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.ratpack;
import static java.util.Arrays.asList;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
@AutoService(InstrumentationModule.class)
public class RatpackInstrumentationModule extends InstrumentationModule {
public RatpackInstrumentationModule() {
super("ratpack");
}
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".ActionWrapper",
packageName + ".BlockWrapper",
packageName + ".RatpackTracer",
packageName + ".TracingHandler",
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(
new ContinuationInstrumentation(),
new DefaultExecutionInstrumentation(),
new ServerErrorHandlerInstrumentation(),
new ServerRegistryInstrumentation());
}
}

View File

@ -13,19 +13,13 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public class ServerErrorHandlerInstrumentation extends Instrumenter.Default {
public ServerErrorHandlerInstrumentation() {
super("ratpack");
}
final class ServerErrorHandlerInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
@ -38,19 +32,12 @@ public class ServerErrorHandlerInstrumentation extends Instrumenter.Default {
return not(isAbstract()).and(implementsInterface(named("ratpack.error.ServerErrorHandler")));
}
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".RatpackTracer",
};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
named("error")
.and(takesArgument(0, named("ratpack.handling.Context")))
.and(takesArgument(1, Throwable.class)),
packageName + ".ErrorHandlerAdvice");
ErrorHandlerAdvice.class.getName());
}
}

View File

@ -10,36 +10,23 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isStatic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public class ServerRegistryInstrumentation extends Instrumenter.Default {
public ServerRegistryInstrumentation() {
super("ratpack");
}
final class ServerRegistryInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("ratpack.server.internal.ServerRegistry");
}
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".RatpackTracer", packageName + ".TracingHandler",
};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(isStatic()).and(named("buildBaseRegistry")),
packageName + ".ServerRegistryAdvice");
ServerRegistryAdvice.class.getName());
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.reactor;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer;
import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class ReactorHooksInstrumentation extends Instrumenter.Default {
public ReactorHooksInstrumentation() {
super("reactor-core");
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.instrumentation.reactor.TracingOperator$Lifter",
"io.opentelemetry.instrumentation.reactor.TracingOperator",
"io.opentelemetry.instrumentation.reactor.TracingSubscriber"
};
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("reactor.core.publisher.Hooks");
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isTypeInitializer().or(named("resetOnEachOperator")), packageName + ".ReactorHooksAdvice");
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.reactor;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer;
import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(InstrumentationModule.class)
public final class ReactorInstrumentationModule extends InstrumentationModule {
public ReactorInstrumentationModule() {
super("reactor-core");
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.instrumentation.reactor.TracingOperator$Lifter",
"io.opentelemetry.instrumentation.reactor.TracingOperator",
"io.opentelemetry.instrumentation.reactor.TracingSubscriber"
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new HooksInstrumentation());
}
private static final class HooksInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("reactor.core.publisher.Hooks");
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isTypeInitializer().or(named("resetOnEachOperator")), ReactorHooksAdvice.class.getName());
}
}
}

View File

@ -9,6 +9,7 @@ import static io.opentelemetry.javaagent.instrumentation.rediscala.RediscalaClie
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.safeHasSuperType;
import static io.opentelemetry.javaagent.tooling.matcher.NameMatchers.namedOneOf;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
@ -19,7 +20,9 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
@ -31,52 +34,59 @@ import scala.concurrent.Future;
import scala.runtime.AbstractFunction1;
import scala.util.Try;
@AutoService(Instrumenter.class)
public final class RediscalaInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public final class RediscalaInstrumentationModule extends InstrumentationModule {
public RediscalaInstrumentation() {
public RediscalaInstrumentationModule() {
super("rediscala", "redis");
}
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
return hasClassesNamed("redis.Request");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return safeHasSuperType(
namedOneOf(
"redis.ActorRequest",
"redis.Request",
"redis.BufferedRequest",
"redis.RoundRobinPoolRequest"));
}
@Override
public String[] helperClassNames() {
return new String[] {
RediscalaInstrumentation.class.getName() + "$OnCompleteHandler",
RediscalaInstrumentationModule.class.getName() + "$OnCompleteHandler",
packageName + ".RediscalaClientTracer",
};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod()
.and(isPublic())
.and(named("send"))
.and(takesArgument(0, named("redis.RedisCommand")))
.and(returns(named("scala.concurrent.Future"))),
RediscalaInstrumentation.class.getName() + "$RediscalaAdvice");
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new RequestInstrumentation());
}
private static final class RequestInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
return hasClassesNamed("redis.Request");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return safeHasSuperType(
namedOneOf(
"redis.ActorRequest",
"redis.Request",
"redis.BufferedRequest",
"redis.RoundRobinPoolRequest"));
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
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.Argument(0) RedisCommand<?, ?> cmd,
@Advice.Local("otelSpan") Span span,
@Advice.Local("otelScope") Scope scope) {
span = tracer().startSpan(cmd, cmd);

View File

@ -6,6 +6,7 @@
package io.opentelemetry.javaagent.instrumentation.redisson;
import static io.opentelemetry.javaagent.instrumentation.redisson.RedissonClientTracer.tracer;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -13,7 +14,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
@ -21,27 +24,35 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.redisson.client.RedisConnection;
@AutoService(Instrumenter.class)
public final class RedissonInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public final class RedissonInstrumentation extends InstrumentationModule {
public RedissonInstrumentation() {
super("redisson", "redis");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.redisson.client.RedisConnection");
}
@Override
public String[] helperClassNames() {
return new String[] {packageName + ".RedissonClientTracer"};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(named("send")), RedissonInstrumentation.class.getName() + "$RedissonAdvice");
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new RedisConnectionInstrumentation());
}
private static final class RedisConnectionInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.redisson.client.RedisConnection");
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(named("send")),
RedissonInstrumentation.class.getName() + "$RedissonAdvice");
}
}
public static class RedissonAdvice {

View File

@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.rmi.client;
import static io.opentelemetry.javaagent.instrumentation.rmi.client.RmiClientTracer.tracer;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -16,39 +17,48 @@ import com.google.auto.service.AutoService;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class RmiClientInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public final class RmiClientInstrumentationModule extends InstrumentationModule {
public RmiClientInstrumentation() {
public RmiClientInstrumentationModule() {
super("rmi", "rmi-client");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return extendsClass(named("sun.rmi.server.UnicastRef"));
}
@Override
public String[] helperClassNames() {
return new String[] {packageName + ".RmiClientTracer"};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod()
.and(named("invoke"))
.and(takesArgument(0, named("java.rmi.Remote")))
.and(takesArgument(1, named("java.lang.reflect.Method"))),
getClass().getName() + "$RmiClientAdvice");
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new ClientInstrumentation());
}
private static final class ClientInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return extendsClass(named("sun.rmi.server.UnicastRef"));
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod()
.and(named("invoke"))
.and(takesArgument(0, named("java.rmi.Remote")))
.and(takesArgument(1, named("java.lang.reflect.Method"))),
RmiClientInstrumentationModule.class.getName() + "$RmiClientAdvice");
}
}
public static class RmiClientAdvice {

View File

@ -0,0 +1,47 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.rmi.context;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonMap;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.instrumentation.rmi.context.client.RmiClientContextInstrumentation;
import io.opentelemetry.javaagent.instrumentation.rmi.context.server.RmiServerContextInstrumentation;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
import java.util.Map;
@AutoService(InstrumentationModule.class)
public class RmiContextPropagationInstrumentationModule extends InstrumentationModule {
public RmiContextPropagationInstrumentationModule() {
super("rmi", "rmi-context-propagator");
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPayload$InjectAdapter",
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPayload$ExtractAdapter",
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPayload",
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPropagator",
"io.opentelemetry.javaagent.instrumentation.rmi.context.server.ContextDispatcher",
"io.opentelemetry.javaagent.instrumentation.rmi.context.server.ContextDispatcher$NoopRemote"
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new RmiClientContextInstrumentation(), new RmiServerContextInstrumentation());
}
@Override
public Map<String, String> contextStore() {
// caching if a connection can support enhanced format
return singletonMap("sun.rmi.transport.Connection", "java.lang.Boolean");
}
}

View File

@ -12,12 +12,11 @@ import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.api.trace.Span;
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.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.rmi.server.ObjID;
import java.util.Map;
import net.bytebuddy.asm.Advice;
@ -47,34 +46,13 @@ import sun.rmi.transport.Connection;
* that instruction will essentially be garbage data and will cause the parsing loop to throw
* exception and shutdown the connection which we do not want
*/
@AutoService(Instrumenter.class)
public class RmiClientContextInstrumentation extends Instrumenter.Default {
public RmiClientContextInstrumentation() {
super("rmi", "rmi-context-propagator", "rmi-client-context-propagator");
}
public final class RmiClientContextInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<? super TypeDescription> typeMatcher() {
return extendsClass(named("sun.rmi.transport.StreamRemoteCall"));
}
@Override
public Map<String, String> contextStore() {
// caching if a connection can support enhanced format
return singletonMap("sun.rmi.transport.Connection", "java.lang.Boolean");
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPayload$InjectAdapter",
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPayload$ExtractAdapter",
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPayload",
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPropagator"
};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(

View File

@ -13,8 +13,7 @@ import static net.bytebuddy.matcher.ElementMatchers.isStatic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
@ -22,30 +21,13 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import sun.rmi.transport.Target;
@AutoService(Instrumenter.class)
public class RmiServerContextInstrumentation extends Instrumenter.Default {
public RmiServerContextInstrumentation() {
super("rmi", "rmi-context-propagator", "rmi-server-context-propagator");
}
public final class RmiServerContextInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<? super TypeDescription> typeMatcher() {
return extendsClass(named("sun.rmi.transport.ObjectTable"));
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPayload$InjectAdapter",
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPayload$ExtractAdapter",
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPayload",
"io.opentelemetry.javaagent.instrumentation.rmi.context.ContextPropagator",
packageName + ".ContextDispatcher",
packageName + ".ContextDispatcher$NoopRemote"
};
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(

View File

@ -8,6 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.rmi.server;
import static io.opentelemetry.javaagent.instrumentation.api.rmi.ThreadLocalContext.THREAD_LOCAL_CONTEXT;
import static io.opentelemetry.javaagent.instrumentation.rmi.server.RmiServerTracer.tracer;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
@ -20,17 +21,19 @@ import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.lang.reflect.Method;
import java.rmi.server.RemoteServer;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class RmiServerInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public final class RmiServerInstrumentation extends InstrumentationModule {
public RmiServerInstrumentation() {
super("rmi", "rmi-server");
@ -42,14 +45,22 @@ public final class RmiServerInstrumentation extends Instrumenter.Default {
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return extendsClass(named("java.rmi.server.RemoteServer"));
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new ServerInstrumentation());
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(isPublic()).and(not(isStatic())), getClass().getName() + "$ServerAdvice");
private static final class ServerInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return extendsClass(named("java.rmi.server.RemoteServer"));
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(isPublic()).and(not(isStatic())),
RmiServerInstrumentation.class.getName() + "$ServerAdvice");
}
}
public static class ServerAdvice {

View File

@ -0,0 +1,40 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.scalaconcurrent;
import static io.opentelemetry.javaagent.instrumentation.scalaconcurrent.ScalaForkJoinTaskInstrumentation.TASK_CLASS_NAME;
import static java.util.Arrays.asList;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.State;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
@AutoService(InstrumentationModule.class)
public class ScalaConcurrentInstrumentationModule extends InstrumentationModule {
public ScalaConcurrentInstrumentationModule() {
super("java_concurrent", "scala_concurrent");
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new ScalaForkJoinPoolInstrumentation(), new ScalaForkJoinTaskInstrumentation());
}
@Override
public Map<String, String> contextStore() {
Map<String, String> map = new HashMap<>();
map.put(Runnable.class.getName(), State.class.getName());
map.put(Callable.class.getName(), State.class.getName());
map.put(TASK_CLASS_NAME, State.class.getName());
return Collections.unmodifiableMap(map);
}
}

View File

@ -5,18 +5,16 @@
package io.opentelemetry.javaagent.instrumentation.scalaconcurrent;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.nameMatches;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
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.State;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.HashMap;
import java.util.Map;
import net.bytebuddy.asm.Advice;
@ -25,12 +23,7 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import scala.concurrent.forkjoin.ForkJoinTask;
@AutoService(Instrumenter.class)
public final class ScalaForkJoinPoolInstrumentation extends Instrumenter.Default {
public ScalaForkJoinPoolInstrumentation() {
super("java_concurrent", "scala_concurrent");
}
final class ScalaForkJoinPoolInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
@ -38,11 +31,6 @@ public final class ScalaForkJoinPoolInstrumentation extends Instrumenter.Default
return named("scala.concurrent.forkjoin.ForkJoinPool");
}
@Override
public Map<String, String> contextStore() {
return singletonMap(ScalaForkJoinTaskInstrumentation.TASK_CLASS_NAME, State.class.getName());
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>();
@ -65,7 +53,7 @@ public final class ScalaForkJoinPoolInstrumentation extends Instrumenter.Default
@Advice.OnMethodEnter(suppress = Throwable.class)
public static State enterJobSubmit(
@Advice.Argument(value = 0, readOnly = false) ForkJoinTask task) {
@Advice.Argument(value = 0, readOnly = false) ForkJoinTask<?> task) {
if (ExecutorInstrumentationUtils.shouldAttachStateToTask(task)) {
ContextStore<ForkJoinTask, State> contextStore =
InstrumentationContext.get(ForkJoinTask.class, State.class);

View File

@ -13,15 +13,12 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import com.google.auto.service.AutoService;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.AdviceUtils;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.State;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import java.util.Collections;
import java.util.HashMap;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import java.util.concurrent.Callable;
import net.bytebuddy.asm.Advice;
@ -37,15 +34,10 @@ import scala.concurrent.forkjoin.ForkJoinTask;
* <p>Note: There are quite a few separate implementations of {@code ForkJoinTask}/{@code
* ForkJoinPool}: JVM, Akka, Scala, Netty to name a few. This class handles Scala version.
*/
@AutoService(Instrumenter.class)
public final class ScalaForkJoinTaskInstrumentation extends Instrumenter.Default {
final class ScalaForkJoinTaskInstrumentation implements TypeInstrumentation {
static final String TASK_CLASS_NAME = "scala.concurrent.forkjoin.ForkJoinTask";
public ScalaForkJoinTaskInstrumentation() {
super("java_concurrent", "scala_concurrent");
}
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
@ -57,15 +49,6 @@ public final class ScalaForkJoinTaskInstrumentation extends Instrumenter.Default
return extendsClass(named(TASK_CLASS_NAME));
}
@Override
public Map<String, String> contextStore() {
Map<String, String> map = new HashMap<>();
map.put(Runnable.class.getName(), State.class.getName());
map.put(Callable.class.getName(), State.class.getName());
map.put(TASK_CLASS_NAME, State.class.getName());
return Collections.unmodifiableMap(map);
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
@ -82,7 +65,7 @@ public final class ScalaForkJoinTaskInstrumentation extends Instrumenter.Default
* need to use that state.
*/
@Advice.OnMethodEnter(suppress = Throwable.class)
public static Scope enter(@Advice.This ForkJoinTask thiz) {
public static Scope enter(@Advice.This ForkJoinTask<?> thiz) {
ContextStore<ForkJoinTask, State> contextStore =
InstrumentationContext.get(ForkJoinTask.class, State.class);
Scope scope = AdviceUtils.startTaskScope(contextStore, thiz);

View File

@ -59,16 +59,16 @@ Next, request passes several other methods from Servlet specification, such as
`protected void org.springframework.web.servlet.FrameworkServlet#doGet(HttpServletRequest, HttpServletResponse)`.
They are the targets for `HttpServletInstrumentation`.
They are the targets for `HttpServletInstrumentationModule`.
From the observability point of view nothing of interest usually happens inside these methods.
Thus it usually does not make sense to create spans from them, as they would only add useless noise.
For this reason `HttpServletInstrumentation` is disabled by default.
In rare cases when you need it, you can enable it using configuration property `otel.integration.servlet-service.enabled`.
For this reason `HttpServletInstrumentationModule` is disabled by default.
In rare cases when you need it, you can enable it using configuration property `otel.instrumentation.servlet-service.enabled`.
In exactly the same situation are all other Servlet filters beyond the initial entry point.
Usually unimportant, they may be sometimes of interest during troubleshooting.
They are instrumented by `FilterInstrumentation` which is also disabled by default.
You can enable it with the configuration property `otel.integration.servlet-filter.enabled`.
They are instrumented by `FilterInstrumentationModule` which is also disabled by default.
You can enable it with the configuration property `otel.instrumentation.servlet-filter.enabled`.
At last, request processing may reach the specific framework that your application uses.
In this case Spring MVC and `OwnerController.initCreationForm`.
@ -88,10 +88,10 @@ Of course, still adhering to OpenTelemetry
[semantic conventions](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md).
## Additional instrumentations
`RequestDispatcherInstrumentation` instruments `javax.servlet.RequestDispatcher.forward` and
`RequestDispatcherInstrumentationModule` instruments `javax.servlet.RequestDispatcher.forward` and
`javax.servlet.RequestDispatcher.include` methods to create new `INTERNAL` spans around their
invocations.
`HttpServletResponseInstrumentation` instruments `javax.servlet.http.HttpServletResponse.sendError`
`HttpServletResponseInstrumentationModule` instruments `javax.servlet.http.HttpServletResponse.sendError`
and `javax.servlet.http.HttpServletResponse.sendRedirect` methods to create new `INTERNAL` spans
around their invocations.

View File

@ -8,15 +8,12 @@ package io.opentelemetry.javaagent.instrumentation.servlet.v2_2;
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.safeHasSuperType;
import static io.opentelemetry.javaagent.tooling.matcher.NameMatchers.namedOneOf;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import com.google.auto.service.AutoService;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
@ -38,16 +35,10 @@ import net.bytebuddy.matcher.ElementMatcher;
* ServletResponse, Throwable, Span, Scope)} can get it from context and set required span
* attribute.
*/
@AutoService(Instrumenter.class)
public final class Servlet2ResponseStatusInstrumentation extends Instrumenter.Default {
public Servlet2ResponseStatusInstrumentation() {
super("servlet", "servlet-2");
}
// this is required to make sure servlet 2 instrumentation won't apply to servlet 3
final class HttpServletResponseInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
return not(hasClassesNamed("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener"));
return hasClassesNamed("javax.servlet.http.HttpServletResponse");
}
@Override
@ -55,20 +46,15 @@ public final class Servlet2ResponseStatusInstrumentation extends Instrumenter.De
return safeHasSuperType(named("javax.servlet.http.HttpServletResponse"));
}
@Override
public Map<String, String> contextStore() {
return singletonMap("javax.servlet.ServletResponse", Integer.class.getName());
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>();
transformers.put(
namedOneOf("sendError", "setStatus"),
Servlet2ResponseStatusInstrumentation.class.getName() + "$Servlet2ResponseStatusAdvice");
HttpServletResponseInstrumentation.class.getName() + "$Servlet2ResponseStatusAdvice");
transformers.put(
named("sendRedirect"),
Servlet2ResponseStatusInstrumentation.class.getName() + "$Servlet2ResponseRedirectAdvice");
HttpServletResponseInstrumentation.class.getName() + "$Servlet2ResponseRedirectAdvice");
return transformers;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.servlet.v2_2;
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.not;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(InstrumentationModule.class)
public class Servlet2InstrumentationModule extends InstrumentationModule {
public Servlet2InstrumentationModule() {
super("servlet", "servlet-2");
}
// this is required to make sure servlet 2 instrumentation won't apply to servlet 3
@Override
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
return not(hasClassesNamed("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener"));
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.instrumentation.servlet.ServletHttpServerTracer",
"io.opentelemetry.instrumentation.servlet.HttpServletRequestGetter",
packageName + ".ResponseWithStatus",
packageName + ".Servlet2HttpServerTracer"
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return Arrays.asList(
new HttpServletResponseInstrumentation(), new ServletAndFilterChainInstrumentation());
}
@Override
public Map<String, String> contextStore() {
return singletonMap("javax.servlet.ServletResponse", Integer.class.getName());
}
}

View File

@ -11,29 +11,20 @@ import static io.opentelemetry.javaagent.tooling.matcher.NameMatchers.namedOneOf
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class Servlet2Instrumentation extends Instrumenter.Default {
final class ServletAndFilterChainInstrumentation implements TypeInstrumentation {
public Servlet2Instrumentation() {
super("servlet", "servlet-2");
}
// this is required to make sure servlet 2 instrumentation won't apply to servlet 3
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("javax.servlet.http.HttpServlet")
.and(not(hasClassesNamed("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener")));
return hasClassesNamed("javax.servlet.http.HttpServlet");
}
@Override
@ -41,22 +32,6 @@ public final class Servlet2Instrumentation extends Instrumenter.Default {
return safeHasSuperType(
namedOneOf("javax.servlet.FilterChain", "javax.servlet.http.HttpServlet"));
}
@Override
public Map<String, String> contextStore() {
return singletonMap("javax.servlet.ServletResponse", Integer.class.getName());
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.instrumentation.servlet.ServletHttpServerTracer",
"io.opentelemetry.instrumentation.servlet.HttpServletRequestGetter",
packageName + ".ResponseWithStatus",
packageName + ".Servlet2HttpServerTracer"
};
}
/**
* Here we are instrumenting the public method for HttpServlet. This should ensure that this
* advice is always called before HttpServletInstrumentation which is instrumenting the protected
@ -69,6 +44,6 @@ public final class Servlet2Instrumentation extends Instrumenter.Default {
.and(takesArgument(0, named("javax.servlet.ServletRequest")))
.and(takesArgument(1, named("javax.servlet.ServletResponse")))
.and(isPublic()),
packageName + ".Servlet2Advice");
Servlet2Advice.class.getName());
}
}

View File

@ -13,12 +13,11 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import javax.servlet.AsyncContext;
import javax.servlet.ServletRequest;
@ -27,20 +26,7 @@ import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class AsyncContextInstrumentation extends Instrumenter.Default {
public AsyncContextInstrumentation() {
super("servlet", "servlet-3");
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.instrumentation.servlet.HttpServletRequestGetter",
"io.opentelemetry.instrumentation.servlet.ServletHttpServerTracer",
};
}
final class AsyncContextInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {

View File

@ -0,0 +1,36 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.servlet.v3_0;
import static java.util.Arrays.asList;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
@AutoService(InstrumentationModule.class)
public class Servlet3InstrumentationModule extends InstrumentationModule {
public Servlet3InstrumentationModule() {
super("servlet", "servlet-3");
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.instrumentation.servlet.HttpServletRequestGetter",
"io.opentelemetry.instrumentation.servlet.ServletHttpServerTracer",
packageName + ".Servlet3Advice",
packageName + ".Servlet3HttpServerTracer",
packageName + ".TagSettingAsyncListener"
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new AsyncContextInstrumentation(), new ServletAndFilterChainInstrumentation());
}
}

View File

@ -13,19 +13,13 @@ 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 io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class Servlet3Instrumentation extends Instrumenter.Default {
public Servlet3Instrumentation() {
super("servlet", "servlet-3");
}
final class ServletAndFilterChainInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
@ -38,17 +32,6 @@ public final class Servlet3Instrumentation extends Instrumenter.Default {
namedOneOf("javax.servlet.FilterChain", "javax.servlet.http.HttpServlet"));
}
@Override
public String[] helperClassNames() {
return new String[] {
"io.opentelemetry.instrumentation.servlet.HttpServletRequestGetter",
"io.opentelemetry.instrumentation.servlet.ServletHttpServerTracer",
packageName + ".Servlet3Advice",
packageName + ".Servlet3HttpServerTracer",
packageName + ".TagSettingAsyncListener"
};
}
/**
* Here we are instrumenting the public method for HttpServlet. This should ensure that this
* advice is always called before HttpServletInstrumentation which is instrumenting the protected
@ -61,6 +44,6 @@ public final class Servlet3Instrumentation extends Instrumenter.Default {
.and(takesArgument(0, named("javax.servlet.ServletRequest")))
.and(takesArgument(1, named("javax.servlet.ServletResponse")))
.and(isPublic()),
packageName + ".Servlet3Advice");
Servlet3Advice.class.getName());
}
}

View File

@ -4,7 +4,12 @@ muzzle {
pass {
group = "javax.servlet"
module = "servlet-api"
versions = "[2.2,)"
versions = "(0,)"
}
pass {
group = "javax.servlet"
module = 'javax.servlet-api'
versions = "[3.0,)"
assertInverse = true
}
}

View File

@ -10,6 +10,7 @@ import static io.opentelemetry.javaagent.instrumentation.servlet.dispatcher.Requ
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface;
import static io.opentelemetry.javaagent.tooling.matcher.NameMatchers.namedOneOf;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -22,8 +23,10 @@ import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletRequest;
@ -32,23 +35,12 @@ import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class RequestDispatcherInstrumentation extends Instrumenter.Default {
public RequestDispatcherInstrumentation() {
@AutoService(InstrumentationModule.class)
public final class RequestDispatcherInstrumentationModule extends InstrumentationModule {
public RequestDispatcherInstrumentationModule() {
super("servlet", "servlet-dispatcher");
}
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("javax.servlet.RequestDispatcher");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return implementsInterface(named("javax.servlet.RequestDispatcher"));
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -56,20 +48,38 @@ public final class RequestDispatcherInstrumentation extends Instrumenter.Default
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new RequestDispatcherInstrumentation());
}
@Override
public Map<String, String> contextStore() {
return singletonMap("javax.servlet.RequestDispatcher", String.class.getName());
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
namedOneOf("forward", "include")
.and(takesArguments(2))
.and(takesArgument(0, named("javax.servlet.ServletRequest")))
.and(takesArgument(1, named("javax.servlet.ServletResponse")))
.and(isPublic()),
getClass().getName() + "$RequestDispatcherAdvice");
private static final class RequestDispatcherInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("javax.servlet.RequestDispatcher");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return implementsInterface(named("javax.servlet.RequestDispatcher"));
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
namedOneOf("forward", "include")
.and(takesArguments(2))
.and(takesArgument(0, named("javax.servlet.ServletRequest")))
.and(takesArgument(1, named("javax.servlet.ServletResponse")))
.and(isPublic()),
RequestDispatcherInstrumentationModule.class.getName() + "$RequestDispatcherAdvice");
}
}
public static class RequestDispatcherAdvice {

View File

@ -8,6 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.servlet.filter;
import static io.opentelemetry.javaagent.instrumentation.servlet.filter.FilterTracer.tracer;
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -18,7 +19,9 @@ import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Span.Kind;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import net.bytebuddy.asm.Advice;
@ -31,9 +34,9 @@ import net.bytebuddy.matcher.ElementMatcher;
*
* <p>See README.md for more information about different servlet instrumentations.
*/
@AutoService(Instrumenter.class)
public final class FilterInstrumentation extends Instrumenter.Default {
public FilterInstrumentation() {
@AutoService(InstrumentationModule.class)
public final class FilterInstrumentationModule extends InstrumentationModule {
public FilterInstrumentationModule() {
super("servlet-filter");
}
@ -42,18 +45,6 @@ public final class FilterInstrumentation extends Instrumenter.Default {
return false;
}
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
// return hasClassesNamed("javax.servlet.Filter"); // Not available in 2.2
return hasClassesNamed("javax.servlet.http.HttpServlet");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return implementsInterface(named("javax.servlet.Filter"));
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -62,13 +53,31 @@ public final class FilterInstrumentation extends Instrumenter.Default {
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
named("doFilter")
.and(takesArgument(0, named("javax.servlet.ServletRequest")))
.and(takesArgument(1, named("javax.servlet.ServletResponse")))
.and(isPublic()),
getClass().getName() + "$FilterAdvice");
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new FilterInstrumentation());
}
private static final class FilterInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("javax.servlet.Filter");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return implementsInterface(named("javax.servlet.Filter"));
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
named("doFilter")
.and(takesArgument(0, named("javax.servlet.ServletRequest")))
.and(takesArgument(1, named("javax.servlet.ServletResponse")))
.and(isPublic()),
FilterInstrumentationModule.class.getName() + "$FilterAdvice");
}
}
public static class FilterAdvice {

View File

@ -8,6 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.servlet.http;
import static io.opentelemetry.javaagent.instrumentation.servlet.http.HttpServletTracer.tracer;
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
@ -19,18 +20,21 @@ import com.google.auto.service.AutoService;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
// Please read README.md of this subproject to understand what is this instrumentation.
@AutoService(Instrumenter.class)
public final class HttpServletInstrumentation extends Instrumenter.Default {
public HttpServletInstrumentation() {
// Please read README.md of this subproject to understand what this instrumentation is and why it
// requires a separate module.
@AutoService(InstrumentationModule.class)
public final class HttpServletInstrumentationModule extends InstrumentationModule {
public HttpServletInstrumentationModule() {
super("servlet-service");
}
@ -39,17 +43,6 @@ public final class HttpServletInstrumentation extends Instrumenter.Default {
return false;
}
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("javax.servlet.http.HttpServlet");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return extendsClass(named("javax.servlet.http.HttpServlet"));
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -57,19 +50,38 @@ public final class HttpServletInstrumentation extends Instrumenter.Default {
};
}
/**
* Here we are instrumenting the protected method for HttpServlet. This should ensure that this
* advice is always called after Servlet3Instrumentation which is instrumenting the public method.
*/
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
named("service")
.or(nameStartsWith("do")) // doGet, doPost, etc
.and(takesArgument(0, named("javax.servlet.http.HttpServletRequest")))
.and(takesArgument(1, named("javax.servlet.http.HttpServletResponse")))
.and(isProtected().or(isPublic())),
getClass().getName() + "$HttpServletAdvice");
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new HttpServletInstrumentation());
}
private static final class HttpServletInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("javax.servlet.http.HttpServlet");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return extendsClass(named("javax.servlet.http.HttpServlet"));
}
/**
* Here we are instrumenting the protected method for HttpServlet. This should ensure that this
* advice is always called after Servlet3Instrumentation which is instrumenting the public
* method.
*/
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
named("service")
.or(nameStartsWith("do")) // doGet, doPost, etc
.and(takesArgument(0, named("javax.servlet.http.HttpServletRequest")))
.and(takesArgument(1, named("javax.servlet.http.HttpServletResponse")))
.and(isProtected().or(isPublic())),
HttpServletInstrumentationModule.class.getName() + "$HttpServletAdvice");
}
}
public static class HttpServletAdvice {

View File

@ -9,6 +9,7 @@ import static io.opentelemetry.javaagent.instrumentation.servlet.http.HttpServle
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface;
import static io.opentelemetry.javaagent.tooling.matcher.NameMatchers.namedOneOf;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -18,8 +19,10 @@ import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap.Depth;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import net.bytebuddy.asm.Advice;
@ -27,23 +30,12 @@ import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class HttpServletResponseInstrumentation extends Instrumenter.Default {
public HttpServletResponseInstrumentation() {
@AutoService(InstrumentationModule.class)
public final class HttpServletResponseInstrumentationModule extends InstrumentationModule {
public HttpServletResponseInstrumentationModule() {
super("servlet", "servlet-response");
}
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("javax.servlet.http.HttpServletResponse");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return implementsInterface(named("javax.servlet.http.HttpServletResponse"));
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -52,8 +44,26 @@ public final class HttpServletResponseInstrumentation extends Instrumenter.Defau
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(namedOneOf("sendError", "sendRedirect"), SendAdvice.class.getName());
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new HttpServletResponseInstrumentation());
}
private static final class HttpServletResponseInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("javax.servlet.http.HttpServletResponse");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return implementsInterface(named("javax.servlet.http.HttpServletResponse"));
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(namedOneOf("sendError", "sendRedirect"), SendAdvice.class.getName());
}
}
public static class SendAdvice {

View File

@ -5,6 +5,7 @@
package io.opentelemetry.javaagent.instrumentation.sparkjava;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -12,11 +13,11 @@ import static net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
@ -24,41 +25,32 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import spark.routematch.RouteMatch;
@AutoService(Instrumenter.class)
public class RoutesInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public class SparkInstrumentationModule extends InstrumentationModule {
public RoutesInstrumentation() {
public SparkInstrumentationModule() {
super("sparkjava", "sparkjava-2.4");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("spark.route.Routes");
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new RoutesInstrumentation());
}
@Override
public String[] helperClassNames() {
return new String[] {
RoutesInstrumentation.class.getName() + "$TracerHolder",
};
}
private static final class RoutesInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("spark.route.Routes");
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
named("find")
.and(takesArgument(0, named("spark.route.HttpMethod")))
.and(returns(named("spark.routematch.RouteMatch")))
.and(isPublic()),
RoutesInstrumentation.class.getName() + "$RoutesAdvice");
}
public static class TracerHolder {
private static final Tracer TRACER =
OpenTelemetry.getGlobalTracer("io.opentelemetry.auto.sparkjava-2.3");
public static Tracer tracer() {
return TRACER;
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
named("find")
.and(takesArgument(0, named("spark.route.HttpMethod")))
.and(returns(named("spark.routematch.RouteMatch")))
.and(isPublic()),
SparkInstrumentationModule.class.getName() + "$RoutesAdvice");
}
}

View File

@ -6,6 +6,7 @@
package io.opentelemetry.javaagent.instrumentation.spring.data;
import static io.opentelemetry.javaagent.instrumentation.spring.data.SpringDataTracer.tracer;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -13,8 +14,10 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
@ -28,18 +31,13 @@ import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
@AutoService(Instrumenter.class)
public final class SpringRepositoryInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public final class SpringDataInstrumentationModule extends InstrumentationModule {
public SpringRepositoryInstrumentation() {
public SpringDataInstrumentationModule() {
super("spring-data");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.springframework.data.repository.core.support.RepositoryFactorySupport");
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -50,10 +48,23 @@ public final class SpringRepositoryInstrumentation extends Instrumenter.Default
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isConstructor(),
SpringRepositoryInstrumentation.class.getName() + "$RepositoryFactorySupportAdvice");
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new RepositoryFactorySupportInstrumentation());
}
private static final class RepositoryFactorySupportInstrumentation
implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.springframework.data.repository.core.support.RepositoryFactorySupport");
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isConstructor(),
SpringDataInstrumentationModule.class.getName() + "$RepositoryFactorySupportAdvice");
}
}
public static class RepositoryFactorySupportAdvice {

View File

@ -5,31 +5,29 @@
package io.opentelemetry.javaagent.instrumentation.spring.scheduling;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class SpringSchedulingInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public final class SpringSchedulingInstrumentationModule extends InstrumentationModule {
public SpringSchedulingInstrumentation() {
public SpringSchedulingInstrumentationModule() {
super("spring-scheduling");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.springframework.scheduling.config.Task");
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -38,10 +36,22 @@ public final class SpringSchedulingInstrumentation extends Instrumenter.Default
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isConstructor().and(takesArgument(0, Runnable.class)),
SpringSchedulingInstrumentation.class.getName() + "$SpringSchedulingAdvice");
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new TaskInstrumentation());
}
private static final class TaskInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.springframework.scheduling.config.Task");
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isConstructor().and(takesArgument(0, Runnable.class)),
SpringSchedulingInstrumentationModule.class.getName() + "$SpringSchedulingAdvice");
}
}
public static class SpringSchedulingAdvice {

View File

@ -7,31 +7,28 @@ package io.opentelemetry.javaagent.instrumentation.spring.webflux.client;
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public class WebClientFilterInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public class WebfluxClientInstrumentationModule extends InstrumentationModule {
public WebClientFilterInstrumentation() {
public WebfluxClientInstrumentationModule() {
super("spring-webflux", "spring-webflux-client");
}
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("org.springframework.web.reactive.function.client.WebClient");
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -44,14 +41,27 @@ public class WebClientFilterInstrumentation extends Instrumenter.Default {
}
@Override
public ElementMatcher<? super TypeDescription> typeMatcher() {
return implementsInterface(
named("org.springframework.web.reactive.function.client.WebClient$Builder"));
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new WebClientBuilderInstrumentation());
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(isPublic()).and(named("build")), packageName + ".WebClientFilterAdvice");
private static final class WebClientBuilderInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
return hasClassesNamed("org.springframework.web.reactive.function.client.WebClient");
}
@Override
public ElementMatcher<? super TypeDescription> typeMatcher() {
return implementsInterface(
named("org.springframework.web.reactive.function.client.WebClient$Builder"));
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(isPublic()).and(named("build")), WebClientFilterAdvice.class.getName());
}
}
}

View File

@ -1,25 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.spring.webflux.server;
import io.opentelemetry.javaagent.tooling.Instrumenter;
public abstract class AbstractWebfluxInstrumentation extends Instrumenter.Default {
public AbstractWebfluxInstrumentation(String... additionalNames) {
super("spring-webflux", additionalNames);
}
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".SpringWebfluxHttpServerTracer",
packageName + ".AdviceUtils",
packageName + ".AdviceUtils$SpanFinishingSubscriber",
packageName + ".RouteOnSuccessOrError"
};
}
}

View File

@ -12,15 +12,13 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class DispatcherHandlerInstrumentation extends AbstractWebfluxInstrumentation {
final class DispatcherHandlerInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
@ -35,7 +33,6 @@ public final class DispatcherHandlerInstrumentation extends AbstractWebfluxInstr
.and(named("handle"))
.and(takesArgument(0, named("org.springframework.web.server.ServerWebExchange")))
.and(takesArguments(1)),
// Cannot reference class directly here because it would lead to class load failure on Java7
packageName + ".DispatcherHandlerAdvice");
DispatcherHandlerAdvice.class.getName());
}
}

View File

@ -16,15 +16,13 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class HandlerAdapterInstrumentation extends AbstractWebfluxInstrumentation {
final class HandlerAdapterInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
@ -47,7 +45,6 @@ public final class HandlerAdapterInstrumentation extends AbstractWebfluxInstrume
.and(takesArgument(0, named("org.springframework.web.server.ServerWebExchange")))
.and(takesArgument(1, named("java.lang.Object")))
.and(takesArguments(2)),
// Cannot reference class directly here because it would lead to class load failure on Java7
packageName + ".HandlerAdapterAdvice");
HandlerAdapterAdvice.class.getName());
}
}

View File

@ -16,19 +16,13 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class RouterFunctionInstrumentation extends AbstractWebfluxInstrumentation {
public RouterFunctionInstrumentation() {
super("spring-webflux-functional");
}
final class RouterFunctionInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
@ -56,7 +50,6 @@ public final class RouterFunctionInstrumentation extends AbstractWebfluxInstrume
takesArgument(
0, named("org.springframework.web.reactive.function.server.ServerRequest")))
.and(takesArguments(1)),
// Cannot reference class directly here because it would lead to class load failure on Java7
packageName + ".RouterFunctionAdvice");
RouterFunctionAdvice.class.getName());
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.spring.webflux.server;
import static java.util.Arrays.asList;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
@AutoService(InstrumentationModule.class)
public class WebfluxServerInstrumentationModule extends InstrumentationModule {
public WebfluxServerInstrumentationModule() {
super("spring-webflux", "spring-webflux-server");
}
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".SpringWebfluxHttpServerTracer",
packageName + ".AdviceUtils",
packageName + ".AdviceUtils$SpanFinishingSubscriber",
packageName + ".RouteOnSuccessOrError"
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(
new DispatcherHandlerInstrumentation(),
new HandlerAdapterInstrumentation(),
new RouterFunctionInstrumentation());
}
}

View File

@ -6,6 +6,7 @@
package io.opentelemetry.javaagent.instrumentation.spymemcached;
import static io.opentelemetry.javaagent.tooling.matcher.NameMatchers.namedOneOf;
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;
@ -14,8 +15,10 @@ import static net.bytebuddy.matcher.ElementMatchers.returns;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
@ -26,20 +29,13 @@ import net.spy.memcached.internal.BulkFuture;
import net.spy.memcached.internal.GetFuture;
import net.spy.memcached.internal.OperationFuture;
@AutoService(Instrumenter.class)
public final class MemcachedClientInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public final class SpymemcachedInstrumentationModule extends InstrumentationModule {
private static final String MEMCACHED_PACKAGE = "net.spy.memcached";
public MemcachedClientInstrumentation() {
public SpymemcachedInstrumentationModule() {
super("spymemcached");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named(MEMCACHED_PACKAGE + ".MemcachedClient");
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -53,28 +49,40 @@ public final class MemcachedClientInstrumentation extends Instrumenter.Default {
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>();
transformers.put(
isMethod()
.and(isPublic())
.and(returns(named(MEMCACHED_PACKAGE + ".internal.OperationFuture")))
/*
Flush seems to have a bug when listeners may not be always called.
Also tracing flush is probably of a very limited value.
*/
.and(not(named("flush"))),
MemcachedClientInstrumentation.class.getName() + "$AsyncOperationAdvice");
transformers.put(
isMethod().and(isPublic()).and(returns(named(MEMCACHED_PACKAGE + ".internal.GetFuture"))),
MemcachedClientInstrumentation.class.getName() + "$AsyncGetAdvice");
transformers.put(
isMethod().and(isPublic()).and(returns(named(MEMCACHED_PACKAGE + ".internal.BulkFuture"))),
MemcachedClientInstrumentation.class.getName() + "$AsyncBulkAdvice");
transformers.put(
isMethod().and(isPublic()).and(namedOneOf("incr", "decr")),
MemcachedClientInstrumentation.class.getName() + "$SyncOperationAdvice");
return transformers;
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new MemcachedClientInstrumentation());
}
private static final class MemcachedClientInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("net.spy.memcached.MemcachedClient");
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>();
transformers.put(
isMethod()
.and(isPublic())
.and(returns(named("net.spy.memcached.internal.OperationFuture")))
/*
Flush seems to have a bug when listeners may not be always called.
Also tracing flush is probably of a very limited value.
*/
.and(not(named("flush"))),
SpymemcachedInstrumentationModule.class.getName() + "$AsyncOperationAdvice");
transformers.put(
isMethod().and(isPublic()).and(returns(named("net.spy.memcached.internal.GetFuture"))),
SpymemcachedInstrumentationModule.class.getName() + "$AsyncGetAdvice");
transformers.put(
isMethod().and(isPublic()).and(returns(named("net.spy.memcached.internal.BulkFuture"))),
SpymemcachedInstrumentationModule.class.getName() + "$AsyncBulkAdvice");
transformers.put(
isMethod().and(isPublic()).and(namedOneOf("incr", "decr")),
SpymemcachedInstrumentationModule.class.getName() + "$SyncOperationAdvice");
return transformers;
}
}
public static class AsyncOperationAdvice {
@ -89,7 +97,7 @@ public final class MemcachedClientInstrumentation extends Instrumenter.Default {
@Advice.Enter int callDepth,
@Advice.This MemcachedClient client,
@Advice.Origin("#m") String methodName,
@Advice.Return OperationFuture future) {
@Advice.Return OperationFuture<?> future) {
if (callDepth > 0) {
return;
}
@ -115,7 +123,7 @@ public final class MemcachedClientInstrumentation extends Instrumenter.Default {
@Advice.Enter int callDepth,
@Advice.This MemcachedClient client,
@Advice.Origin("#m") String methodName,
@Advice.Return GetFuture future) {
@Advice.Return GetFuture<?> future) {
if (callDepth > 0) {
return;
}
@ -141,7 +149,7 @@ public final class MemcachedClientInstrumentation extends Instrumenter.Default {
@Advice.Enter int callDepth,
@Advice.This MemcachedClient client,
@Advice.Origin("#m") String methodName,
@Advice.Return BulkFuture future) {
@Advice.Return BulkFuture<?> future) {
if (callDepth > 0) {
return;
}

View File

@ -19,7 +19,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import com.google.auto.service.AutoService;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@ -27,19 +26,14 @@ import com.twilio.Twilio;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
/** Instrument the Twilio SDK to identify calls as a seperate service. */
@AutoService(Instrumenter.class)
public class TwilioAsyncInstrumentation extends Instrumenter.Default {
public TwilioAsyncInstrumentation() {
super("twilio-sdk");
}
/** Instrument the Twilio SDK to identify calls as a separate service. */
final class TwilioAsyncInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
@ -59,15 +53,6 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default {
"com.twilio.base.Updater"));
}
/** Return the helper classes which will be available for use in instrumentation. */
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".TwilioClientDecorator",
packageName + ".TwilioAsyncInstrumentation$SpanFinishingCallback",
};
}
/** Return bytebuddy transformers for instrumenting the Twilio SDK. */
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
@ -122,7 +107,7 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default {
public static void methodExit(
@Advice.Enter SpanWithScope spanWithScope,
@Advice.Thrown Throwable throwable,
@Advice.Return ListenableFuture response) {
@Advice.Return ListenableFuture<?> response) {
if (spanWithScope == null) {
return;
}
@ -142,7 +127,7 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default {
// We're calling an async operation, we still need to finish the span when it's
// complete and report the results; set an appropriate callback
Futures.addCallback(
response, new SpanFinishingCallback(span), Twilio.getExecutorService());
response, new SpanFinishingCallback<>(span), Twilio.getExecutorService());
}
} finally {
spanWithScope.closeScope();
@ -155,7 +140,7 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default {
* FutureCallback, which automatically finishes the span and annotates with any appropriate
* metadata on a potential failure.
*/
public static class SpanFinishingCallback implements FutureCallback {
public static class SpanFinishingCallback<T> implements FutureCallback<T> {
/** Span that we should finish and annotate when the future is complete. */
private final Span span;

View File

@ -0,0 +1,33 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.twilio;
import static java.util.Arrays.asList;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.List;
@AutoService(InstrumentationModule.class)
public class TwilioInstrumentationModule extends InstrumentationModule {
public TwilioInstrumentationModule() {
super("twilio-sdk");
}
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".TwilioClientDecorator",
packageName + ".TwilioAsyncInstrumentation$SpanFinishingCallback",
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new TwilioAsyncInstrumentation(), new TwilioSyncInstrumentation());
}
}

View File

@ -17,24 +17,18 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.not;
import com.google.auto.service.AutoService;
import com.twilio.Twilio;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.javaagent.instrumentation.api.CallDepthThreadLocalMap;
import io.opentelemetry.javaagent.instrumentation.api.SpanWithScope;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
/** Instrument the Twilio SDK to identify calls as a seperate service. */
@AutoService(Instrumenter.class)
public class TwilioSyncInstrumentation extends Instrumenter.Default {
public TwilioSyncInstrumentation() {
super("twilio-sdk");
}
/** Instrument the Twilio SDK to identify calls as a separate service. */
final class TwilioSyncInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
@ -56,14 +50,6 @@ public class TwilioSyncInstrumentation extends Instrumenter.Default {
"com.twilio.base.Updater"));
}
/** Return the helper classes which will be available for use in instrumentation. */
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".TwilioClientDecorator",
};
}
/** Return bytebuddy transformers for instrumenting the Twilio SDK. */
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {

View File

@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.vertx;
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.safeHasSuperType;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
@ -15,32 +16,24 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class RouteInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public final class VertxInstrumentationModule extends InstrumentationModule {
public RouteInstrumentation() {
public VertxInstrumentationModule() {
super("vertx");
}
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
return hasClassesNamed("io.vertx.ext.web.Route");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return not(isInterface()).and(safeHasSuperType(named("io.vertx.ext.web.Route")));
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -49,10 +42,27 @@ public final class RouteInstrumentation extends Instrumenter.Default {
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(named("handler")).and(takesArgument(0, named("io.vertx.core.Handler"))),
RouteInstrumentation.class.getName() + "$RouteAdvice");
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new RouteInstrumentation());
}
private static final class RouteInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
return hasClassesNamed("io.vertx.ext.web.Route");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return not(isInterface()).and(safeHasSuperType(named("io.vertx.ext.web.Route")));
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(named("handler")).and(takesArgument(0, named("io.vertx.core.Handler"))),
VertxInstrumentationModule.class.getName() + "$RouteAdvice");
}
}
public static class RouteAdvice {

View File

@ -2,9 +2,9 @@
* The majority of monitoring needs of Vert.x application is covered by generic instrumentations.
* Such as those of netty or JDBC.
*
* <p>{@link io.opentelemetry.javaagent.instrumentation.vertx.RouteInstrumentation} wraps all Vert.x
* route handlers in order to update the name of the currently active SERVER span with the name of
* route. This is, arguably, a much more user-friendly name that defaults provided by HTTP server
* instrumentations.
* <p>{@link io.opentelemetry.javaagent.instrumentation.vertx.VertxInstrumentationModule} wraps all
* Vert.x route handlers in order to update the name of the currently active SERVER span with the
* name of route. This is, arguably, a much more user-friendly name that defaults provided by HTTP
* server instrumentations.
*/
package io.opentelemetry.javaagent.instrumentation.vertx;

View File

@ -6,16 +6,19 @@
package io.opentelemetry.javaagent.instrumentation.vertx.reactive;
import static io.opentelemetry.javaagent.tooling.ClassLoaderMatcher.hasClassesNamed;
import static java.util.Collections.singletonList;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.Instrumenter;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import net.bytebuddy.asm.Advice;
@ -24,26 +27,13 @@ import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
/** This instrumentation allows span context propagation across Vert.x reactive executions. */
@AutoService(Instrumenter.class)
public class VertxRxInstrumentation extends Instrumenter.Default {
@AutoService(InstrumentationModule.class)
public class VertxRxInstrumentationModule extends InstrumentationModule {
public VertxRxInstrumentation() {
public VertxRxInstrumentationModule() {
super("vertx");
}
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Different versions of Vert.x has this class in different packages
return hasClassesNamed("io.vertx.reactivex.core.impl.AsyncResultSingle")
.or(hasClassesNamed("io.vertx.reactivex.impl.AsyncResultSingle"));
}
@Override
public ElementMatcher<? super TypeDescription> typeMatcher() {
return named("io.vertx.reactivex.core.impl.AsyncResultSingle")
.or(named("io.vertx.reactivex.impl.AsyncResultSingle"));
}
@Override
public String[] helperClassNames() {
return new String[] {
@ -52,15 +42,35 @@ public class VertxRxInstrumentation extends Instrumenter.Default {
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
Map<ElementMatcher<? super MethodDescription>, String> result = new HashMap<>();
result.put(
isConstructor().and(takesArgument(0, named("io.vertx.core.Handler"))),
this.getClass().getName() + "$AsyncResultSingleHandlerAdvice");
result.put(
isConstructor().and(takesArgument(0, named("java.util.function.Consumer"))),
this.getClass().getName() + "$AsyncResultSingleConsumerAdvice");
return result;
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new AsyncResultSingleInstrumentation());
}
private static final class AsyncResultSingleInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Different versions of Vert.x has this class in different packages
return hasClassesNamed("io.vertx.reactivex.core.impl.AsyncResultSingle")
.or(hasClassesNamed("io.vertx.reactivex.impl.AsyncResultSingle"));
}
@Override
public ElementMatcher<? super TypeDescription> typeMatcher() {
return named("io.vertx.reactivex.core.impl.AsyncResultSingle")
.or(named("io.vertx.reactivex.impl.AsyncResultSingle"));
}
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
Map<ElementMatcher<? super MethodDescription>, String> result = new HashMap<>();
result.put(
isConstructor().and(takesArgument(0, named("io.vertx.core.Handler"))),
VertxRxInstrumentationModule.class.getName() + "$AsyncResultSingleHandlerAdvice");
result.put(
isConstructor().and(takesArgument(0, named("java.util.function.Consumer"))),
VertxRxInstrumentationModule.class.getName() + "$AsyncResultSingleConsumerAdvice");
return result;
}
}
public static class AsyncResultSingleHandlerAdvice {

View File

@ -2,8 +2,8 @@
* The majority of monitoring needs of Vert.x application is covered by generic instrumentations.
* Such as those of netty or JDBC.
*
* <p>{@link io.opentelemetry.javaagent.instrumentation.vertx.reactive.VertxRxInstrumentation} wraps
* {code AsyncResultSingle} classes from Vert.x RxJava library to ensure proper span context
* <p>{@link io.opentelemetry.javaagent.instrumentation.vertx.reactive.VertxRxInstrumentationModule}
* wraps {code AsyncResultSingle} classes from Vert.x RxJava library to ensure proper span context
* propagation in reactive Vert.x applications.
*/
package io.opentelemetry.javaagent.instrumentation.vertx.reactive;