diff --git a/README.md b/README.md index da07f2b7a341..e86131a4c74f 100644 --- a/README.md +++ b/README.md @@ -274,7 +274,7 @@ OpenTelemetry `getTracer` and API directly, configure a `@WithSpan` annotation. Add the trace annotation to your application's code: ```java -import io.opentelemetry.contrib.auto.annotations.WithSpan; +import io.opentelemetry.extensions.auto.annotations.WithSpan; public class MyClass { @WithSpan diff --git a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/MethodsConfigurationParser.java b/agent-bootstrap/src/main/java/io/opentelemetry/auto/config/MethodsConfigurationParser.java similarity index 90% rename from instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/MethodsConfigurationParser.java rename to agent-bootstrap/src/main/java/io/opentelemetry/auto/config/MethodsConfigurationParser.java index fb2076b425cd..14120ae87a23 100644 --- a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/MethodsConfigurationParser.java +++ b/agent-bootstrap/src/main/java/io/opentelemetry/auto/config/MethodsConfigurationParser.java @@ -14,12 +14,11 @@ * limitations under the License. */ -package io.opentelemetry.auto.instrumentation.traceannotation; +package io.opentelemetry.auto.config; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import io.opentelemetry.auto.config.Config; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; import org.slf4j.Logger; @@ -59,7 +58,7 @@ public static Map> parse(String configString) { configString); return Collections.emptyMap(); } else { - Map> toTrace = Maps.newHashMap(); + Map> toTrace = new HashMap<>(); String[] classMethods = configString.split(";", -1); for (String classMethod : classMethods) { if (classMethod.trim().isEmpty()) { @@ -70,7 +69,7 @@ public static Map> parse(String configString) { String method = splitClassMethod[1].trim(); String methodNames = method.substring(0, method.length() - 1); String[] splitMethodNames = methodNames.split(",", -1); - Set trimmedMethodNames = Sets.newHashSetWithExpectedSize(splitMethodNames.length); + Set trimmedMethodNames = new HashSet<>(splitMethodNames.length); for (String methodName : splitMethodNames) { String trimmedMethodName = methodName.trim(); if (!trimmedMethodName.isEmpty()) { diff --git a/instrumentation/annotations/src/test/groovy/io/opentelemetry/auto/instrumentation/traceannotation/MethodsConfigurationParserTest.groovy b/agent-bootstrap/src/test/groovy/io/opentelemetry/auto/config/MethodsConfigurationParserTest.groovy similarity index 96% rename from instrumentation/annotations/src/test/groovy/io/opentelemetry/auto/instrumentation/traceannotation/MethodsConfigurationParserTest.groovy rename to agent-bootstrap/src/test/groovy/io/opentelemetry/auto/config/MethodsConfigurationParserTest.groovy index 7ab4eec296b5..4cd24f4dd5f8 100644 --- a/instrumentation/annotations/src/test/groovy/io/opentelemetry/auto/instrumentation/traceannotation/MethodsConfigurationParserTest.groovy +++ b/agent-bootstrap/src/test/groovy/io/opentelemetry/auto/config/MethodsConfigurationParserTest.groovy @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.opentelemetry.auto.instrumentation.traceannotation +package io.opentelemetry.auto.config import spock.lang.Specification diff --git a/buildSrc/src/main/java/io/opentelemetry/instrumentation/gradle/AutoInstrumentationPlugin.java b/buildSrc/src/main/java/io/opentelemetry/instrumentation/gradle/AutoInstrumentationPlugin.java index e400c4b77916..343610f8e74b 100644 --- a/buildSrc/src/main/java/io/opentelemetry/instrumentation/gradle/AutoInstrumentationPlugin.java +++ b/buildSrc/src/main/java/io/opentelemetry/instrumentation/gradle/AutoInstrumentationPlugin.java @@ -64,7 +64,6 @@ public class AutoInstrumentationPlugin implements Plugin { "io.opentelemetry.internal", // OpenTelemetry API "io.opentelemetry.metrics", // OpenTelemetry API "io.opentelemetry.trace", // OpenTelemetry API - "io.opentelemetry.contrib.auto.annotations", // OpenTelemetry API Contrib "io.grpc.Context", // OpenTelemetry API dependency "io.grpc.Deadline", // OpenTelemetry API dependency "io.grpc.PersistentHashArrayMappedTrie", // OpenTelemetry API dependency diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index f5a14f54f578..dd09e6764888 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -28,22 +28,22 @@ ext { deps = [ // OpenTelemetry - opentelemetryApi : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api', version: versions.opentelemetry), - opentelemetryApiAutoAnnotations: dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-auto-annotations', version: versions.opentelemetryOther), - opentelemetryTraceProps : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-trace-propagators', version: versions.opentelemetryOther), - opentelemetrySdk : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk', version: versions.opentelemetry), - opentelemetrySdkAutoConfig : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-auto-config', version: versions.opentelemetryOther), - opentelemetryJaeger : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-jaeger', version: versions.opentelemetry), - opentelemetryOtlp : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-otlp', version: versions.opentelemetryOther), - opentelemetryZipkin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-zipkin', version: versions.opentelemetryOther), - opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-logging', version: versions.opentelemetryOther), + opentelemetryApi : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api', version: versions.opentelemetry), + opentelemetryAutoAnnotations: dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-auto-annotations', version: versions.opentelemetryOther), + opentelemetryTraceProps : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-trace-propagators', version: versions.opentelemetryOther), + opentelemetrySdk : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk', version: versions.opentelemetry), + opentelemetrySdkAutoConfig : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-auto-config', version: versions.opentelemetryOther), + opentelemetryJaeger : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-jaeger', version: versions.opentelemetry), + opentelemetryOtlp : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-otlp', version: versions.opentelemetryOther), + opentelemetryZipkin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-zipkin', version: versions.opentelemetryOther), + opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporters-logging', version: versions.opentelemetryOther), // General - slf4j : "org.slf4j:slf4j-api:${versions.slf4j}", - guava : "com.google.guava:guava:$versions.guava", - bytebuddy : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy', version: "${versions.bytebuddy}"), - bytebuddyagent : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy-agent', version: "${versions.bytebuddy}"), - autoservice : [ + slf4j : "org.slf4j:slf4j-api:${versions.slf4j}", + guava : "com.google.guava:guava:$versions.guava", + bytebuddy : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy', version: "${versions.bytebuddy}"), + bytebuddyagent : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy-agent', version: "${versions.bytebuddy}"), + autoservice : [ dependencies.create(group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc3'), dependencies.create(group: 'com.google.auto', name: 'auto-common', version: '0.8'), // These are the last versions that support guava 20.0. Upgrading has odd interactions with shadow. @@ -52,23 +52,23 @@ ext { // Testing - spock : [ + spock : [ dependencies.create("org.spockframework:spock-core:${versions.spock}", { exclude group: 'org.codehaus.groovy', module: 'groovy-all' }), // Used by Spock for mocking: dependencies.create(group: 'org.objenesis', name: 'objenesis', version: '2.6') // Last version to support Java7 ], - groovy : "org.codehaus.groovy:groovy-all:${versions.groovy}", - testcontainers : "org.testcontainers:testcontainers:1.12.2", - testLogging : [ + groovy : "org.codehaus.groovy:groovy-all:${versions.groovy}", + testcontainers : "org.testcontainers:testcontainers:1.12.2", + testLogging : [ dependencies.create(group: 'ch.qos.logback', name: 'logback-classic', version: versions.logback), dependencies.create(group: 'org.slf4j', name: 'log4j-over-slf4j', version: versions.slf4j), dependencies.create(group: 'org.slf4j', name: 'jcl-over-slf4j', version: versions.slf4j), dependencies.create(group: 'org.slf4j', name: 'jul-to-slf4j', version: versions.slf4j), ], - scala : dependencies.create(group: 'org.scala-lang', name: 'scala-library', version: "${versions.scala}"), - kotlin : dependencies.create(group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "${versions.kotlin}"), - coroutines : dependencies.create(group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: "${versions.coroutines}"), + scala : dependencies.create(group: 'org.scala-lang', name: 'scala-library', version: "${versions.scala}"), + kotlin : dependencies.create(group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "${versions.kotlin}"), + coroutines : dependencies.create(group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: "${versions.coroutines}"), ] } diff --git a/instrumentation-core/spring/spring-boot-autoconfigure/spring-boot-autoconfigure.gradle b/instrumentation-core/spring/spring-boot-autoconfigure/spring-boot-autoconfigure.gradle index 7e1566011f7b..d291d9ef1fb7 100644 --- a/instrumentation-core/spring/spring-boot-autoconfigure/spring-boot-autoconfigure.gradle +++ b/instrumentation-core/spring/spring-boot-autoconfigure/spring-boot-autoconfigure.gradle @@ -13,15 +13,15 @@ dependencies { implementation group: 'org.springframework.boot', name: 'spring-boot-autoconfigure', version: versions.springboot annotationProcessor group: 'org.springframework.boot', name: 'spring-boot-autoconfigure-processor', version: versions.springboot implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' - + compileOnly group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: versions.springboot compileOnly group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: versions.springboot compileOnly group: 'org.springframework.boot', name: 'spring-boot-starter-webflux', version: versions.springboot - implementation project(':instrumentation-core:spring:spring-webmvc-3.1') + implementation project(':instrumentation-core:spring:spring-webmvc-3.1') implementation project(':instrumentation-core:spring:spring-web-3.1') implementation project(':instrumentation-core:spring:spring-webflux-5.0') - - compileOnly deps.opentelemetryApiAutoAnnotations + + compileOnly deps.opentelemetryAutoAnnotations compileOnly group: 'io.grpc', name: 'grpc-api', version: '1.30.2' compileOnly deps.opentelemetryLogging compileOnly deps.opentelemetryJaeger @@ -34,9 +34,9 @@ dependencies { testImplementation(group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: versions.springboot) { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } - + testImplementation deps.opentelemetrySdk - testImplementation deps.opentelemetryApiAutoAnnotations + testImplementation deps.opentelemetryAutoAnnotations testImplementation group: 'io.grpc', name: 'grpc-api', version: '1.30.2' testImplementation group: 'io.grpc', name: 'grpc-netty-shaded', version: '1.30.2' testImplementation deps.opentelemetryLogging diff --git a/instrumentation-core/spring/starters/spring-starter/spring-starter.gradle b/instrumentation-core/spring/starters/spring-starter/spring-starter.gradle index 72b21a1bdea1..b6f83ce8b4db 100644 --- a/instrumentation-core/spring/starters/spring-starter/spring-starter.gradle +++ b/instrumentation-core/spring/starters/spring-starter/spring-starter.gradle @@ -9,11 +9,11 @@ apply from: "$rootDir/gradle/publish.gradle" sourceCompatibility = '8' -dependencies { +dependencies { api group: "org.springframework.boot", name: "spring-boot-starter", version: versions.springboot api group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: versions.springboot api project(':instrumentation-core:spring:spring-boot-autoconfigure') - api deps.opentelemetryApiAutoAnnotations + api deps.opentelemetryAutoAnnotations api deps.opentelemetryApi api deps.opentelemetryLogging api deps.opentelemetrySdk diff --git a/instrumentation/annotations/annotations.gradle b/instrumentation/annotations/annotations.gradle index ed0f98f01125..05cad5aebfa6 100644 --- a/instrumentation/annotations/annotations.gradle +++ b/instrumentation/annotations/annotations.gradle @@ -10,8 +10,6 @@ muzzle { } dependencies { - implementation deps.opentelemetryApiAutoAnnotations - testImplementation group: 'com.newrelic.agent.java', name: 'newrelic-api', version: '+' testImplementation(group: 'io.opentracing.contrib.dropwizard', name: 'dropwizard-opentracing', version: '0.2.2') { transitive = false diff --git a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/AbstractTraceAnnotationInstrumentation.java b/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/AbstractTraceAnnotationInstrumentation.java index 6bfa6e86244e..848a34b41b3b 100644 --- a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/AbstractTraceAnnotationInstrumentation.java +++ b/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/AbstractTraceAnnotationInstrumentation.java @@ -20,6 +20,7 @@ import static net.bytebuddy.matcher.ElementMatchers.none; import io.opentelemetry.auto.config.Config; +import io.opentelemetry.auto.config.MethodsConfigurationParser; import io.opentelemetry.auto.tooling.Instrumenter; import java.util.Map; import java.util.Set; diff --git a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/TraceConfigInstrumentation.java b/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/TraceConfigInstrumentation.java index 88780ecab81f..e7e92a24aacb 100644 --- a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/TraceConfigInstrumentation.java +++ b/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/TraceConfigInstrumentation.java @@ -22,6 +22,7 @@ import com.google.auto.service.AutoService; import io.opentelemetry.auto.config.Config; +import io.opentelemetry.auto.config.MethodsConfigurationParser; import io.opentelemetry.auto.tooling.Instrumenter; import java.util.Collections; import java.util.Map; diff --git a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/TraceDecorator.java b/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/TraceDecorator.java index 29677e23d47a..b483f754554e 100644 --- a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/TraceDecorator.java +++ b/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/TraceDecorator.java @@ -18,35 +18,11 @@ import io.opentelemetry.OpenTelemetry; import io.opentelemetry.auto.bootstrap.instrumentation.decorator.BaseDecorator; -import io.opentelemetry.extensions.auto.annotations.WithSpan; -import io.opentelemetry.trace.Span; -import io.opentelemetry.trace.Span.Kind; import io.opentelemetry.trace.Tracer; -import java.lang.reflect.Method; public class TraceDecorator extends BaseDecorator { public static final TraceDecorator DECORATE = new TraceDecorator(); public static final Tracer TRACER = OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto.trace-annotation"); - - /** - * This method is used to generate an acceptable span (operation) name based on a given method - * reference. It first checks for existence of {@link WithSpan} annotation. If it is present, then - * tries to derive name from its {@code value} attribute. Otherwise delegates to {@link - * #spanNameForMethod(Method)}. - */ - public String spanNameForMethodWithAnnotation(final Method method) { - WithSpan annotation = method.getAnnotation(WithSpan.class); - if (annotation != null && !annotation.value().isEmpty()) { - return annotation.value(); - } - - return spanNameForMethod(method); - } - - public Span.Kind extractSpanKind(final Method method) { - WithSpan annotation = method.getAnnotation(WithSpan.class); - return annotation != null ? annotation.kind() : Kind.INTERNAL; - } } diff --git a/instrumentation/opentelemetry-api-beta/opentelemetry-api-beta.gradle b/instrumentation/opentelemetry-api-beta/opentelemetry-api-beta.gradle index 327abb97fa38..eb14ef89242f 100644 --- a/instrumentation/opentelemetry-api-beta/opentelemetry-api-beta.gradle +++ b/instrumentation/opentelemetry-api-beta/opentelemetry-api-beta.gradle @@ -20,8 +20,10 @@ dependencies { // and in the code "io.opentelemetry.*" refers to the (shaded) OpenTelemetry API that is in the // bootstrap class loader (as those references will later be shaded) compileOnly project(path: ':opentelemetry-api-beta-shaded-for-instrumenting', configuration: 'shadow') + compileOnly project(path: ':opentelemetry-auto-annotations-beta-shaded-for-instrumenting', configuration: 'shadow') // using OpenTelemetry SDK to make sure that instrumentation doesn't cause // OpenTelemetrySdk.getTracerProvider() to throw ClassCastException testImplementation project(path: ':opentelemetry-sdk-beta-shaded-for-instrumenting', configuration: 'shadow') + testImplementation project(path: ':opentelemetry-auto-annotations-beta-shaded-for-instrumenting', configuration: 'shadow') } diff --git a/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/AbstractTraceAnnotationInstrumentation.java b/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/AbstractTraceAnnotationInstrumentation.java new file mode 100644 index 000000000000..ad1bf908f097 --- /dev/null +++ b/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/AbstractTraceAnnotationInstrumentation.java @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opentelemetry.auto.instrumentation.opentelemetryapi.anotations; + +import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; +import static net.bytebuddy.matcher.ElementMatchers.none; + +import io.opentelemetry.auto.config.Config; +import io.opentelemetry.auto.config.MethodsConfigurationParser; +import io.opentelemetry.auto.tooling.Instrumenter; +import java.util.Map; +import java.util.Set; +import net.bytebuddy.description.ByteCodeElement; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +public abstract class AbstractTraceAnnotationInstrumentation extends Instrumenter.Default { + public AbstractTraceAnnotationInstrumentation( + String instrumentationName, String... additionalNames) { + super(instrumentationName, additionalNames); + } + + /* + Returns a matcher for all methods that should be excluded from auto-instrumentation by + annotation-based advices. + */ + ElementMatcher.Junction configureExcludedMethods() { + ElementMatcher.Junction result = none(); + + Map> excludedMethods = + MethodsConfigurationParser.parse(Config.get().getTraceAnnotatedMethodsExclude()); + for (Map.Entry> entry : excludedMethods.entrySet()) { + String className = entry.getKey(); + ElementMatcher.Junction classMather = + isDeclaredBy(ElementMatchers.named(className)); + + ElementMatcher.Junction excludedMethodsMatcher = none(); + for (String methodName : entry.getValue()) { + excludedMethodsMatcher = excludedMethodsMatcher.or(ElementMatchers.named(methodName)); + } + + result = result.or(classMather.and(excludedMethodsMatcher)); + } + + return result; + } +} diff --git a/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/TraceDecorator.java b/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/TraceDecorator.java new file mode 100644 index 000000000000..f59027f81b12 --- /dev/null +++ b/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/TraceDecorator.java @@ -0,0 +1,64 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opentelemetry.auto.instrumentation.opentelemetryapi.anotations; + +import io.opentelemetry.OpenTelemetry; +import io.opentelemetry.auto.bootstrap.instrumentation.decorator.BaseDecorator; +import io.opentelemetry.trace.Span; +import io.opentelemetry.trace.Tracer; +import java.lang.reflect.Method; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import unshaded.io.opentelemetry.extensions.auto.annotations.WithSpan; +import unshaded.io.opentelemetry.trace.Span.Kind; + +public class TraceDecorator extends BaseDecorator { + public static final TraceDecorator DECORATE = new TraceDecorator(); + + public static final Tracer TRACER = + OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto.trace-annotation"); + + private static final Logger log = LoggerFactory.getLogger(TraceDecorator.class); + + /** + * This method is used to generate an acceptable span (operation) name based on a given method + * reference. It first checks for existence of {@link WithSpan} annotation. If it is present, then + * tries to derive name from its {@code value} attribute. Otherwise delegates to {@link + * #spanNameForMethod(Method)}. + */ + public String spanNameForMethodWithAnnotation(WithSpan annotation, Method method) { + if (annotation != null && !annotation.value().isEmpty()) { + return annotation.value(); + } + return spanNameForMethod(method); + } + + public Span.Kind extractSpanKind(WithSpan annotation) { + Kind unshadedKind = annotation != null ? annotation.kind() : Kind.INTERNAL; + return toShadedOrNull(unshadedKind); + } + + public static io.opentelemetry.trace.Span.Kind toShadedOrNull( + final unshaded.io.opentelemetry.trace.Span.Kind unshadedSpanKind) { + try { + return io.opentelemetry.trace.Span.Kind.valueOf(unshadedSpanKind.name()); + } catch (final IllegalArgumentException e) { + log.debug("unexpected span kind: {}", unshadedSpanKind.name()); + return io.opentelemetry.trace.Span.Kind.INTERNAL; + } + } +} diff --git a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/WithSpanAdvice.java b/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/WithSpanAdvice.java similarity index 77% rename from instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/WithSpanAdvice.java rename to instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/WithSpanAdvice.java index 0b51be6d8460..a447a7209f81 100644 --- a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/WithSpanAdvice.java +++ b/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/WithSpanAdvice.java @@ -14,16 +14,17 @@ * limitations under the License. */ -package io.opentelemetry.auto.instrumentation.traceannotation; +package io.opentelemetry.auto.instrumentation.opentelemetryapi.anotations; -import static io.opentelemetry.auto.instrumentation.traceannotation.TraceDecorator.DECORATE; -import static io.opentelemetry.auto.instrumentation.traceannotation.TraceDecorator.TRACER; +import static io.opentelemetry.auto.instrumentation.opentelemetryapi.anotations.TraceDecorator.DECORATE; +import static io.opentelemetry.auto.instrumentation.opentelemetryapi.anotations.TraceDecorator.TRACER; import static io.opentelemetry.trace.TracingContextUtils.currentContextWith; import io.opentelemetry.auto.instrumentation.api.SpanWithScope; import io.opentelemetry.trace.Span; import java.lang.reflect.Method; import net.bytebuddy.asm.Advice; +import unshaded.io.opentelemetry.extensions.auto.annotations.WithSpan; /** * Instrumentation for methods annotated with {@link @@ -35,10 +36,12 @@ public class WithSpanAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static SpanWithScope onEnter(@Advice.Origin final Method method) { + WithSpan annotation = method.getAnnotation(WithSpan.class); + Span span = TRACER - .spanBuilder(DECORATE.spanNameForMethodWithAnnotation(method)) - .setSpanKind(DECORATE.extractSpanKind(method)) + .spanBuilder(DECORATE.spanNameForMethodWithAnnotation(annotation, method)) + .setSpanKind(DECORATE.extractSpanKind(annotation)) .startSpan(); DECORATE.afterStart(span); return new SpanWithScope(span, currentContextWith(span)); diff --git a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/WithSpanAnnotationInstrumentation.java b/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/WithSpanAnnotationInstrumentation.java similarity index 85% rename from instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/WithSpanAnnotationInstrumentation.java rename to instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/WithSpanAnnotationInstrumentation.java index 147c2f81f3a8..7ef5aa0240d5 100644 --- a/instrumentation/annotations/src/main/java/io/opentelemetry/auto/instrumentation/traceannotation/WithSpanAnnotationInstrumentation.java +++ b/instrumentation/opentelemetry-api-beta/src/main/java/io/opentelemetry/auto/instrumentation/opentelemetryapi/anotations/WithSpanAnnotationInstrumentation.java @@ -14,16 +14,16 @@ * limitations under the License. */ -package io.opentelemetry.auto.instrumentation.traceannotation; +package io.opentelemetry.auto.instrumentation.opentelemetryapi.anotations; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import io.opentelemetry.auto.tooling.Instrumenter; -import io.opentelemetry.extensions.auto.annotations.WithSpan; import java.util.Map; import net.bytebuddy.description.annotation.AnnotationSource; import net.bytebuddy.description.method.MethodDescription; @@ -32,9 +32,7 @@ /** * Instrumentation for methods annotated with {@link - * io.opentelemetry.extensions.auto.annotations.WithSpan} annotation. As that is Otel annotation, we - * provide full support for all its attributes, as opposed to bare minimum functionality of {@link - * TraceAnnotationsInstrumentation} for third party annotations. + * io.opentelemetry.extensions.auto.annotations.WithSpan} annotation. */ @AutoService(Instrumenter.class) public final class WithSpanAnnotationInstrumentation @@ -48,7 +46,8 @@ public final class WithSpanAnnotationInstrumentation public WithSpanAnnotationInstrumentation() { super("trace", "with-span-annotation"); - annotatedMethodMatcher = isAnnotatedWith(WithSpan.class); + annotatedMethodMatcher = + isAnnotatedWith(named("unshaded.io.opentelemetry.extensions.auto.annotations.WithSpan")); excludedMethodsMatcher = configureExcludedMethods(); } diff --git a/instrumentation/annotations/src/test/groovy/WithSpanInstrumentationTest.groovy b/instrumentation/opentelemetry-api-beta/src/test/groovy/WithSpanInstrumentationTest.groovy similarity index 100% rename from instrumentation/annotations/src/test/groovy/WithSpanInstrumentationTest.groovy rename to instrumentation/opentelemetry-api-beta/src/test/groovy/WithSpanInstrumentationTest.groovy diff --git a/instrumentation/annotations/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java b/instrumentation/opentelemetry-api-beta/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java similarity index 92% rename from instrumentation/annotations/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java rename to instrumentation/opentelemetry-api-beta/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java index dff76e5c5999..e3ea0b2aec19 100644 --- a/instrumentation/annotations/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java +++ b/instrumentation/opentelemetry-api-beta/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java @@ -17,9 +17,9 @@ package io.opentelemetry.test.annotation; import io.opentelemetry.OpenTelemetry; -import io.opentelemetry.extensions.auto.annotations.WithSpan; -import io.opentelemetry.trace.Span.Kind; import io.opentelemetry.trace.Tracer; +import unshaded.io.opentelemetry.extensions.auto.annotations.WithSpan; +import unshaded.io.opentelemetry.trace.Span.Kind; public class TracedWithSpan { diff --git a/opentelemetry-auto-annotations-beta-shaded-for-instrumenting/opentelemetry-auto-annotations-beta-shaded-for-instrumenting.gradle b/opentelemetry-auto-annotations-beta-shaded-for-instrumenting/opentelemetry-auto-annotations-beta-shaded-for-instrumenting.gradle new file mode 100644 index 000000000000..24396419c97c --- /dev/null +++ b/opentelemetry-auto-annotations-beta-shaded-for-instrumenting/opentelemetry-auto-annotations-beta-shaded-for-instrumenting.gradle @@ -0,0 +1,17 @@ +plugins { + id "com.github.johnrengelman.shadow" +} + +apply from: "$rootDir/gradle/java.gradle" + +dependencies { + implementation deps.opentelemetryAutoAnnotations +} + +// OpenTelemetry Auto Annotations shaded so that it can be used in opentelemetry-api-beta +// instrumentation, and then its usage can be unshaded after OpenTelemetry API is shaded +// (see more explanation in opentelemetry-api-beta.gradle) +shadowJar { + + relocate "io.opentelemetry", "unshaded.io.opentelemetry" +} diff --git a/opentelemetry-javaagent/opentelemetry-javaagent.gradle b/opentelemetry-javaagent/opentelemetry-javaagent.gradle index 7c232d634209..a2defd180d1e 100644 --- a/opentelemetry-javaagent/opentelemetry-javaagent.gradle +++ b/opentelemetry-javaagent/opentelemetry-javaagent.gradle @@ -85,7 +85,6 @@ tasks.withType(ShadowJar).configureEach { relocate "io.opentelemetry.internal", "io.opentelemetry.auto.shaded.io.opentelemetry.internal" relocate "io.opentelemetry.metrics", "io.opentelemetry.auto.shaded.io.opentelemetry.metrics" relocate "io.opentelemetry.trace", "io.opentelemetry.auto.shaded.io.opentelemetry.trace" - relocate "io.opentelemetry.contrib.auto.annotations", "io.opentelemetry.auto.shaded.io.opentelemetry.contrib.auto.annotations" // relocate OpenTelemetry API dependency relocate "io.grpc", "io.opentelemetry.auto.shaded.io.grpc" diff --git a/settings.gradle b/settings.gradle index bb5817927294..95745ce20b82 100644 --- a/settings.gradle +++ b/settings.gradle @@ -22,6 +22,7 @@ rootProject.name = 'opentelemetry-java-instrumentation' include ':opentelemetry-javaagent' include ':opentelemetry-sdk-shaded-for-testing' include ':opentelemetry-api-beta-shaded-for-instrumenting' +include ':opentelemetry-auto-annotations-beta-shaded-for-instrumenting' include ':opentelemetry-sdk-beta-shaded-for-instrumenting' include ':agent-bootstrap' include ':agent-tooling' diff --git a/smoke-tests/springboot/springboot.gradle b/smoke-tests/springboot/springboot.gradle index be8581cff706..9b31398dc0c0 100644 --- a/smoke-tests/springboot/springboot.gradle +++ b/smoke-tests/springboot/springboot.gradle @@ -16,6 +16,7 @@ jar { dependencies { implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.18.RELEASE' + implementation deps.opentelemetryAutoAnnotations testImplementation project(':smoke-tests') } diff --git a/smoke-tests/springboot/src/main/java/io/opentelemetry/smoketest/springboot/controller/WebController.java b/smoke-tests/springboot/src/main/java/io/opentelemetry/smoketest/springboot/controller/WebController.java index 2c8f521f7532..3041376a801e 100644 --- a/smoke-tests/springboot/src/main/java/io/opentelemetry/smoketest/springboot/controller/WebController.java +++ b/smoke-tests/springboot/src/main/java/io/opentelemetry/smoketest/springboot/controller/WebController.java @@ -16,6 +16,7 @@ package io.opentelemetry.smoketest.springboot.controller; +import io.opentelemetry.extensions.auto.annotations.WithSpan; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -23,6 +24,11 @@ public class WebController { @RequestMapping("/greeting") public String greeting() { - return "Sup Dawg"; + return withSpan(); + } + + @WithSpan + public String withSpan() { + return "Hi!"; } } diff --git a/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeTest.groovy b/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeTest.groovy index 6abdddd6b5ed..137efefc78ec 100644 --- a/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeTest.groovy +++ b/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeTest.groovy @@ -20,8 +20,9 @@ import okhttp3.Request class SpringBootSmokeTest extends AbstractServerSmokeTest { - static final HANDLER_SPAN = "LOGGED_SPAN WebController.greeting" static final SERVLET_SPAN = "LOGGED_SPAN /greeting" + static final HANDLER_SPAN = "LOGGED_SPAN WebController.greeting" + static final WITH_SPAN = "LOGGED_SPAN WebController.withSpan" @Override ProcessBuilder createProcessBuilder() { @@ -38,8 +39,9 @@ class SpringBootSmokeTest extends AbstractServerSmokeTest { def "default home page #n th time"() { setup: def spanCounter = new SpanCounter(logfile, [ - (HANDLER_SPAN): 1, (SERVLET_SPAN): 1, + (HANDLER_SPAN): 1, + (WITH_SPAN) : 1 ], 10000) String url = "http://localhost:${httpPort}/greeting" def request = new Request.Builder().url(url).get().build() @@ -51,11 +53,12 @@ class SpringBootSmokeTest extends AbstractServerSmokeTest { then: def responseBodyStr = response.body().string() responseBodyStr != null - responseBodyStr.contains("Sup Dawg") + responseBodyStr.contains("Hi!") response.body().contentType().toString().contains("text/plain") response.code() == 200 - spans[HANDLER_SPAN] == 1 spans[SERVLET_SPAN] == 1 + spans[HANDLER_SPAN] == 1 + spans[WITH_SPAN] == 1 where: n << (1..200) diff --git a/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeWithEmbeddedExporterTest.groovy b/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeWithEmbeddedExporterTest.groovy index 00f446705483..796520357f68 100644 --- a/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeWithEmbeddedExporterTest.groovy +++ b/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeWithEmbeddedExporterTest.groovy @@ -25,8 +25,9 @@ import okhttp3.Request */ class SpringBootSmokeWithEmbeddedExporterTest extends AbstractServerSmokeTest { - static final HANDLER_SPAN = "LOGGED_SPAN WebController.greeting" static final SERVLET_SPAN = "LOGGED_SPAN /greeting" + static final HANDLER_SPAN = "LOGGED_SPAN WebController.greeting" + static final WITH_SPAN = "LOGGED_SPAN WebController.withSpan" @Override ProcessBuilder createProcessBuilder() { @@ -43,8 +44,9 @@ class SpringBootSmokeWithEmbeddedExporterTest extends AbstractServerSmokeTest { def "can monitor default home page"() { setup: def spanCounter = new SpanCounter(logfile, [ - (HANDLER_SPAN): 1, (SERVLET_SPAN): 1, + (HANDLER_SPAN): 1, + (WITH_SPAN) : 1 ], 10000) String url = "http://localhost:${httpPort}/greeting" def request = new Request.Builder().url(url).get().build() @@ -56,10 +58,11 @@ class SpringBootSmokeWithEmbeddedExporterTest extends AbstractServerSmokeTest { then: def responseBodyStr = response.body().string() responseBodyStr != null - responseBodyStr.contains("Sup Dawg") + responseBodyStr.contains("Hi!") response.body().contentType().toString().contains("text/plain") response.code() == 200 - spans[HANDLER_SPAN] == 1 spans[SERVLET_SPAN] == 1 + spans[HANDLER_SPAN] == 1 + spans[WITH_SPAN] == 1 } } diff --git a/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootWithSamplingSmokeTest.groovy b/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootWithSamplingSmokeTest.groovy index 6b71ffe50ece..b8bc762532e7 100644 --- a/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootWithSamplingSmokeTest.groovy +++ b/smoke-tests/springboot/src/test/groovy/io/opentelemetry/smoketest/SpringBootWithSamplingSmokeTest.groovy @@ -20,8 +20,10 @@ import okhttp3.Request class SpringBootWithSamplingSmokeTest extends AbstractServerSmokeTest { - static final HANDLER_SPAN = "LOGGED_SPAN WebController.greeting" static final SERVLET_SPAN = "LOGGED_SPAN /greeting" + static final HANDLER_SPAN = "LOGGED_SPAN WebController.greeting" + static final WITH_SPAN = "LOGGED_SPAN WebController.withSpan" + static final double SAMPLER_PROBABILITY = 0.2 static final int NUM_TRIES = 1000 static final int ALLOWED_DEVIATION = 0.1 * NUM_TRIES @@ -44,20 +46,22 @@ class SpringBootWithSamplingSmokeTest extends AbstractServerSmokeTest { // since sampling is enabled, not really expecting to receive NUM_TRIES spans, // instead giving it 10 seconds and then checking below how many spans were received def spanCounter = new SpanCounter(logfile, [ - (HANDLER_SPAN): NUM_TRIES, (SERVLET_SPAN): NUM_TRIES, + (HANDLER_SPAN): NUM_TRIES, + (WITH_SPAN) : NUM_TRIES ], 10000) String url = "http://localhost:${httpPort}/greeting" def request = new Request.Builder().url(url).get().build() when: - for (int i = 1; i<=NUM_TRIES; i++) { + for (int i = 1; i <= NUM_TRIES; i++) { client.newCall(request).execute() } def spans = spanCounter.countSpans() then: - Math.abs(spans[HANDLER_SPAN] - (SAMPLER_PROBABILITY * NUM_TRIES)) <= ALLOWED_DEVIATION Math.abs(spans[SERVLET_SPAN] - (SAMPLER_PROBABILITY * NUM_TRIES)) <= ALLOWED_DEVIATION + Math.abs(spans[HANDLER_SPAN] - (SAMPLER_PROBABILITY * NUM_TRIES)) <= ALLOWED_DEVIATION + Math.abs(spans[WITH_SPAN] - (SAMPLER_PROBABILITY * NUM_TRIES)) <= ALLOWED_DEVIATION } } diff --git a/testing-common/src/main/groovy/io/opentelemetry/auto/test/SpockRunner.java b/testing-common/src/main/groovy/io/opentelemetry/auto/test/SpockRunner.java index 0e0733dff991..e5430c42aa06 100644 --- a/testing-common/src/main/groovy/io/opentelemetry/auto/test/SpockRunner.java +++ b/testing-common/src/main/groovy/io/opentelemetry/auto/test/SpockRunner.java @@ -62,7 +62,6 @@ public class SpockRunner extends Sputnik { "io.opentelemetry.internal", // OpenTelemetry API "io.opentelemetry.metrics", // OpenTelemetry API "io.opentelemetry.trace", // OpenTelemetry API - "io.opentelemetry.contrib.auto.annotations", // OpenTelemetry API Contrib "io.grpc.Context", // OpenTelemetry API dependency "io.grpc.Deadline", // OpenTelemetry API dependency "io.grpc.PersistentHashArrayMappedTrie", // OpenTelemetry API dependency diff --git a/testing-common/testing-common.gradle b/testing-common/testing-common.gradle index 138d647e4501..718cc0d04b6e 100644 --- a/testing-common/testing-common.gradle +++ b/testing-common/testing-common.gradle @@ -46,7 +46,7 @@ dependencies { api deps.groovy - testImplementation deps.opentelemetryApiAutoAnnotations + testImplementation deps.opentelemetryAutoAnnotations testImplementation project(':instrumentation:annotations') testImplementation group: 'cglib', name: 'cglib', version: '3.2.5'