From fb784aa8772f9c1ba440cb4e9dd9813ed8ec7eff Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 11 Jul 2022 14:34:26 -0700 Subject: [PATCH] Support new annotations (and change of instrumentation name for opentelemetry-annotations) (#6296) * Support new annotations * Consistency * Simplify * Annotation * oops --- .../kotlin/otel.java-conventions.gradle.kts | 1 + .../build.gradle.kts | 2 - .../otelannotations/AbstractTraced.java | 0 .../otelannotations/AbstractWithSpanTest.java | 0 .../guava-10.0/javaagent/build.gradle.kts | 2 +- ...anTest.java => BaseGuavaWithSpanTest.java} | 31 +- ...ExtensionAnnotationsGuavaWithSpanTest.java | 42 ++ .../opentelemetry-annotations-1.0/README.md | 5 - .../javaagent/build.gradle.kts | 2 +- .../README.md | 5 + .../javaagent/build.gradle.kts | 0 .../extensionannotations}/MethodRequest.java | 2 +- .../WithSpanInstrumentation.java | 200 +++++++++ .../WithSpanInstrumentationModule.java | 4 +- ...hSpanParameterAttributeNamesExtractor.java | 3 +- .../WithSpanSingletons.java | 2 +- .../groovy/WithSpanInstrumentationTest.groovy | 0 .../test/annotation/TracedWithSpan.java | 0 .../README.md | 5 + .../javaagent/build.gradle.kts | 42 ++ .../MethodRequest.java | 26 ++ .../WithSpanInstrumentation.java | 22 +- .../WithSpanInstrumentationModule.java | 28 ++ ...hSpanParameterAttributeNamesExtractor.java | 69 +++ .../WithSpanSingletons.java | 89 ++++ .../groovy/WithSpanInstrumentationTest.groovy | 405 ++++++++++++++++++ .../test/annotation/TracedWithSpan.java | 60 +++ .../reactor-3.1/javaagent/build.gradle.kts | 2 +- ...panTest.java => BaseFluxWithSpanTest.java} | 34 +- ...panTest.java => BaseMonoWithSpanTest.java} | 35 +- ...ropagationOperatorInstrumentationTest.java | 10 +- .../ExtensionAnnotationsFluxWithSpanTest.java | 45 ++ .../ExtensionAnnotationsMonoWithSpanTest.java | 46 ++ .../ExtensionAnnotationsTracedWithSpan.java | 31 ++ .../reactor/TracedWithSpan.java | 18 +- .../javaagent/build.gradle.kts | 2 +- javaagent/build.gradle.kts | 3 +- .../build.gradle.kts | 3 +- .../build.gradle.kts | 23 + settings.gradle.kts | 6 +- 40 files changed, 1166 insertions(+), 139 deletions(-) rename {instrumentation/opentelemetry-annotations-1.0/testing => instrumentation-annotations-support-testing}/build.gradle.kts (55%) rename {instrumentation/opentelemetry-annotations-1.0/testing => instrumentation-annotations-support-testing}/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractTraced.java (100%) rename {instrumentation/opentelemetry-annotations-1.0/testing => instrumentation-annotations-support-testing}/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractWithSpanTest.java (100%) rename instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/{GuavaWithSpanTest.java => BaseGuavaWithSpanTest.java} (59%) create mode 100644 instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/ExtensionAnnotationsGuavaWithSpanTest.java delete mode 100644 instrumentation/opentelemetry-annotations-1.0/README.md create mode 100644 instrumentation/opentelemetry-extension-annotations-1.0/README.md rename instrumentation/{opentelemetry-annotations-1.0 => opentelemetry-extension-annotations-1.0}/javaagent/build.gradle.kts (100%) rename instrumentation/{opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations => opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations}/MethodRequest.java (85%) create mode 100644 instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanInstrumentation.java rename instrumentation/{opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations => opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations}/WithSpanInstrumentationModule.java (86%) rename instrumentation/{opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations => opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations}/WithSpanParameterAttributeNamesExtractor.java (96%) rename instrumentation/{opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations => opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations}/WithSpanSingletons.java (97%) rename instrumentation/{opentelemetry-annotations-1.0 => opentelemetry-extension-annotations-1.0}/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy (100%) rename instrumentation/{opentelemetry-annotations-1.0 => opentelemetry-extension-annotations-1.0}/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java (100%) create mode 100644 instrumentation/opentelemetry-instrumentation-annotations-1.16/README.md create mode 100644 instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/build.gradle.kts create mode 100644 instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/MethodRequest.java rename instrumentation/{opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations => opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations}/WithSpanInstrumentation.java (89%) create mode 100644 instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanInstrumentationModule.java create mode 100644 instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanParameterAttributeNamesExtractor.java create mode 100644 instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanSingletons.java create mode 100644 instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy create mode 100644 instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java rename instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/{FluxWithSpanTest.java => BaseFluxWithSpanTest.java} (82%) rename instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/{MonoWithSpanTest.java => BaseMonoWithSpanTest.java} (82%) create mode 100644 instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsFluxWithSpanTest.java create mode 100644 instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsMonoWithSpanTest.java create mode 100644 instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsTracedWithSpan.java create mode 100644 opentelemetry-instrumentation-annotations-shaded-for-instrumenting/build.gradle.kts diff --git a/conventions/src/main/kotlin/otel.java-conventions.gradle.kts b/conventions/src/main/kotlin/otel.java-conventions.gradle.kts index 2b491bebdf..b05a41ba9e 100644 --- a/conventions/src/main/kotlin/otel.java-conventions.gradle.kts +++ b/conventions/src/main/kotlin/otel.java-conventions.gradle.kts @@ -376,6 +376,7 @@ configurations.configureEach { dependencySubstitution { substitute(module("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api")).using(project(":instrumentation-api")) substitute(module("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-semconv")).using(project(":instrumentation-api-semconv")) + substitute(module("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations")).using(project(":instrumentation-annotations")) substitute(module("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations-support")).using(project(":instrumentation-annotations-support")) substitute(module("io.opentelemetry.instrumentation:opentelemetry-instrumentation-appender-api-internal")).using(project(":instrumentation-appender-api-internal")) substitute(module("io.opentelemetry.javaagent:opentelemetry-javaagent-bootstrap")).using(project(":javaagent-bootstrap")) diff --git a/instrumentation/opentelemetry-annotations-1.0/testing/build.gradle.kts b/instrumentation-annotations-support-testing/build.gradle.kts similarity index 55% rename from instrumentation/opentelemetry-annotations-1.0/testing/build.gradle.kts rename to instrumentation-annotations-support-testing/build.gradle.kts index 7a990e83ed..484e04028a 100644 --- a/instrumentation/opentelemetry-annotations-1.0/testing/build.gradle.kts +++ b/instrumentation-annotations-support-testing/build.gradle.kts @@ -4,6 +4,4 @@ plugins { dependencies { api(project(":testing-common")) - - implementation("io.opentelemetry:opentelemetry-extension-annotations") } diff --git a/instrumentation/opentelemetry-annotations-1.0/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractTraced.java b/instrumentation-annotations-support-testing/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractTraced.java similarity index 100% rename from instrumentation/opentelemetry-annotations-1.0/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractTraced.java rename to instrumentation-annotations-support-testing/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractTraced.java diff --git a/instrumentation/opentelemetry-annotations-1.0/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractWithSpanTest.java b/instrumentation-annotations-support-testing/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractWithSpanTest.java similarity index 100% rename from instrumentation/opentelemetry-annotations-1.0/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractWithSpanTest.java rename to instrumentation-annotations-support-testing/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/AbstractWithSpanTest.java diff --git a/instrumentation/guava-10.0/javaagent/build.gradle.kts b/instrumentation/guava-10.0/javaagent/build.gradle.kts index 34365ed0b1..73c5a399d1 100644 --- a/instrumentation/guava-10.0/javaagent/build.gradle.kts +++ b/instrumentation/guava-10.0/javaagent/build.gradle.kts @@ -24,6 +24,6 @@ dependencies { implementation(project(":instrumentation:guava-10.0:library")) - testImplementation(project(":instrumentation:opentelemetry-annotations-1.0:testing")) + testImplementation(project(":instrumentation-annotations-support-testing")) testImplementation("io.opentelemetry:opentelemetry-extension-annotations") } diff --git a/instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/GuavaWithSpanTest.java b/instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/BaseGuavaWithSpanTest.java similarity index 59% rename from instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/GuavaWithSpanTest.java rename to instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/BaseGuavaWithSpanTest.java index 95fde75277..fd84ff458a 100644 --- a/instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/GuavaWithSpanTest.java +++ b/instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/BaseGuavaWithSpanTest.java @@ -8,19 +8,12 @@ package io.opentelemetry.javaagent.instrumentation.guava; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; -import io.opentelemetry.extension.annotations.WithSpan; -import io.opentelemetry.javaagent.instrumentation.otelannotations.AbstractTraced; import io.opentelemetry.javaagent.instrumentation.otelannotations.AbstractWithSpanTest; import org.testcontainers.shaded.com.google.common.base.Throwables; -class GuavaWithSpanTest +abstract class BaseGuavaWithSpanTest extends AbstractWithSpanTest, ListenableFuture> { - @Override - protected AbstractTraced, ListenableFuture> newTraced() { - return new Traced(); - } - @Override protected void complete(SettableFuture future, String value) { future.set(value); @@ -50,26 +43,4 @@ class GuavaWithSpanTest protected String canceledKey() { return "guava.canceled"; } - - static final class Traced - extends AbstractTraced, ListenableFuture> { - - @Override - @WithSpan - protected SettableFuture completable() { - return SettableFuture.create(); - } - - @Override - @WithSpan - protected ListenableFuture alreadySucceeded() { - return Futures.immediateFuture("Value"); - } - - @Override - @WithSpan - protected ListenableFuture alreadyFailed() { - return Futures.immediateFailedFuture(FAILURE); - } - } } diff --git a/instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/ExtensionAnnotationsGuavaWithSpanTest.java b/instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/ExtensionAnnotationsGuavaWithSpanTest.java new file mode 100644 index 0000000000..0b6a96f680 --- /dev/null +++ b/instrumentation/guava-10.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/guava/ExtensionAnnotationsGuavaWithSpanTest.java @@ -0,0 +1,42 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.guava; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; +import io.opentelemetry.extension.annotations.WithSpan; +import io.opentelemetry.javaagent.instrumentation.otelannotations.AbstractTraced; + +class ExtensionAnnotationsGuavaWithSpanTest extends BaseGuavaWithSpanTest { + + @Override + protected AbstractTraced, ListenableFuture> newTraced() { + return new Traced(); + } + + static final class Traced + extends AbstractTraced, ListenableFuture> { + + @Override + @WithSpan + protected SettableFuture completable() { + return SettableFuture.create(); + } + + @Override + @WithSpan + protected ListenableFuture alreadySucceeded() { + return Futures.immediateFuture("Value"); + } + + @Override + @WithSpan + protected ListenableFuture alreadyFailed() { + return Futures.immediateFailedFuture(FAILURE); + } + } +} diff --git a/instrumentation/opentelemetry-annotations-1.0/README.md b/instrumentation/opentelemetry-annotations-1.0/README.md deleted file mode 100644 index 33d9911f68..0000000000 --- a/instrumentation/opentelemetry-annotations-1.0/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Settings for the OpenTelemetry Annotations integration - -| Environment variable | Type | Default | Description | -|----------------- |------ |--------- |------------- | -| `otel.instrumentation.external-annotations.exclude-methods` | String | | All methods to be excluded from auto-instrumentation by annotation-based advices. | \ No newline at end of file diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/build.gradle.kts b/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/build.gradle.kts index 2e4242fc0c..5dc4443732 100644 --- a/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/build.gradle.kts +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/build.gradle.kts @@ -41,5 +41,5 @@ dependencies { // @WithSpan annotation is used to generate spans in ContextBridgeTest testImplementation("io.opentelemetry:opentelemetry-extension-annotations") - testInstrumentation(project(":instrumentation:opentelemetry-annotations-1.0:javaagent")) + testInstrumentation(project(":instrumentation:opentelemetry-extension-annotations-1.0:javaagent")) } diff --git a/instrumentation/opentelemetry-extension-annotations-1.0/README.md b/instrumentation/opentelemetry-extension-annotations-1.0/README.md new file mode 100644 index 0000000000..814adeb6d0 --- /dev/null +++ b/instrumentation/opentelemetry-extension-annotations-1.0/README.md @@ -0,0 +1,5 @@ +# Settings for the OpenTelemetry Extension Annotations integration + +| Environment variable | Type | Default | Description | +|----------------- |------ |--------- |------------- | +| `otel.instrumentation.opentelemetry-annotations.exclude-methods` | String | | All methods to be excluded from auto-instrumentation by annotation-based advices. | \ No newline at end of file diff --git a/instrumentation/opentelemetry-annotations-1.0/javaagent/build.gradle.kts b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/build.gradle.kts similarity index 100% rename from instrumentation/opentelemetry-annotations-1.0/javaagent/build.gradle.kts rename to instrumentation/opentelemetry-extension-annotations-1.0/javaagent/build.gradle.kts diff --git a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/MethodRequest.java b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/MethodRequest.java similarity index 85% rename from instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/MethodRequest.java rename to instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/MethodRequest.java index d886fc72ff..97dbb7c774 100644 --- a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/MethodRequest.java +++ b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/MethodRequest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.otelannotations; +package io.opentelemetry.javaagent.instrumentation.extensionannotations; import java.lang.reflect.Method; diff --git a/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanInstrumentation.java b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanInstrumentation.java new file mode 100644 index 0000000000..ce375b37c4 --- /dev/null +++ b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanInstrumentation.java @@ -0,0 +1,200 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.extensionannotations; + +import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; +import static net.bytebuddy.matcher.ElementMatchers.hasParameters; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.none; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.whereAny; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.annotation.support.async.AsyncOperationEndSupport; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; +import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.tooling.config.MethodsConfigurationParser; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.ByteCodeElement; +import net.bytebuddy.description.annotation.AnnotationSource; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.assign.Assigner; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +public class WithSpanInstrumentation implements TypeInstrumentation { + + private static final String TRACE_ANNOTATED_METHODS_EXCLUDE_CONFIG = + "otel.instrumentation.opentelemetry-annotations.exclude-methods"; + + private final ElementMatcher.Junction annotatedMethodMatcher; + private final ElementMatcher.Junction annotatedParametersMatcher; + // this matcher matches all methods that should be excluded from transformation + private final ElementMatcher.Junction excludedMethodsMatcher; + + WithSpanInstrumentation() { + annotatedMethodMatcher = + isAnnotatedWith(named("application.io.opentelemetry.extension.annotations.WithSpan")); + annotatedParametersMatcher = + hasParameters( + whereAny( + isAnnotatedWith( + named("application.io.opentelemetry.extension.annotations.SpanAttribute")))); + excludedMethodsMatcher = configureExcludedMethods(); + } + + @Override + public ElementMatcher typeMatcher() { + return declaresMethod(annotatedMethodMatcher); + } + + @Override + public void transform(TypeTransformer transformer) { + ElementMatcher.Junction tracedMethods = + annotatedMethodMatcher.and(not(excludedMethodsMatcher)); + + ElementMatcher.Junction tracedMethodsWithParameters = + tracedMethods.and(annotatedParametersMatcher); + ElementMatcher.Junction tracedMethodsWithoutParameters = + tracedMethods.and(not(annotatedParametersMatcher)); + + transformer.applyAdviceToMethod( + tracedMethodsWithoutParameters, + WithSpanInstrumentation.class.getName() + "$WithSpanAdvice"); + + // Only apply advice for tracing parameters as attributes if any of the parameters are annotated + // with @SpanAttribute to avoid unnecessarily copying the arguments into an array. + transformer.applyAdviceToMethod( + tracedMethodsWithParameters, + WithSpanInstrumentation.class.getName() + "$WithSpanAttributesAdvice"); + } + + /* + Returns a matcher for all methods that should be excluded from auto-instrumentation by + annotation-based advices. + */ + static ElementMatcher.Junction configureExcludedMethods() { + ElementMatcher.Junction result = none(); + + Map> excludedMethods = + MethodsConfigurationParser.parse( + InstrumentationConfig.get().getString(TRACE_ANNOTATED_METHODS_EXCLUDE_CONFIG)); + for (Map.Entry> entry : excludedMethods.entrySet()) { + String className = entry.getKey(); + ElementMatcher.Junction matcher = + isDeclaredBy(ElementMatchers.named(className)); + + Set methodNames = entry.getValue(); + if (!methodNames.isEmpty()) { + matcher = matcher.and(namedOneOf(methodNames.toArray(new String[0]))); + } + + result = result.or(matcher); + } + + return result; + } + + @SuppressWarnings("unused") + public static class WithSpanAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Origin Method originMethod, + @Advice.Local("otelMethod") Method method, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + // Every usage of @Advice.Origin Method is replaced with a call to Class.getMethod, copy it + // to local variable so that there would be only one call to Class.getMethod. + method = originMethod; + + Instrumenter instrumenter = WithSpanSingletons.instrumenter(); + Context current = Java8BytecodeBridge.currentContext(); + + if (instrumenter.shouldStart(current, method)) { + context = instrumenter.start(current, method); + scope = context.makeCurrent(); + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Local("otelMethod") Method method, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope, + @Advice.Return(typing = Assigner.Typing.DYNAMIC, readOnly = false) Object returnValue, + @Advice.Thrown Throwable throwable) { + if (scope == null) { + return; + } + scope.close(); + + AsyncOperationEndSupport operationEndSupport = + AsyncOperationEndSupport.create( + WithSpanSingletons.instrumenter(), Object.class, method.getReturnType()); + returnValue = operationEndSupport.asyncEnd(context, method, returnValue, throwable); + } + } + + @SuppressWarnings("unused") + public static class WithSpanAttributesAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Origin Method originMethod, + @Advice.Local("otelMethod") Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Local("otelRequest") MethodRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + + // Every usage of @Advice.Origin Method is replaced with a call to Class.getMethod, copy it + // to local variable so that there would be only one call to Class.getMethod. + method = originMethod; + + Instrumenter instrumenter = + WithSpanSingletons.instrumenterWithAttributes(); + Context current = Java8BytecodeBridge.currentContext(); + request = new MethodRequest(method, args); + + if (instrumenter.shouldStart(current, request)) { + context = instrumenter.start(current, request); + scope = context.makeCurrent(); + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Local("otelMethod") Method method, + @Advice.Local("otelRequest") MethodRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope, + @Advice.Return(typing = Assigner.Typing.DYNAMIC, readOnly = false) Object returnValue, + @Advice.Thrown Throwable throwable) { + if (scope == null) { + return; + } + scope.close(); + AsyncOperationEndSupport operationEndSupport = + AsyncOperationEndSupport.create( + WithSpanSingletons.instrumenterWithAttributes(), + Object.class, + method.getReturnType()); + returnValue = operationEndSupport.asyncEnd(context, request, returnValue, throwable); + } + } +} diff --git a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanInstrumentationModule.java b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanInstrumentationModule.java similarity index 86% rename from instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanInstrumentationModule.java rename to instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanInstrumentationModule.java index 102af65bd4..f7a821ca17 100644 --- a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanInstrumentationModule.java +++ b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanInstrumentationModule.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.otelannotations; +package io.opentelemetry.javaagent.instrumentation.extensionannotations; import static java.util.Collections.singletonList; @@ -18,7 +18,7 @@ import java.util.List; public class WithSpanInstrumentationModule extends InstrumentationModule { public WithSpanInstrumentationModule() { - super("opentelemetry-annotations"); + super("opentelemetry-extension-annotations"); } @Override diff --git a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanParameterAttributeNamesExtractor.java b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanParameterAttributeNamesExtractor.java similarity index 96% rename from instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanParameterAttributeNamesExtractor.java rename to instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanParameterAttributeNamesExtractor.java index 2de8d0089a..bd0a2a994b 100644 --- a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanParameterAttributeNamesExtractor.java +++ b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanParameterAttributeNamesExtractor.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.otelannotations; +package io.opentelemetry.javaagent.instrumentation.extensionannotations; import io.opentelemetry.instrumentation.api.annotation.support.AnnotationReflectionHelper; import io.opentelemetry.instrumentation.api.annotation.support.ParameterAttributeNamesExtractor; @@ -43,7 +43,6 @@ public enum WithSpanParameterAttributeNamesExtractor implements ParameterAttribu } @Override - @Nullable public String[] extract(Method method, Parameter[] parameters) { String[] attributeNames = new String[parameters.length]; for (int i = 0; i < parameters.length; i++) { diff --git a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanSingletons.java b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanSingletons.java similarity index 97% rename from instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanSingletons.java rename to instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanSingletons.java index e229d176c0..4ca6c53172 100644 --- a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanSingletons.java +++ b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extensionannotations/WithSpanSingletons.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.otelannotations; +package io.opentelemetry.javaagent.instrumentation.extensionannotations; import static java.util.logging.Level.FINE; diff --git a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy similarity index 100% rename from instrumentation/opentelemetry-annotations-1.0/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy rename to instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy diff --git a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java b/instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java similarity index 100% rename from instrumentation/opentelemetry-annotations-1.0/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java rename to instrumentation/opentelemetry-extension-annotations-1.0/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java diff --git a/instrumentation/opentelemetry-instrumentation-annotations-1.16/README.md b/instrumentation/opentelemetry-instrumentation-annotations-1.16/README.md new file mode 100644 index 0000000000..a7fffbfc33 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-annotations-1.16/README.md @@ -0,0 +1,5 @@ +# Settings for the OpenTelemetry Instrumentation Annotations integration + +| Environment variable | Type | Default | Description | +|----------------- |------ |--------- |------------- | +| `otel.instrumentation.opentelemetry-annotations.exclude-methods` | String | | All methods to be excluded from auto-instrumentation by annotation-based advices. | \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/build.gradle.kts b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/build.gradle.kts new file mode 100644 index 0000000000..ba169155f4 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/build.gradle.kts @@ -0,0 +1,42 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +// note that muzzle is not run against the current SNAPSHOT instrumentation-annotations, but this is +// ok because the tests are run against the current SNAPSHOT instrumentation-annotations which will +// catch any muzzle issues in SNAPSHOT instrumentation-annotations + +muzzle { + pass { + group.set("io.opentelemetry") + module.set("opentelemetry-instrumentation-annotations") + versions.set("(,)") + } +} + +val versions: Map by project + +dependencies { + compileOnly(project(":instrumentation-annotations-support")) + + compileOnly(project(":javaagent-tooling")) + + // this instrumentation needs to do similar shading dance as opentelemetry-api-1.0 because + // the @WithSpan annotation references the OpenTelemetry API's SpanKind class + // + // see the comment in opentelemetry-api-1.0.gradle for more details + compileOnly(project(":opentelemetry-instrumentation-annotations-shaded-for-instrumenting", configuration = "shadow")) + + testImplementation("io.opentelemetry:opentelemetry-extension-annotations") + testImplementation(project(":instrumentation-annotations-support")) + testImplementation("net.bytebuddy:byte-buddy") +} + +tasks { + compileTestJava { + options.compilerArgs.add("-parameters") + } + test { + jvmArgs("-Dotel.instrumentation.opentelemetry-annotations.exclude-methods=io.opentelemetry.test.annotation.TracedWithSpan[ignored]") + } +} diff --git a/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/MethodRequest.java b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/MethodRequest.java new file mode 100644 index 0000000000..32b09d6bf9 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/MethodRequest.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.instrumentationannotations; + +import java.lang.reflect.Method; + +public final class MethodRequest { + private final Method method; + private final Object[] args; + + public MethodRequest(Method method, Object[] args) { + this.method = method; + this.args = args; + } + + public Method method() { + return this.method; + } + + public Object[] args() { + return this.args; + } +} diff --git a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanInstrumentation.java b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanInstrumentation.java similarity index 89% rename from instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanInstrumentation.java rename to instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanInstrumentation.java index d4d880f5a6..b90df1ced9 100644 --- a/instrumentation/opentelemetry-annotations-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/otelannotations/WithSpanInstrumentation.java +++ b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanInstrumentation.java @@ -3,15 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.otelannotations; +package io.opentelemetry.javaagent.instrumentation.instrumentationannotations; -import static io.opentelemetry.javaagent.instrumentation.otelannotations.WithSpanSingletons.instrumenter; -import static io.opentelemetry.javaagent.instrumentation.otelannotations.WithSpanSingletons.instrumenterWithAttributes; +import static io.opentelemetry.javaagent.instrumentation.instrumentationannotations.WithSpanSingletons.instrumenter; +import static io.opentelemetry.javaagent.instrumentation.instrumentationannotations.WithSpanSingletons.instrumenterWithAttributes; import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; import static net.bytebuddy.matcher.ElementMatchers.hasParameters; import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import static net.bytebuddy.matcher.ElementMatchers.none; import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.whereAny; @@ -49,12 +50,13 @@ public class WithSpanInstrumentation implements TypeInstrumentation { WithSpanInstrumentation() { annotatedMethodMatcher = - isAnnotatedWith(named("application.io.opentelemetry.extension.annotations.WithSpan")); + isAnnotatedWith(named("application.io.opentelemetry.instrumentation.annotations.WithSpan")); annotatedParametersMatcher = hasParameters( whereAny( isAnnotatedWith( - named("application.io.opentelemetry.extension.annotations.SpanAttribute")))); + named( + "application.io.opentelemetry.instrumentation.annotations.SpanAttribute")))); excludedMethodsMatcher = configureExcludedMethods(); } @@ -96,15 +98,15 @@ public class WithSpanInstrumentation implements TypeInstrumentation { InstrumentationConfig.get().getString(TRACE_ANNOTATED_METHODS_EXCLUDE_CONFIG)); for (Map.Entry> entry : excludedMethods.entrySet()) { String className = entry.getKey(); - ElementMatcher.Junction classMather = + ElementMatcher.Junction matcher = isDeclaredBy(ElementMatchers.named(className)); - ElementMatcher.Junction excludedMethodsMatcher = none(); - for (String methodName : entry.getValue()) { - excludedMethodsMatcher = excludedMethodsMatcher.or(ElementMatchers.named(methodName)); + Set methodNames = entry.getValue(); + if (!methodNames.isEmpty()) { + matcher = matcher.and(namedOneOf(methodNames.toArray(new String[0]))); } - result = result.or(classMather.and(excludedMethodsMatcher)); + result = result.or(matcher); } return result; diff --git a/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanInstrumentationModule.java b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanInstrumentationModule.java new file mode 100644 index 0000000000..99d485452a --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanInstrumentationModule.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.instrumentationannotations; + +import static java.util.Collections.singletonList; + +import application.io.opentelemetry.instrumentation.annotations.WithSpan; +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; + +/** Instrumentation for methods annotated with {@link WithSpan} annotation. */ +@AutoService(InstrumentationModule.class) +public class WithSpanInstrumentationModule extends InstrumentationModule { + + public WithSpanInstrumentationModule() { + super("opentelemetry-instrumentation-annotations"); + } + + @Override + public List typeInstrumentations() { + return singletonList(new WithSpanInstrumentation()); + } +} diff --git a/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanParameterAttributeNamesExtractor.java b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanParameterAttributeNamesExtractor.java new file mode 100644 index 0000000000..2811057d2f --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanParameterAttributeNamesExtractor.java @@ -0,0 +1,69 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.instrumentationannotations; + +import io.opentelemetry.instrumentation.api.annotation.support.AnnotationReflectionHelper; +import io.opentelemetry.instrumentation.api.annotation.support.ParameterAttributeNamesExtractor; +import java.lang.annotation.Annotation; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.function.Function; +import javax.annotation.Nullable; + +public enum WithSpanParameterAttributeNamesExtractor implements ParameterAttributeNamesExtractor { + INSTANCE; + + private static final Class spanAttributeAnnotation; + private static final Function spanAttributeValueFunction; + + static { + ClassLoader classLoader = WithSpanParameterAttributeNamesExtractor.class.getClassLoader(); + spanAttributeAnnotation = + AnnotationReflectionHelper.forNameOrNull( + classLoader, "io.opentelemetry.instrumentation.annotations.SpanAttribute"); + if (spanAttributeAnnotation != null) { + spanAttributeValueFunction = resolveSpanAttributeValue(spanAttributeAnnotation); + } else { + spanAttributeValueFunction = null; + } + } + + private static Function resolveSpanAttributeValue( + Class spanAttributeAnnotation) { + try { + return AnnotationReflectionHelper.bindAnnotationElementMethod( + MethodHandles.lookup(), spanAttributeAnnotation, "value", String.class); + } catch (Throwable exception) { + return annotation -> ""; + } + } + + @Override + public String[] extract(Method method, Parameter[] parameters) { + String[] attributeNames = new String[parameters.length]; + for (int i = 0; i < parameters.length; i++) { + attributeNames[i] = attributeName(parameters[i]); + } + return attributeNames; + } + + @Nullable + private static String attributeName(Parameter parameter) { + Annotation annotation = parameter.getDeclaredAnnotation(spanAttributeAnnotation); + if (annotation == null) { + return null; + } + String value = spanAttributeValueFunction.apply(annotation); + if (!value.isEmpty()) { + return value; + } else if (parameter.isNamePresent()) { + return parameter.getName(); + } else { + return null; + } + } +} diff --git a/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanSingletons.java b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanSingletons.java new file mode 100644 index 0000000000..e78e30d316 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/instrumentationannotations/WithSpanSingletons.java @@ -0,0 +1,89 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.instrumentationannotations; + +import static java.util.logging.Level.FINE; + +import application.io.opentelemetry.instrumentation.annotations.WithSpan; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.api.annotation.support.MethodSpanAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.util.SpanNames; +import java.lang.reflect.Method; +import java.util.logging.Logger; + +public final class WithSpanSingletons { + private static final String INSTRUMENTATION_NAME = + "io.opentelemetry.opentelemetry-annotations-1.0"; + + private static final Logger logger = Logger.getLogger(WithSpanSingletons.class.getName()); + private static final Instrumenter INSTRUMENTER = createInstrumenter(); + private static final Instrumenter INSTRUMENTER_WITH_ATTRIBUTES = + createInstrumenterWithAttributes(); + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + public static Instrumenter instrumenterWithAttributes() { + return INSTRUMENTER_WITH_ATTRIBUTES; + } + + private static Instrumenter createInstrumenter() { + return Instrumenter.builder( + GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, WithSpanSingletons::spanNameFromMethod) + .newInstrumenter(WithSpanSingletons::spanKindFromMethod); + } + + private static Instrumenter createInstrumenterWithAttributes() { + return Instrumenter.builder( + GlobalOpenTelemetry.get(), + INSTRUMENTATION_NAME, + WithSpanSingletons::spanNameFromMethodRequest) + .addAttributesExtractor( + MethodSpanAttributesExtractor.newInstance( + MethodRequest::method, + WithSpanParameterAttributeNamesExtractor.INSTANCE, + MethodRequest::args)) + .newInstrumenter(WithSpanSingletons::spanKindFromMethodRequest); + } + + private static SpanKind spanKindFromMethodRequest(MethodRequest request) { + return spanKindFromMethod(request.method()); + } + + private static SpanKind spanKindFromMethod(Method method) { + WithSpan annotation = method.getDeclaredAnnotation(WithSpan.class); + if (annotation == null) { + return SpanKind.INTERNAL; + } + return toAgentOrNull(annotation.kind()); + } + + private static SpanKind toAgentOrNull( + application.io.opentelemetry.api.trace.SpanKind applicationSpanKind) { + try { + return SpanKind.valueOf(applicationSpanKind.name()); + } catch (IllegalArgumentException e) { + logger.log(FINE, "unexpected span kind: {0}", applicationSpanKind.name()); + return SpanKind.INTERNAL; + } + } + + private static String spanNameFromMethodRequest(MethodRequest request) { + return spanNameFromMethod(request.method()); + } + + private static String spanNameFromMethod(Method method) { + WithSpan annotation = method.getDeclaredAnnotation(WithSpan.class); + String spanName = annotation.value(); + if (spanName.isEmpty()) { + spanName = SpanNames.fromMethod(method); + } + return spanName; + } +} diff --git a/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy new file mode 100644 index 0000000000..14fef17c9a --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy @@ -0,0 +1,405 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +import io.opentelemetry.extension.annotations.WithSpan +import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification +import io.opentelemetry.test.annotation.TracedWithSpan +import net.bytebuddy.ByteBuddy +import net.bytebuddy.ClassFileVersion +import net.bytebuddy.asm.MemberAttributeExtension +import net.bytebuddy.description.annotation.AnnotationDescription +import net.bytebuddy.implementation.MethodDelegation +import net.bytebuddy.implementation.bind.annotation.RuntimeType +import net.bytebuddy.implementation.bind.annotation.This +import net.bytebuddy.matcher.ElementMatchers + +import java.lang.reflect.Modifier +import java.util.concurrent.CompletableFuture + +import static io.opentelemetry.api.trace.SpanKind.INTERNAL +import static io.opentelemetry.api.trace.SpanKind.PRODUCER +import static io.opentelemetry.api.trace.SpanKind.SERVER +import static io.opentelemetry.api.trace.StatusCode.ERROR + +/** + * This test verifies that auto instrumentation supports {@link io.opentelemetry.extension.annotations.WithSpan} contrib annotation. + */ +class WithSpanInstrumentationTest extends AgentInstrumentationSpecification { + + def "should derive automatic name"() { + setup: + new TracedWithSpan().otel() + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.otel" + kind INTERNAL + hasNoParent() + attributes { + } + } + } + } + } + + def "should take span name from annotation"() { + setup: + new TracedWithSpan().namedOtel() + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "manualName" + hasNoParent() + attributes { + } + } + } + } + } + + def "should take span kind from annotation"() { + setup: + new TracedWithSpan().someKind() + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.someKind" + kind PRODUCER + hasNoParent() + attributes { + } + } + } + } + } + + def "should capture multiple spans"() { + setup: + new TracedWithSpan().server() + + expect: + assertTraces(1) { + trace(0, 2) { + span(0) { + name "TracedWithSpan.server" + kind SERVER + hasNoParent() + attributes { + } + } + span(1) { + name "TracedWithSpan.otel" + childOf span(0) + attributes { + } + } + } + } + } + + def "should ignore method excluded by trace.annotated.methods.exclude configuration"() { + setup: + new TracedWithSpan().ignored() + + expect: + Thread.sleep(500) // sleep a bit just to make sure no span is captured + assertTraces(0) {} + } + + def "should capture span for already completed CompletionStage"() { + setup: + def future = CompletableFuture.completedFuture("Done") + new TracedWithSpan().completionStage(future) + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completionStage" + kind INTERNAL + hasNoParent() + attributes { + } + } + } + } + } + + def "should capture span for eventually completed CompletionStage"() { + setup: + def future = new CompletableFuture() + new TracedWithSpan().completionStage(future) + + expect: + Thread.sleep(500) // sleep a bit just to make sure no span is captured + assertTraces(0) {} + + future.complete("Done") + + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completionStage" + kind INTERNAL + hasNoParent() + attributes { + } + } + } + } + } + + def "should capture span for already exceptionally completed CompletionStage"() { + setup: + def future = new CompletableFuture() + future.completeExceptionally(new IllegalArgumentException("Boom")) + new TracedWithSpan().completionStage(future) + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completionStage" + kind INTERNAL + hasNoParent() + status ERROR + errorEvent(IllegalArgumentException, "Boom") + attributes { + } + } + } + } + } + + def "should capture span for eventually exceptionally completed CompletionStage"() { + setup: + def future = new CompletableFuture() + new TracedWithSpan().completionStage(future) + + expect: + Thread.sleep(500) // sleep a bit just to make sure no span is captured + assertTraces(0) {} + + future.completeExceptionally(new IllegalArgumentException("Boom")) + + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completionStage" + kind INTERNAL + hasNoParent() + status ERROR + errorEvent(IllegalArgumentException, "Boom") + attributes { + } + } + } + } + } + + def "should capture span for null CompletionStage"() { + setup: + new TracedWithSpan().completionStage(null) + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completionStage" + kind INTERNAL + hasNoParent() + attributes { + } + } + } + } + } + + def "should capture span for already completed CompletableFuture"() { + setup: + def future = CompletableFuture.completedFuture("Done") + new TracedWithSpan().completableFuture(future) + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completableFuture" + kind INTERNAL + hasNoParent() + attributes { + } + } + } + } + } + + def "should capture span for eventually completed CompletableFuture"() { + setup: + def future = new CompletableFuture() + new TracedWithSpan().completableFuture(future) + + expect: + Thread.sleep(500) // sleep a bit just to make sure no span is captured + assertTraces(0) {} + + future.complete("Done") + + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completableFuture" + kind INTERNAL + hasNoParent() + attributes { + } + } + } + } + } + + def "should capture span for already exceptionally completed CompletableFuture"() { + setup: + def future = new CompletableFuture() + future.completeExceptionally(new IllegalArgumentException("Boom")) + new TracedWithSpan().completableFuture(future) + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completableFuture" + kind INTERNAL + hasNoParent() + status ERROR + errorEvent(IllegalArgumentException, "Boom") + attributes { + } + } + } + } + } + + def "should capture span for eventually exceptionally completed CompletableFuture"() { + setup: + def future = new CompletableFuture() + new TracedWithSpan().completableFuture(future) + + expect: + Thread.sleep(500) // sleep a bit just to make sure no span is captured + assertTraces(0) {} + + future.completeExceptionally(new IllegalArgumentException("Boom")) + + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completableFuture" + kind INTERNAL + hasNoParent() + status ERROR + errorEvent(IllegalArgumentException, "Boom") + attributes { + } + } + } + } + } + + def "should capture span for null CompletableFuture"() { + setup: + new TracedWithSpan().completableFuture(null) + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.completableFuture" + kind INTERNAL + hasNoParent() + attributes { + } + } + } + } + } + + def "instrument java6 class"() { + setup: + /* + class GeneratedJava6TestClass implements Runnable { + @WithSpan + public void run() { + runWithSpan("intercept", {}) + } + } + */ + Class generatedClass = new ByteBuddy(ClassFileVersion.JAVA_V6) + .subclass(Object) + .name("GeneratedJava6TestClass") + .implement(Runnable) + .defineMethod("run", void.class, Modifier.PUBLIC).intercept(MethodDelegation.to(new Object() { + @RuntimeType + void intercept(@This Object o) { + runWithSpan("intercept", {}) + } + })) + .visit(new MemberAttributeExtension.ForMethod() + .annotateMethod(AnnotationDescription.Builder.ofType(WithSpan).build()) + .on(ElementMatchers.named("run"))) + .make() + .load(getClass().getClassLoader()) + .getLoaded() + + Runnable runnable = (Runnable) generatedClass.getConstructor().newInstance() + runnable.run() + + expect: + assertTraces(1) { + trace(0, 2) { + span(0) { + name "GeneratedJava6TestClass.run" + kind INTERNAL + hasNoParent() + attributes { + } + } + span(1) { + name "intercept" + kind INTERNAL + childOf(span(0)) + attributes { + } + } + } + } + } + + def "should capture attributes"() { + setup: + new TracedWithSpan().withSpanAttributes("foo", "bar", null, "baz") + + expect: + assertTraces(1) { + trace(0, 1) { + span(0) { + name "TracedWithSpan.withSpanAttributes" + kind INTERNAL + hasNoParent() + attributes { + "implicitName" "foo" + "explicitName" "bar" + } + } + } + } + } +} diff --git a/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java new file mode 100644 index 0000000000..869e407964 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-annotations-1.16/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java @@ -0,0 +1,60 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.test.annotation; + +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.extension.annotations.SpanAttribute; +import io.opentelemetry.extension.annotations.WithSpan; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +public class TracedWithSpan { + + @WithSpan + public String otel() { + return "hello!"; + } + + @WithSpan("manualName") + public String namedOtel() { + return "hello!"; + } + + @WithSpan + public String ignored() { + return "hello!"; + } + + @WithSpan(kind = SpanKind.PRODUCER) + public String someKind() { + return "hello!"; + } + + @WithSpan(kind = SpanKind.SERVER) + public String server() { + return otel(); + } + + @WithSpan + public String withSpanAttributes( + @SpanAttribute String implicitName, + @SpanAttribute("explicitName") String parameter, + @SpanAttribute("nullAttribute") String nullAttribute, + String notTraced) { + + return "hello!"; + } + + @WithSpan + public CompletionStage completionStage(CompletableFuture future) { + return future; + } + + @WithSpan + public CompletableFuture completableFuture(CompletableFuture future) { + return future; + } +} diff --git a/instrumentation/reactor/reactor-3.1/javaagent/build.gradle.kts b/instrumentation/reactor/reactor-3.1/javaagent/build.gradle.kts index 9c5ad446c9..b373235368 100644 --- a/instrumentation/reactor/reactor-3.1/javaagent/build.gradle.kts +++ b/instrumentation/reactor/reactor-3.1/javaagent/build.gradle.kts @@ -29,7 +29,7 @@ dependencies { compileOnly(project(":opentelemetry-api-shaded-for-instrumenting", configuration = "shadow")) testLibrary("io.projectreactor:reactor-test:3.1.0.RELEASE") - testImplementation(project(":instrumentation:opentelemetry-annotations-1.0:testing")) + testImplementation(project(":instrumentation-annotations-support-testing")) testImplementation(project(":instrumentation:reactor:reactor-3.1:testing")) testImplementation("io.opentelemetry:opentelemetry-extension-annotations") diff --git a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/FluxWithSpanTest.java b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/BaseFluxWithSpanTest.java similarity index 82% rename from instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/FluxWithSpanTest.java rename to instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/BaseFluxWithSpanTest.java index 95dbd0e72d..c9b42fcc83 100644 --- a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/FluxWithSpanTest.java +++ b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/BaseFluxWithSpanTest.java @@ -7,8 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.reactor; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.extension.annotations.WithSpan; -import io.opentelemetry.javaagent.instrumentation.otelannotations.AbstractTraced; import io.opentelemetry.javaagent.instrumentation.otelannotations.AbstractWithSpanTest; import org.junit.jupiter.api.Test; import reactor.core.Scannable; @@ -16,12 +14,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.UnicastProcessor; import reactor.test.StepVerifier; -class FluxWithSpanTest extends AbstractWithSpanTest, Flux> { - - @Override - protected AbstractTraced, Flux> newTraced() { - return new Traced(); - } +abstract class BaseFluxWithSpanTest extends AbstractWithSpanTest, Flux> { @Override protected void complete(Flux future, String value) { @@ -65,7 +58,7 @@ class FluxWithSpanTest extends AbstractWithSpanTest, Flux> return Flux.just("Value"); }); - Flux result = new TracedWithSpan().flux(flux); + Flux result = newTracedWithSpan().flux(flux); StepVerifier.create(result).expectNext("Value").verifyComplete(); @@ -92,7 +85,7 @@ class FluxWithSpanTest extends AbstractWithSpanTest, Flux> "parent", () -> { Flux result = - new TracedWithSpan() + newTracedWithSpan() .flux( Flux.defer( () -> { @@ -139,24 +132,5 @@ class FluxWithSpanTest extends AbstractWithSpanTest, Flux> .get(); } - static class Traced extends AbstractTraced, Flux> { - - @Override - @WithSpan - protected Flux completable() { - return UnicastProcessor.create(); - } - - @Override - @WithSpan - protected Flux alreadySucceeded() { - return Flux.just(SUCCESS_VALUE); - } - - @Override - @WithSpan - protected Flux alreadyFailed() { - return Flux.error(FAILURE); - } - } + abstract TracedWithSpan newTracedWithSpan(); } diff --git a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/MonoWithSpanTest.java b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/BaseMonoWithSpanTest.java similarity index 82% rename from instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/MonoWithSpanTest.java rename to instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/BaseMonoWithSpanTest.java index f53bf92514..dc23d9841c 100644 --- a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/MonoWithSpanTest.java +++ b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/BaseMonoWithSpanTest.java @@ -7,8 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.reactor; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.extension.annotations.WithSpan; -import io.opentelemetry.javaagent.instrumentation.otelannotations.AbstractTraced; import io.opentelemetry.javaagent.instrumentation.otelannotations.AbstractWithSpanTest; import org.junit.jupiter.api.Test; import reactor.core.Scannable; @@ -16,12 +14,7 @@ import reactor.core.publisher.Mono; import reactor.core.publisher.UnicastProcessor; import reactor.test.StepVerifier; -class MonoWithSpanTest extends AbstractWithSpanTest, Mono> { - - @Override - protected AbstractTraced, Mono> newTraced() { - return new Traced(); - } +abstract class BaseMonoWithSpanTest extends AbstractWithSpanTest, Mono> { @Override protected void complete(Mono future, String value) { @@ -65,7 +58,7 @@ class MonoWithSpanTest extends AbstractWithSpanTest, Mono> return Mono.just("Value"); }); - Mono result = new TracedWithSpan().outer(mono); + Mono result = newTracedWithSpan().outer(mono); StepVerifier.create(result).expectNext("Value").verifyComplete(); @@ -97,7 +90,7 @@ class MonoWithSpanTest extends AbstractWithSpanTest, Mono> "parent", () -> { Mono result = - new TracedWithSpan() + newTracedWithSpan() .mono( Mono.defer( () -> { @@ -141,25 +134,5 @@ class MonoWithSpanTest extends AbstractWithSpanTest, Mono> .get(); } - static class Traced extends AbstractTraced, Mono> { - - @Override - @WithSpan - protected Mono completable() { - UnicastProcessor source = UnicastProcessor.create(); - return source.singleOrEmpty(); - } - - @Override - @WithSpan - protected Mono alreadySucceeded() { - return Mono.just(SUCCESS_VALUE); - } - - @Override - @WithSpan - protected Mono alreadyFailed() { - return Mono.error(FAILURE); - } - } + abstract TracedWithSpan newTracedWithSpan(); } diff --git a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ContextPropagationOperatorInstrumentationTest.java b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ContextPropagationOperatorInstrumentationTest.java index a8d6341299..757ea59f82 100644 --- a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ContextPropagationOperatorInstrumentationTest.java +++ b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ContextPropagationOperatorInstrumentationTest.java @@ -83,7 +83,9 @@ class ContextPropagationOperatorInstrumentationTest { () -> { Span span = testing.getOpenTelemetry().getTracer("test").spanBuilder("parent").startSpan(); - Mono outer = Mono.defer(() -> new TracedWithSpan().mono(Mono.just("Value"))); + Mono outer = + Mono.defer( + () -> new ExtensionAnnotationsTracedWithSpan().mono(Mono.just("Value"))); return ContextPropagationOperator.runWithContext(outer, Context.current().with(span)) .doFinally(unused -> span.end()); }); @@ -107,7 +109,9 @@ class ContextPropagationOperatorInstrumentationTest { () -> { Span span = testing.getOpenTelemetry().getTracer("test").spanBuilder("parent").startSpan(); - Flux outer = Flux.defer(() -> new TracedWithSpan().flux(Flux.just("Value"))); + Flux outer = + Flux.defer( + () -> new ExtensionAnnotationsTracedWithSpan().flux(Flux.just("Value"))); return ContextPropagationOperator.runWithContext(outer, Context.current().with(span)) .doFinally(unused -> span.end()); }); @@ -137,7 +141,7 @@ class ContextPropagationOperatorInstrumentationTest { unused -> { // usual trick to force this to run under new TracingSubscriber with context // written in the next call - return new TracedWithSpan().mono(Mono.just("Value")); + return new ExtensionAnnotationsTracedWithSpan().mono(Mono.just("Value")); }) .subscriberContext( ctx -> diff --git a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsFluxWithSpanTest.java b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsFluxWithSpanTest.java new file mode 100644 index 0000000000..6407a597ce --- /dev/null +++ b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsFluxWithSpanTest.java @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactor; + +import io.opentelemetry.extension.annotations.WithSpan; +import io.opentelemetry.javaagent.instrumentation.otelannotations.AbstractTraced; +import reactor.core.publisher.Flux; +import reactor.core.publisher.UnicastProcessor; + +class ExtensionAnnotationsFluxWithSpanTest extends BaseFluxWithSpanTest { + + @Override + protected AbstractTraced, Flux> newTraced() { + return new Traced(); + } + + @Override + TracedWithSpan newTracedWithSpan() { + return new ExtensionAnnotationsTracedWithSpan(); + } + + static class Traced extends AbstractTraced, Flux> { + + @Override + @WithSpan + protected Flux completable() { + return UnicastProcessor.create(); + } + + @Override + @WithSpan + protected Flux alreadySucceeded() { + return Flux.just(SUCCESS_VALUE); + } + + @Override + @WithSpan + protected Flux alreadyFailed() { + return Flux.error(FAILURE); + } + } +} diff --git a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsMonoWithSpanTest.java b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsMonoWithSpanTest.java new file mode 100644 index 0000000000..bc7c20d781 --- /dev/null +++ b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsMonoWithSpanTest.java @@ -0,0 +1,46 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactor; + +import io.opentelemetry.extension.annotations.WithSpan; +import io.opentelemetry.javaagent.instrumentation.otelannotations.AbstractTraced; +import reactor.core.publisher.Mono; +import reactor.core.publisher.UnicastProcessor; + +class ExtensionAnnotationsMonoWithSpanTest extends BaseMonoWithSpanTest { + + @Override + protected AbstractTraced, Mono> newTraced() { + return new Traced(); + } + + @Override + TracedWithSpan newTracedWithSpan() { + return new ExtensionAnnotationsTracedWithSpan(); + } + + static class Traced extends AbstractTraced, Mono> { + + @Override + @WithSpan + protected Mono completable() { + UnicastProcessor source = UnicastProcessor.create(); + return source.singleOrEmpty(); + } + + @Override + @WithSpan + protected Mono alreadySucceeded() { + return Mono.just(SUCCESS_VALUE); + } + + @Override + @WithSpan + protected Mono alreadyFailed() { + return Mono.error(FAILURE); + } + } +} diff --git a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsTracedWithSpan.java b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsTracedWithSpan.java new file mode 100644 index 0000000000..a596e9537b --- /dev/null +++ b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/ExtensionAnnotationsTracedWithSpan.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.reactor; + +import io.opentelemetry.extension.annotations.WithSpan; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class ExtensionAnnotationsTracedWithSpan implements TracedWithSpan { + + @Override + @WithSpan("TracedWithSpan.mono") + public Mono mono(Mono mono) { + return mono; + } + + @Override + @WithSpan("TracedWithSpan.outer") + public Mono outer(Mono inner) { + return mono(inner); + } + + @Override + @WithSpan("TracedWithSpan.flux") + public Flux flux(Flux flux) { + return flux; + } +} diff --git a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/TracedWithSpan.java b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/TracedWithSpan.java index d2cfa3eb63..7a1a115aa5 100644 --- a/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/TracedWithSpan.java +++ b/instrumentation/reactor/reactor-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/reactor/TracedWithSpan.java @@ -5,23 +5,13 @@ package io.opentelemetry.javaagent.instrumentation.reactor; -import io.opentelemetry.extension.annotations.WithSpan; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -public class TracedWithSpan { - @WithSpan - public Mono mono(Mono mono) { - return mono; - } +public interface TracedWithSpan { + Mono mono(Mono mono); - @WithSpan - public Mono outer(Mono inner) { - return mono(inner); - } + Mono outer(Mono inner); - @WithSpan - public Flux flux(Flux flux) { - return flux; - } + Flux flux(Flux flux); } diff --git a/instrumentation/reactor/reactor-netty/reactor-netty-1.0/javaagent/build.gradle.kts b/instrumentation/reactor/reactor-netty/reactor-netty-1.0/javaagent/build.gradle.kts index 8ba9063883..c467874050 100644 --- a/instrumentation/reactor/reactor-netty/reactor-netty-1.0/javaagent/build.gradle.kts +++ b/instrumentation/reactor/reactor-netty/reactor-netty-1.0/javaagent/build.gradle.kts @@ -34,7 +34,7 @@ dependencies { testLibrary("io.projectreactor:reactor-test:3.1.0.RELEASE") testImplementation("io.opentelemetry:opentelemetry-extension-annotations") - testInstrumentation(project(":instrumentation:opentelemetry-annotations-1.0:javaagent")) + testInstrumentation(project(":instrumentation:opentelemetry-extension-annotations-1.0:javaagent")) } tasks { diff --git a/javaagent/build.gradle.kts b/javaagent/build.gradle.kts index f791c7c1b8..4e691437ca 100644 --- a/javaagent/build.gradle.kts +++ b/javaagent/build.gradle.kts @@ -64,7 +64,8 @@ dependencies { baseJavaagentLibs(project(":javaagent-tooling")) baseJavaagentLibs(project(":muzzle")) - baseJavaagentLibs(project(":instrumentation:opentelemetry-annotations-1.0:javaagent")) + // TODO (trask) replace with opentelemetry-instrumentation-annotations + baseJavaagentLibs(project(":instrumentation:opentelemetry-extension-annotations-1.0:javaagent")) baseJavaagentLibs(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.0:javaagent")) baseJavaagentLibs(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.4:javaagent")) baseJavaagentLibs(project(":instrumentation:opentelemetry-instrumentation-api:javaagent")) diff --git a/opentelemetry-ext-annotations-shaded-for-instrumenting/build.gradle.kts b/opentelemetry-ext-annotations-shaded-for-instrumenting/build.gradle.kts index 98239bfaba..d0c92d3611 100644 --- a/opentelemetry-ext-annotations-shaded-for-instrumenting/build.gradle.kts +++ b/opentelemetry-ext-annotations-shaded-for-instrumenting/build.gradle.kts @@ -17,6 +17,7 @@ dependencies { // (see more explanation in opentelemetry-api-1.0.gradle) tasks { shadowJar { - relocate("io.opentelemetry", "application.io.opentelemetry") + relocate("io.opentelemetry.extension.annotations", "application.io.opentelemetry.extension.annotations") + relocate("io.opentelemetry.api.trace.SpanKind", "application.io.opentelemetry.api.trace.SpanKind") } } diff --git a/opentelemetry-instrumentation-annotations-shaded-for-instrumenting/build.gradle.kts b/opentelemetry-instrumentation-annotations-shaded-for-instrumenting/build.gradle.kts new file mode 100644 index 0000000000..3dc2911875 --- /dev/null +++ b/opentelemetry-instrumentation-annotations-shaded-for-instrumenting/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + id("com.github.johnrengelman.shadow") + + id("otel.java-conventions") +} + +description = "opentelemetry-instrumentation-annotations shaded for internal javaagent usage" +group = "io.opentelemetry.javaagent" + +dependencies { + implementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations") +} + +// OpenTelemetry Instrumentation Annotations shaded so that it can be used in instrumentation of +// OpenTelemetry Instrumentation Annotations itself, +// and then its usage can be unshaded after OpenTelemetry Instrumentation Annotations is shaded +// (see more explanation in opentelemetry-api-1.0.gradle) +tasks { + shadowJar { + relocate("io.opentelemetry.instrumentation.annotations", "application.io.opentelemetry.instrumentation.annotations") + relocate("io.opentelemetry.api.trace.SpanKind", "application.io.opentelemetry.api.trace.SpanKind") + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index a9bb03847f..23a189777e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -98,6 +98,7 @@ include(":muzzle") // agent projects include(":opentelemetry-api-shaded-for-instrumenting") include(":opentelemetry-ext-annotations-shaded-for-instrumenting") +include(":opentelemetry-instrumentation-annotations-shaded-for-instrumenting") include(":opentelemetry-instrumentation-api-shaded-for-instrumenting") include(":javaagent-bootstrap") include(":javaagent-extension-api") @@ -112,6 +113,7 @@ include(":instrumentation-appender-api-internal") include(":instrumentation-appender-sdk-internal") include(":instrumentation-annotations") include(":instrumentation-annotations-support") +include(":instrumentation-annotations-support-testing") // misc include(":dependencyManagement") @@ -350,11 +352,11 @@ include(":instrumentation:okhttp:okhttp-2.2:javaagent") include(":instrumentation:okhttp:okhttp-3.0:javaagent") include(":instrumentation:okhttp:okhttp-3.0:library") include(":instrumentation:okhttp:okhttp-3.0:testing") -include(":instrumentation:opentelemetry-annotations-1.0:javaagent") -include(":instrumentation:opentelemetry-annotations-1.0:testing") include(":instrumentation:opentelemetry-api:opentelemetry-api-1.0:javaagent") include(":instrumentation:opentelemetry-api:opentelemetry-api-1.4:javaagent") include(":instrumentation:opentelemetry-api:opentelemetry-api-1.10:javaagent") +include(":instrumentation:opentelemetry-extension-annotations-1.0:javaagent") +include(":instrumentation:opentelemetry-instrumentation-annotations-1.16:javaagent") include(":instrumentation:opentelemetry-instrumentation-api:javaagent") include(":instrumentation:opentelemetry-instrumentation-api:testing") include(":instrumentation:oracle-ucp-11.2:javaagent")