Prevent duplicate telemetry when using both library and auto instrumentation (#2661)
* Prevent duplicate telemetry when using both library and auto instrumentation * Add unit test * Fix Oshi tests * Fix couchbase 3.1 tests
This commit is contained in:
parent
55ccf98b4f
commit
30434696ae
|
@ -21,13 +21,15 @@ The compile-time reference collection and code generation process is implemented
|
||||||
plugin (called `MuzzleCodeGenerationPlugin`).
|
plugin (called `MuzzleCodeGenerationPlugin`).
|
||||||
|
|
||||||
For each instrumentation module the ByteBuddy plugin collects symbols referring to both internal and
|
For each instrumentation module the ByteBuddy plugin collects symbols referring to both internal and
|
||||||
third party APIs used by the currently processed module's type instrumentations (`InstrumentationModule#typeInstrumentations()`).
|
third party APIs used by the currently processed module's type
|
||||||
The reference collection process starts from advice classes (values of the map returned by the
|
instrumentations (`InstrumentationModule#typeInstrumentations()`). The reference collection process
|
||||||
`TypeInstrumentation#transformers()`method) and traverses the class graph until it encounters
|
starts from advice classes (values of the map returned by the
|
||||||
a reference to a non-instrumentation class (determined by `InstrumentationClassPredicate`).
|
`TypeInstrumentation#transformers()` method) and traverses the class graph until it encounters a
|
||||||
Aside from references, the collection process also builds a graph of dependencies between internal
|
reference to a non-instrumentation class (determined by `InstrumentationClassPredicate` and
|
||||||
instrumentation helper classes - this dependency graph is later used to construct a list of helper
|
the `InstrumentationModule#isLibraryInstrumentationClass(String)` predicate). Aside from references,
|
||||||
classes that will be injected to the application classloader (`InstrumentationModule#getMuzzleHelperClassNames()`).
|
the collection process also builds a graph of dependencies between internal instrumentation helper
|
||||||
|
classes - this dependency graph is later used to construct a list of helper classes that will be
|
||||||
|
injected to the application classloader (`InstrumentationModule#getMuzzleHelperClassNames()`).
|
||||||
|
|
||||||
All collected references are then used to create a `ReferenceMatcher` instance. This matcher
|
All collected references are then used to create a `ReferenceMatcher` instance. This matcher
|
||||||
is stored in the instrumentation module class in the method `InstrumentationModule#getMuzzleReferenceMatcher()`
|
is stored in the instrumentation module class in the method `InstrumentationModule#getMuzzleReferenceMatcher()`
|
||||||
|
|
|
@ -4,8 +4,8 @@ ext.relocatePackages = { shadowJar ->
|
||||||
// rewrite dependencies calling Logger.getLogger
|
// rewrite dependencies calling Logger.getLogger
|
||||||
shadowJar.relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
shadowJar.relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
||||||
|
|
||||||
// rewrite library instrumentation dependencies
|
// prevents conflict with library instrumentation, which uses its own instrumentation-api
|
||||||
shadowJar.relocate "io.opentelemetry.instrumentation", "io.opentelemetry.javaagent.shaded.instrumentation"
|
shadowJar.relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
|
||||||
|
|
||||||
// relocate OpenTelemetry API usage
|
// relocate OpenTelemetry API usage
|
||||||
shadowJar.relocate "io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api"
|
shadowJar.relocate "io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api"
|
||||||
|
|
|
@ -79,15 +79,12 @@ shadowJar {
|
||||||
|
|
||||||
archiveFileName = 'agent-testing.jar'
|
archiveFileName = 'agent-testing.jar'
|
||||||
|
|
||||||
// rewrite library instrumentation dependencies
|
|
||||||
relocate "io.opentelemetry.instrumentation", "io.opentelemetry.javaagent.shaded.instrumentation"
|
|
||||||
|
|
||||||
// Prevents conflict with other SLF4J instances. Important for premain.
|
// Prevents conflict with other SLF4J instances. Important for premain.
|
||||||
relocate 'org.slf4j', 'io.opentelemetry.javaagent.slf4j'
|
relocate 'org.slf4j', 'io.opentelemetry.javaagent.slf4j'
|
||||||
// rewrite dependencies calling Logger.getLogger
|
// rewrite dependencies calling Logger.getLogger
|
||||||
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
||||||
|
|
||||||
// prevents conflict with library instrumentation
|
// prevents conflict with library instrumentation, which uses its own instrumentation-api
|
||||||
relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
|
relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
|
||||||
|
|
||||||
// relocate OpenTelemetry API usage
|
// relocate OpenTelemetry API usage
|
||||||
|
|
|
@ -32,6 +32,11 @@ public class DubboInstrumentationModule extends InstrumentationModule {
|
||||||
return hasClassesNamed("org.apache.dubbo.rpc.Filter");
|
return hasClassesNamed("org.apache.dubbo.rpc.Filter");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.apachedubbo.v2_7");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return Collections.singletonList(new DubboInstrumentation());
|
return Collections.singletonList(new DubboInstrumentation());
|
||||||
|
|
|
@ -26,6 +26,11 @@ public class ArmeriaInstrumentationModule extends InstrumentationModule {
|
||||||
return hasClassesNamed("com.linecorp.armeria.server.metric.PrometheusExpositionServiceBuilder");
|
return hasClassesNamed("com.linecorp.armeria.server.metric.PrometheusExpositionServiceBuilder");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.armeria.v1_3");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return asList(
|
return asList(
|
||||||
|
|
|
@ -23,6 +23,11 @@ public class AwsLambdaInstrumentationModule extends InstrumentationModule {
|
||||||
return new String[] {"io.opentelemetry.extension.aws.AwsXrayPropagator"};
|
return new String[] {"io.opentelemetry.extension.aws.AwsXrayPropagator"};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.awslambda.v1_0");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new AwsLambdaRequestHandlerInstrumentation());
|
return singletonList(new AwsLambdaRequestHandlerInstrumentation());
|
||||||
|
|
|
@ -23,6 +23,11 @@ public class AwsSdkInstrumentationModule extends InstrumentationModule {
|
||||||
return new String[] {"io.opentelemetry.extension.aws.AwsXrayPropagator"};
|
return new String[] {"io.opentelemetry.extension.aws.AwsXrayPropagator"};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.awssdk.v1_11");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return asList(
|
return asList(
|
||||||
|
|
|
@ -43,6 +43,11 @@ public class AwsSdkInstrumentationModule extends InstrumentationModule {
|
||||||
return hasClassesNamed("software.amazon.awssdk.core.interceptor.ExecutionInterceptor");
|
return hasClassesNamed("software.amazon.awssdk.core.interceptor.ExecutionInterceptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.awssdk.v2_2");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return Collections.singletonList(new AwsSdkInitializationInstrumentation());
|
return Collections.singletonList(new AwsSdkInitializationInstrumentation());
|
||||||
|
|
|
@ -21,4 +21,9 @@ dependencies {
|
||||||
testLibrary group: "com.couchbase.client", name: "java-client", version: "3.1.0"
|
testLibrary group: "com.couchbase.client", name: "java-client", version: "3.1.0"
|
||||||
|
|
||||||
testImplementation group: "org.testcontainers", name: "couchbase", version: versions.testcontainers
|
testImplementation group: "org.testcontainers", name: "couchbase", version: versions.testcontainers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
// exclude lib from test classpath, otherwise the javaagent would be skipped
|
||||||
|
testImplementation.exclude group: 'com.couchbase.client', module: 'tracing-opentelemetry'
|
||||||
|
}
|
||||||
|
|
|
@ -20,11 +20,6 @@ public class CouchbaseInstrumentationModule extends InstrumentationModule {
|
||||||
super("couchbase", "couchbase-3.1");
|
super("couchbase", "couchbase-3.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isHelperClass(String className) {
|
|
||||||
return className.startsWith("com.couchbase.client.tracing.opentelemetry");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
|
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
|
||||||
// New class introduced in 3.1, the minimum version we support.
|
// New class introduced in 3.1, the minimum version we support.
|
||||||
|
@ -33,6 +28,11 @@ public class CouchbaseInstrumentationModule extends InstrumentationModule {
|
||||||
return hasClassesNamed("com.couchbase.client.core.cnc.TracingIdentifiers");
|
return hasClassesNamed("com.couchbase.client.core.cnc.TracingIdentifiers");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("com.couchbase.client.tracing.opentelemetry");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return Collections.singletonList(new CouchbaseEnvironmentInstrumentation());
|
return Collections.singletonList(new CouchbaseEnvironmentInstrumentation());
|
||||||
|
|
|
@ -18,6 +18,11 @@ public class GrpcInstrumentationModule extends InstrumentationModule {
|
||||||
super("grpc", "grpc-1.5");
|
super("grpc", "grpc-1.5");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.grpc.v1_5");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return asList(
|
return asList(
|
||||||
|
|
|
@ -61,12 +61,12 @@ shadowJar {
|
||||||
exclude(project(':javaagent-api'))
|
exclude(project(':javaagent-api'))
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewrite library instrumentation dependencies
|
|
||||||
relocate "io.opentelemetry.instrumentation", "io.opentelemetry.javaagent.shaded.instrumentation"
|
|
||||||
|
|
||||||
// rewrite dependencies calling Logger.getLogger
|
// rewrite dependencies calling Logger.getLogger
|
||||||
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
||||||
|
|
||||||
|
// prevents conflict with library instrumentation, which uses its own instrumentation-api
|
||||||
|
relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
|
||||||
|
|
||||||
// relocate OpenTelemetry API usage
|
// relocate OpenTelemetry API usage
|
||||||
relocate "io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api"
|
relocate "io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api"
|
||||||
relocate "io.opentelemetry.semconv", "io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv"
|
relocate "io.opentelemetry.semconv", "io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv"
|
||||||
|
|
|
@ -26,6 +26,11 @@ public class Axis2InstrumentationModule extends InstrumentationModule {
|
||||||
return hasClassesNamed("org.apache.axis2.jaxws.api.MessageAccessor");
|
return hasClassesNamed("org.apache.axis2.jaxws.api.MessageAccessor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.axis2");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return Collections.singletonList(new InvocationListenerRegistryTypeInstrumentation());
|
return Collections.singletonList(new InvocationListenerRegistryTypeInstrumentation());
|
||||||
|
|
|
@ -17,6 +17,11 @@ public class CxfInstrumentationModule extends InstrumentationModule {
|
||||||
super("cxf", "cxf-3.0");
|
super("cxf", "cxf-3.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.cxf");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return Collections.singletonList(new EndpointImplTypeInstrumentation());
|
return Collections.singletonList(new EndpointImplTypeInstrumentation());
|
||||||
|
|
|
@ -36,6 +36,11 @@ public class LettuceInstrumentationModule extends InstrumentationModule {
|
||||||
return hasClassesNamed("io.lettuce.core.tracing.Tracing");
|
return hasClassesNamed("io.lettuce.core.tracing.Tracing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.lettuce.v5_1");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new DefaultClientResourcesInstrumentation());
|
return singletonList(new DefaultClientResourcesInstrumentation());
|
||||||
|
|
|
@ -37,6 +37,11 @@ public class Log4j2InstrumentationModule extends InstrumentationModule {
|
||||||
return hasClassesNamed("org.apache.logging.log4j.core.util.ContextDataProvider");
|
return hasClassesNamed("org.apache.logging.log4j.core.util.ContextDataProvider");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.log4j.v2_13_2");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return Arrays.asList(new BugFixingInstrumentation(), new EmptyTypeInstrumentation());
|
return Arrays.asList(new BugFixingInstrumentation(), new EmptyTypeInstrumentation());
|
||||||
|
|
|
@ -26,6 +26,11 @@ public class LogbackInstrumentationModule extends InstrumentationModule {
|
||||||
return asList(new LoggerInstrumentation(), new LoggingEventInstrumentation());
|
return asList(new LoggerInstrumentation(), new LoggingEventInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.logback.v1_0");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> contextStore() {
|
public Map<String, String> contextStore() {
|
||||||
return singletonMap("ch.qos.logback.classic.spi.ILoggingEvent", Span.class.getName());
|
return singletonMap("ch.qos.logback.classic.spi.ILoggingEvent", Span.class.getName());
|
||||||
|
|
|
@ -29,6 +29,11 @@ public class OkHttp3InstrumentationModule extends InstrumentationModule {
|
||||||
super("okhttp", "okhttp-3.0");
|
super("okhttp", "okhttp-3.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.okhttp.v3_0");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new OkHttpClientInstrumentation());
|
return singletonList(new OkHttpClientInstrumentation());
|
||||||
|
|
|
@ -31,6 +31,11 @@ public class OshiInstrumentationModule extends InstrumentationModule {
|
||||||
super("oshi");
|
super("oshi");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.oshi");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new SystemInfoInstrumentation());
|
return singletonList(new SystemInfoInstrumentation());
|
||||||
|
|
|
@ -21,13 +21,13 @@ class OshiTest extends AgentInstrumentationSpecification {
|
||||||
expect:
|
expect:
|
||||||
platform != null
|
platform != null
|
||||||
// TODO (trask) is this the instrumentation library name we want?
|
// TODO (trask) is this the instrumentation library name we want?
|
||||||
findMetric("io.opentelemetry.javaagent.shaded.instrumentation.oshi", "system.disk.io") != null
|
findMetric("io.opentelemetry.instrumentation.oshi", "system.disk.io") != null
|
||||||
findMetric("io.opentelemetry.javaagent.shaded.instrumentation.oshi", "system.disk.operations") != null
|
findMetric("io.opentelemetry.instrumentation.oshi", "system.disk.operations") != null
|
||||||
findMetric("io.opentelemetry.javaagent.shaded.instrumentation.oshi", "system.memory.usage") != null
|
findMetric("io.opentelemetry.instrumentation.oshi", "system.memory.usage") != null
|
||||||
findMetric("io.opentelemetry.javaagent.shaded.instrumentation.oshi", "system.memory.utilization") != null
|
findMetric("io.opentelemetry.instrumentation.oshi", "system.memory.utilization") != null
|
||||||
findMetric("io.opentelemetry.javaagent.shaded.instrumentation.oshi", "system.network.errors") != null
|
findMetric("io.opentelemetry.instrumentation.oshi", "system.network.errors") != null
|
||||||
findMetric("io.opentelemetry.javaagent.shaded.instrumentation.oshi", "system.network.io") != null
|
findMetric("io.opentelemetry.instrumentation.oshi", "system.network.io") != null
|
||||||
findMetric("io.opentelemetry.javaagent.shaded.instrumentation.oshi", "system.network.packets") != null
|
findMetric("io.opentelemetry.instrumentation.oshi", "system.network.packets") != null
|
||||||
}
|
}
|
||||||
|
|
||||||
def findMetric(instrumentationName, metricName) {
|
def findMetric(instrumentationName, metricName) {
|
||||||
|
|
|
@ -26,6 +26,11 @@ public class ReactorInstrumentationModule extends InstrumentationModule {
|
||||||
super("reactor", "reactor-3.1");
|
super("reactor", "reactor-3.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.reactor");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new HooksInstrumentation());
|
return singletonList(new HooksInstrumentation());
|
||||||
|
|
|
@ -18,6 +18,11 @@ public class RocketMqInstrumentationModule extends InstrumentationModule {
|
||||||
super("rocketmq-client", "rocketmq-client-4.8");
|
super("rocketmq-client", "rocketmq-client-4.8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.rocketmq");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return asList(new RocketMqProducerInstrumentation(), new RocketMqConsumerInstrumentation());
|
return asList(new RocketMqProducerInstrumentation(), new RocketMqConsumerInstrumentation());
|
||||||
|
|
|
@ -26,6 +26,11 @@ public class RxJava2InstrumentationModule extends InstrumentationModule {
|
||||||
super("rxjava2");
|
super("rxjava2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.rxjava2");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return Collections.singletonList(new PluginInstrumentation());
|
return Collections.singletonList(new PluginInstrumentation());
|
||||||
|
|
|
@ -29,6 +29,11 @@ public class WebfluxClientInstrumentationModule extends InstrumentationModule {
|
||||||
super("spring-webflux", "spring-webflux-5.0", "spring-webflux-client");
|
super("spring-webflux", "spring-webflux-5.0", "spring-webflux-client");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.spring.webflux.client");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new WebClientBuilderInstrumentation());
|
return singletonList(new WebClientBuilderInstrumentation());
|
||||||
|
|
|
@ -18,6 +18,11 @@ public class SpringWebMvcInstrumentationModule extends InstrumentationModule {
|
||||||
super("spring-webmvc", "spring-webmvc-3.1");
|
super("spring-webmvc", "spring-webmvc-3.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return className.startsWith("io.opentelemetry.instrumentation.spring.webmvc");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return asList(
|
return asList(
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.tooling;
|
package io.opentelemetry.javaagent.tooling;
|
||||||
|
|
||||||
|
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.callWhenTrue;
|
||||||
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.failSafe;
|
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.failSafe;
|
||||||
|
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.ClassLoaderMatcher.hasAnyClassesNamed;
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.any;
|
import static net.bytebuddy.matcher.ElementMatchers.any;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
|
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
|
||||||
|
@ -29,6 +31,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||||
import net.bytebuddy.description.annotation.AnnotationSource;
|
import net.bytebuddy.description.annotation.AnnotationSource;
|
||||||
import net.bytebuddy.description.method.MethodDescription;
|
import net.bytebuddy.description.method.MethodDescription;
|
||||||
|
@ -130,7 +133,8 @@ public abstract class InstrumentationModule {
|
||||||
return parentAgentBuilder;
|
return parentAgentBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementMatcher.Junction<ClassLoader> moduleClassLoaderMatcher = classLoaderMatcher();
|
ElementMatcher.Junction<ClassLoader> moduleClassLoaderMatcher =
|
||||||
|
createModuleClassLoaderMatcher(helperClassNames);
|
||||||
MuzzleMatcher muzzleMatcher = new MuzzleMatcher();
|
MuzzleMatcher muzzleMatcher = new MuzzleMatcher();
|
||||||
HelperInjector helperInjector =
|
HelperInjector helperInjector =
|
||||||
new HelperInjector(mainInstrumentationName(), helperClassNames, helperResourceNames);
|
new HelperInjector(mainInstrumentationName(), helperClassNames, helperResourceNames);
|
||||||
|
@ -175,6 +179,40 @@ public abstract class InstrumentationModule {
|
||||||
return helperClassNames;
|
return helperClassNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the matcher produced by {@link #classLoaderMatcher()} with an additional condition
|
||||||
|
* added: no library instrumentation classes defined by this module can be present in the
|
||||||
|
* application classloader. This disables the javaagent instrumentation if the library
|
||||||
|
* instrumentation is already used by the application.
|
||||||
|
*/
|
||||||
|
private ElementMatcher.Junction<ClassLoader> createModuleClassLoaderMatcher(
|
||||||
|
List<String> helperClassNames) {
|
||||||
|
// TODO: optimization: refactor matcher caching, only the matcher returned by this method should
|
||||||
|
// cache results, the intermediary ones don't need to cache anything
|
||||||
|
// right now every matcher returned from ClassLoaderMatcher caches separately
|
||||||
|
// this will also make those "Skipping ..." logs appear less
|
||||||
|
|
||||||
|
List<String> libraryHelperClasses =
|
||||||
|
helperClassNames.stream()
|
||||||
|
.filter(this::isLibraryInstrumentationClass)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (libraryHelperClasses.isEmpty()) {
|
||||||
|
return classLoaderMatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementMatcher.Junction<ClassLoader> libraryMatcher =
|
||||||
|
callWhenTrue(
|
||||||
|
hasAnyClassesNamed(libraryHelperClasses), this::logLibraryInstrumentationDetected);
|
||||||
|
return classLoaderMatcher().and(not(libraryMatcher));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logLibraryInstrumentationDetected() {
|
||||||
|
log.debug(
|
||||||
|
"Skipping instrumentation {} because library instrumentation was detected on classpath",
|
||||||
|
mainInstrumentationName());
|
||||||
|
}
|
||||||
|
|
||||||
private AgentBuilder.Identified.Extendable applyInstrumentationTransformers(
|
private AgentBuilder.Identified.Extendable applyInstrumentationTransformers(
|
||||||
Map<? extends ElementMatcher<? super MethodDescription>, String> transformers,
|
Map<? extends ElementMatcher<? super MethodDescription>, String> transformers,
|
||||||
AgentBuilder.Identified.Extendable agentBuilder) {
|
AgentBuilder.Identified.Extendable agentBuilder) {
|
||||||
|
@ -258,23 +296,8 @@ public abstract class InstrumentationModule {
|
||||||
* Java helper function here.
|
* Java helper function here.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected final Predicate<String> additionalLibraryInstrumentationPackage() {
|
protected final Predicate<String> isLibraryInstrumentationClassPredicate() {
|
||||||
return this::isHelperClass;
|
return this::isLibraryInstrumentationClass;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instrumentation modules can override this method to specify additional packages (or classes)
|
|
||||||
* that should be treated as "library instrumentation" packages. Classes from those packages will
|
|
||||||
* be treated by muzzle as instrumentation helper classes: they will be scanned for references and
|
|
||||||
* automatically injected into the application classloader if they're used in any type
|
|
||||||
* instrumentation. The classes for which this predicate returns {@code true} will be treated as
|
|
||||||
* helper classes, in addition to the default ones defined in {@link
|
|
||||||
* InstrumentationClassPredicate}.
|
|
||||||
*
|
|
||||||
* @param className The name of the class that may or may not be a helper class.
|
|
||||||
*/
|
|
||||||
public boolean isHelperClass(String className) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -304,9 +327,9 @@ public abstract class InstrumentationModule {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instrumentation modules can override this method to provide additional helper classes that are
|
* Instrumentation modules can override this method to provide additional helper classes that are
|
||||||
* not located in instrumentation packages described in {@link InstrumentationClassPredicate} (and
|
* not located in instrumentation packages described in {@link InstrumentationClassPredicate} and
|
||||||
* not automatically detected by muzzle). These additional classes will be injected into the
|
* {@link #isLibraryInstrumentationClass(String)} (and not automatically detected by muzzle).
|
||||||
* application classloader first.
|
* These additional classes will be injected into the application classloader first.
|
||||||
*/
|
*/
|
||||||
protected String[] additionalHelperClassNames() {
|
protected String[] additionalHelperClassNames() {
|
||||||
return EMPTY;
|
return EMPTY;
|
||||||
|
@ -342,6 +365,26 @@ public abstract class InstrumentationModule {
|
||||||
return any();
|
return any();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumentation modules that use existing library instrumentation should override this method
|
||||||
|
* to specify additional packages (or classes) that should be treated as "library instrumentation"
|
||||||
|
* packages/classes.
|
||||||
|
*
|
||||||
|
* <p>Classes marked as library instrumentation classes will be treated by muzzle as
|
||||||
|
* instrumentation helper classes: they will be scanned for references and automatically injected
|
||||||
|
* into the application classloader if they're used in any type instrumentation.
|
||||||
|
*
|
||||||
|
* <p>In addition to that, the javaagent will prevent the instrumentations from this module from
|
||||||
|
* being applied when it detects that the application classloader already contains one of the
|
||||||
|
* library classes. This behavior prevents interference between library and javaagent
|
||||||
|
* instrumentation (for example, duplicate telemetry).
|
||||||
|
*
|
||||||
|
* @param className The name of the class that may or may not be a library instrumentation class.
|
||||||
|
*/
|
||||||
|
public boolean isLibraryInstrumentationClass(String className) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a list of all individual type instrumentation in this module. */
|
/** Returns a list of all individual type instrumentation in this module. */
|
||||||
public abstract List<TypeInstrumentation> typeInstrumentations();
|
public abstract List<TypeInstrumentation> typeInstrumentations();
|
||||||
|
|
||||||
|
|
|
@ -92,4 +92,10 @@ public class AgentElementMatchers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Execute {@code callback} action whenever decorated {@code matcher} returns true. */
|
||||||
|
public static <T> ElementMatcher.Junction<T> callWhenTrue(
|
||||||
|
ElementMatcher<? super T> matcher, Runnable callback) {
|
||||||
|
return new CallWhenTrueDecorator<>(matcher, callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.tooling.bytebuddy.matcher;
|
||||||
|
|
||||||
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
|
final class CallWhenTrueDecorator<T> extends ElementMatcher.Junction.AbstractBase<T> {
|
||||||
|
private final ElementMatcher<? super T> delegate;
|
||||||
|
private final Runnable callback;
|
||||||
|
|
||||||
|
CallWhenTrueDecorator(ElementMatcher<? super T> delegate, Runnable callback) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(T target) {
|
||||||
|
if (delegate.matches(target)) {
|
||||||
|
callback.run();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,13 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.tooling.bytebuddy.matcher;
|
package io.opentelemetry.javaagent.tooling.bytebuddy.matcher;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.caching.Cache;
|
import io.opentelemetry.instrumentation.api.caching.Cache;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.internal.InClassLoaderMatcher;
|
import io.opentelemetry.javaagent.instrumentation.api.internal.InClassLoaderMatcher;
|
||||||
|
import io.opentelemetry.javaagent.tooling.Utils;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
public final class ClassLoaderMatcher {
|
public final class ClassLoaderMatcher {
|
||||||
|
@ -19,45 +24,40 @@ public final class ClassLoaderMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTICE: Does not match the bootstrap classpath. Don't use with classes expected to be on the
|
* Creates a matcher that checks if all of the passed classes are in the passed {@link
|
||||||
* bootstrap.
|
* ClassLoader}. If {@code classNames} is empty the matcher will always return {@code true}.
|
||||||
*
|
*
|
||||||
* @param classNames list of names to match. returns true if empty.
|
* <p>NOTICE: Does not match the bootstrap classpath. Don't use with classes expected to be on the
|
||||||
* @return true if class is available as a resource and not the bootstrap classloader.
|
* bootstrap.
|
||||||
*/
|
*/
|
||||||
public static ElementMatcher.Junction.AbstractBase<ClassLoader> hasClassesNamed(
|
public static ElementMatcher.Junction<ClassLoader> hasClassesNamed(String... classNames) {
|
||||||
String... classNames) {
|
return new ClassLoaderHasAllClassesNamedMatcher(asList(classNames));
|
||||||
return new ClassLoaderHasClassesNamedMatcher(classNames);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ClassLoaderHasClassesNamedMatcher
|
/**
|
||||||
|
* Creates a matcher that checks if any of the passed classes are in the passed {@link
|
||||||
|
* ClassLoader}. If {@code classNames} is empty the matcher will always return {@code false}.
|
||||||
|
*
|
||||||
|
* <p>NOTICE: Does not match the bootstrap classpath. Don't use with classes expected to be on the
|
||||||
|
* bootstrap.
|
||||||
|
*/
|
||||||
|
public static ElementMatcher.Junction<ClassLoader> hasAnyClassesNamed(List<String> classNames) {
|
||||||
|
return new ClassLoaderHasAnyClassesNamedMatcher(classNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract static class AbstractClassLoaderMatcher
|
||||||
extends ElementMatcher.Junction.AbstractBase<ClassLoader> {
|
extends ElementMatcher.Junction.AbstractBase<ClassLoader> {
|
||||||
|
|
||||||
private final Cache<ClassLoader, Boolean> cache =
|
private final Cache<ClassLoader, Boolean> cache =
|
||||||
Cache.newBuilder().setWeakKeys().setMaximumSize(25).build();
|
Cache.newBuilder().setWeakKeys().setMaximumSize(25).build();
|
||||||
|
|
||||||
private final String[] resources;
|
protected final List<String> resources;
|
||||||
|
|
||||||
private ClassLoaderHasClassesNamedMatcher(String... classNames) {
|
private AbstractClassLoaderMatcher(List<String> classNames) {
|
||||||
resources = classNames;
|
resources = classNames.stream().map(Utils::getResourceName).collect(Collectors.toList());
|
||||||
for (int i = 0; i < resources.length; i++) {
|
|
||||||
resources[i] = resources[i].replace(".", "/") + ".class";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasResources(ClassLoader cl) {
|
protected abstract boolean doMatch(ClassLoader cl);
|
||||||
boolean priorValue = InClassLoaderMatcher.getAndSet(true);
|
|
||||||
try {
|
|
||||||
for (String resource : resources) {
|
|
||||||
if (cl.getResource(resource) == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
InClassLoaderMatcher.set(priorValue);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(ClassLoader cl) {
|
public boolean matches(ClassLoader cl) {
|
||||||
|
@ -67,5 +67,48 @@ public final class ClassLoaderMatcher {
|
||||||
}
|
}
|
||||||
return cache.computeIfAbsent(cl, this::hasResources);
|
return cache.computeIfAbsent(cl, this::hasResources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasResources(ClassLoader cl) {
|
||||||
|
boolean priorValue = InClassLoaderMatcher.getAndSet(true);
|
||||||
|
boolean value;
|
||||||
|
try {
|
||||||
|
value = doMatch(cl);
|
||||||
|
} finally {
|
||||||
|
InClassLoaderMatcher.set(priorValue);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ClassLoaderHasAllClassesNamedMatcher extends AbstractClassLoaderMatcher {
|
||||||
|
private ClassLoaderHasAllClassesNamedMatcher(List<String> classNames) {
|
||||||
|
super(classNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doMatch(ClassLoader cl) {
|
||||||
|
for (String resource : resources) {
|
||||||
|
if (cl.getResource(resource) == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ClassLoaderHasAnyClassesNamedMatcher extends AbstractClassLoaderMatcher {
|
||||||
|
private ClassLoaderHasAnyClassesNamedMatcher(List<String> classNames) {
|
||||||
|
super(classNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doMatch(ClassLoader cl) {
|
||||||
|
for (String resource : resources) {
|
||||||
|
if (cl.getResource(resource) != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,9 @@ public final class InstrumentationClassPredicate {
|
||||||
private static final String JAVAAGENT_API_PACKAGE =
|
private static final String JAVAAGENT_API_PACKAGE =
|
||||||
"io.opentelemetry.javaagent.instrumentation.api.";
|
"io.opentelemetry.javaagent.instrumentation.api.";
|
||||||
|
|
||||||
// library instrumentation packages (both shaded in the agent)
|
// library instrumentation packages
|
||||||
private static final String LIBRARY_INSTRUMENTATION_PACKAGE = "io.opentelemetry.instrumentation.";
|
private static final String LIBRARY_INSTRUMENTATION_PACKAGE = "io.opentelemetry.instrumentation.";
|
||||||
|
// note that instrumentation-api is shaded in the agent
|
||||||
private static final String INSTRUMENTATION_API_PACKAGE = "io.opentelemetry.instrumentation.api.";
|
private static final String INSTRUMENTATION_API_PACKAGE = "io.opentelemetry.instrumentation.api.";
|
||||||
|
|
||||||
private final Predicate<String> additionalLibraryInstrumentationPredicate;
|
private final Predicate<String> additionalLibraryInstrumentationPredicate;
|
||||||
|
|
|
@ -147,7 +147,8 @@ class MuzzleCodeGenerator implements AsmVisitorWrapper {
|
||||||
.flatMap(typeInstrumentation -> typeInstrumentation.transformers().values().stream())
|
.flatMap(typeInstrumentation -> typeInstrumentation.transformers().values().stream())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
ReferenceCollector collector = new ReferenceCollector(instrumentationModule::isHelperClass);
|
ReferenceCollector collector =
|
||||||
|
new ReferenceCollector(instrumentationModule::isLibraryInstrumentationClass);
|
||||||
for (String adviceClass : adviceClassNames) {
|
for (String adviceClass : adviceClassNames) {
|
||||||
collector.collectReferencesFromAdvice(adviceClass);
|
collector.collectReferencesFromAdvice(adviceClass);
|
||||||
}
|
}
|
||||||
|
@ -206,7 +207,7 @@ class MuzzleCodeGenerator implements AsmVisitorWrapper {
|
||||||
* new Reference[]{
|
* new Reference[]{
|
||||||
* // reference builders
|
* // reference builders
|
||||||
* },
|
* },
|
||||||
* this.additionalLibraryInstrumentationPackage());
|
* this.isLibraryInstrumentationClassPredicate());
|
||||||
* }
|
* }
|
||||||
* return this.muzzleReferenceMatcher;
|
* return this.muzzleReferenceMatcher;
|
||||||
* }
|
* }
|
||||||
|
@ -472,7 +473,7 @@ class MuzzleCodeGenerator implements AsmVisitorWrapper {
|
||||||
mv.visitMethodInsn(
|
mv.visitMethodInsn(
|
||||||
Opcodes.INVOKEVIRTUAL,
|
Opcodes.INVOKEVIRTUAL,
|
||||||
instrumentationClassName,
|
instrumentationClassName,
|
||||||
"additionalLibraryInstrumentationPackage",
|
"isLibraryInstrumentationClassPredicate",
|
||||||
"()Ljava/util/function/Predicate;",
|
"()Ljava/util/function/Predicate;",
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.tooling.bytebuddy.matcher;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.BDDMockito.then;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
|
||||||
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class CallWhenTrueDecoratorTest {
|
||||||
|
@Mock ElementMatcher<String> delegateMatcher;
|
||||||
|
@Mock Runnable callback;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldExecuteCallbackWhenMatcherReturnsTrue() {
|
||||||
|
// given
|
||||||
|
ElementMatcher<String> matcher = new CallWhenTrueDecorator<>(delegateMatcher, callback);
|
||||||
|
|
||||||
|
given(delegateMatcher.matches("true")).willReturn(true);
|
||||||
|
|
||||||
|
// when
|
||||||
|
boolean result = matcher.matches("true");
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(result);
|
||||||
|
then(callback).should().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotExecuteCallbackWhenMatcherReturnsFalse() {
|
||||||
|
// given
|
||||||
|
ElementMatcher<String> matcher = new CallWhenTrueDecorator<>(delegateMatcher, callback);
|
||||||
|
|
||||||
|
// when
|
||||||
|
boolean result = matcher.matches("not really true");
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertFalse(result);
|
||||||
|
then(callback).should(never()).run();
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,7 +87,7 @@ tasks.withType(ShadowJar).configureEach {
|
||||||
// rewrite dependencies calling Logger.getLogger
|
// rewrite dependencies calling Logger.getLogger
|
||||||
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
||||||
|
|
||||||
// prevents conflict with library instrumentation
|
// prevents conflict with library instrumentation, which uses its own instrumentation-api
|
||||||
relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
|
relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
|
||||||
|
|
||||||
// relocate OpenTelemetry API
|
// relocate OpenTelemetry API
|
||||||
|
|
|
@ -43,12 +43,12 @@ shadowJar {
|
||||||
// Prevents conflict with other SLF4J instances. Important for premain.
|
// Prevents conflict with other SLF4J instances. Important for premain.
|
||||||
relocate 'org.slf4j', 'io.opentelemetry.javaagent.slf4j'
|
relocate 'org.slf4j', 'io.opentelemetry.javaagent.slf4j'
|
||||||
|
|
||||||
// rewrite library instrumentation dependencies
|
|
||||||
relocate "io.opentelemetry.instrumentation", "io.opentelemetry.javaagent.shaded.instrumentation"
|
|
||||||
|
|
||||||
// rewrite dependencies calling Logger.getLogger
|
// rewrite dependencies calling Logger.getLogger
|
||||||
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
||||||
|
|
||||||
|
// prevents conflict with library instrumentation, which uses its own instrumentation-api
|
||||||
|
relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
|
||||||
|
|
||||||
// relocate OpenTelemetry API usage
|
// relocate OpenTelemetry API usage
|
||||||
relocate "io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api"
|
relocate "io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api"
|
||||||
relocate "io.opentelemetry.semconv", "io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv"
|
relocate "io.opentelemetry.semconv", "io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv"
|
||||||
|
|
|
@ -59,7 +59,7 @@ shadowJar {
|
||||||
// rewrite dependencies calling Logger.getLogger
|
// rewrite dependencies calling Logger.getLogger
|
||||||
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
|
||||||
|
|
||||||
// prevents conflict with library instrumentation
|
// prevents conflict with library instrumentation, which uses its own instrumentation-api
|
||||||
relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
|
relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
|
||||||
|
|
||||||
// relocate OpenTelemetry API
|
// relocate OpenTelemetry API
|
||||||
|
|
Loading…
Reference in New Issue