Support new annotations (and change of instrumentation name for opentelemetry-annotations) (#6296)

* Support new annotations

* Consistency

* Simplify

* Annotation

* oops
This commit is contained in:
Trask Stalnaker 2022-07-11 14:34:26 -07:00 committed by GitHub
parent 8adebaadca
commit fb784aa877
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1166 additions and 139 deletions

View File

@ -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"))

View File

@ -4,6 +4,4 @@ plugins {
dependencies {
api(project(":testing-common"))
implementation("io.opentelemetry:opentelemetry-extension-annotations")
}

View File

@ -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")
}

View File

@ -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<SettableFuture<String>, ListenableFuture<String>> {
@Override
protected AbstractTraced<SettableFuture<String>, ListenableFuture<String>> newTraced() {
return new Traced();
}
@Override
protected void complete(SettableFuture<String> future, String value) {
future.set(value);
@ -50,26 +43,4 @@ class GuavaWithSpanTest
protected String canceledKey() {
return "guava.canceled";
}
static final class Traced
extends AbstractTraced<SettableFuture<String>, ListenableFuture<String>> {
@Override
@WithSpan
protected SettableFuture<String> completable() {
return SettableFuture.create();
}
@Override
@WithSpan
protected ListenableFuture<String> alreadySucceeded() {
return Futures.immediateFuture("Value");
}
@Override
@WithSpan
protected ListenableFuture<String> alreadyFailed() {
return Futures.immediateFailedFuture(FAILURE);
}
}
}

View File

@ -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<SettableFuture<String>, ListenableFuture<String>> newTraced() {
return new Traced();
}
static final class Traced
extends AbstractTraced<SettableFuture<String>, ListenableFuture<String>> {
@Override
@WithSpan
protected SettableFuture<String> completable() {
return SettableFuture.create();
}
@Override
@WithSpan
protected ListenableFuture<String> alreadySucceeded() {
return Futures.immediateFuture("Value");
}
@Override
@WithSpan
protected ListenableFuture<String> alreadyFailed() {
return Futures.immediateFailedFuture(FAILURE);
}
}
}

View File

@ -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. |

View File

@ -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"))
}

View File

@ -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. |

View File

@ -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;

View File

@ -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<AnnotationSource> annotatedMethodMatcher;
private final ElementMatcher.Junction<MethodDescription> annotatedParametersMatcher;
// this matcher matches all methods that should be excluded from transformation
private final ElementMatcher.Junction<MethodDescription> 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<TypeDescription> typeMatcher() {
return declaresMethod(annotatedMethodMatcher);
}
@Override
public void transform(TypeTransformer transformer) {
ElementMatcher.Junction<MethodDescription> tracedMethods =
annotatedMethodMatcher.and(not(excludedMethodsMatcher));
ElementMatcher.Junction<MethodDescription> tracedMethodsWithParameters =
tracedMethods.and(annotatedParametersMatcher);
ElementMatcher.Junction<MethodDescription> 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<MethodDescription> configureExcludedMethods() {
ElementMatcher.Junction<MethodDescription> result = none();
Map<String, Set<String>> excludedMethods =
MethodsConfigurationParser.parse(
InstrumentationConfig.get().getString(TRACE_ANNOTATED_METHODS_EXCLUDE_CONFIG));
for (Map.Entry<String, Set<String>> entry : excludedMethods.entrySet()) {
String className = entry.getKey();
ElementMatcher.Junction<ByteCodeElement> matcher =
isDeclaredBy(ElementMatchers.named(className));
Set<String> 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<Method, Object> 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<Method, Object> 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<MethodRequest, Object> 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<MethodRequest, Object> operationEndSupport =
AsyncOperationEndSupport.create(
WithSpanSingletons.instrumenterWithAttributes(),
Object.class,
method.getReturnType());
returnValue = operationEndSupport.asyncEnd(context, request, returnValue, throwable);
}
}
}

View File

@ -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

View File

@ -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++) {

View File

@ -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;

View File

@ -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. |

View File

@ -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<String, String> 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]")
}
}

View File

@ -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;
}
}

View File

@ -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<String, Set<String>> entry : excludedMethods.entrySet()) {
String className = entry.getKey();
ElementMatcher.Junction<ByteCodeElement> classMather =
ElementMatcher.Junction<ByteCodeElement> matcher =
isDeclaredBy(ElementMatchers.named(className));
ElementMatcher.Junction<MethodDescription> excludedMethodsMatcher = none();
for (String methodName : entry.getValue()) {
excludedMethodsMatcher = excludedMethodsMatcher.or(ElementMatchers.named(methodName));
Set<String> 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;

View File

@ -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<TypeInstrumentation> typeInstrumentations() {
return singletonList(new WithSpanInstrumentation());
}
}

View File

@ -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<? extends Annotation> spanAttributeAnnotation;
private static final Function<Annotation, String> 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<Annotation, String> resolveSpanAttributeValue(
Class<? extends Annotation> 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;
}
}
}

View File

@ -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<Method, Object> INSTRUMENTER = createInstrumenter();
private static final Instrumenter<MethodRequest, Object> INSTRUMENTER_WITH_ATTRIBUTES =
createInstrumenterWithAttributes();
public static Instrumenter<Method, Object> instrumenter() {
return INSTRUMENTER;
}
public static Instrumenter<MethodRequest, Object> instrumenterWithAttributes() {
return INSTRUMENTER_WITH_ATTRIBUTES;
}
private static Instrumenter<Method, Object> createInstrumenter() {
return Instrumenter.builder(
GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, WithSpanSingletons::spanNameFromMethod)
.newInstrumenter(WithSpanSingletons::spanKindFromMethod);
}
private static Instrumenter<MethodRequest, Object> 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;
}
}

View File

@ -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<String>()
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<String>()
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<String>()
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<String>()
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<String>()
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<String>()
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"
}
}
}
}
}
}

View File

@ -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<String> completionStage(CompletableFuture<String> future) {
return future;
}
@WithSpan
public CompletableFuture<String> completableFuture(CompletableFuture<String> future) {
return future;
}
}

View File

@ -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")

View File

@ -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<String>, Flux<String>> {
@Override
protected AbstractTraced<Flux<String>, Flux<String>> newTraced() {
return new Traced();
}
abstract class BaseFluxWithSpanTest extends AbstractWithSpanTest<Flux<String>, Flux<String>> {
@Override
protected void complete(Flux<String> future, String value) {
@ -65,7 +58,7 @@ class FluxWithSpanTest extends AbstractWithSpanTest<Flux<String>, Flux<String>>
return Flux.just("Value");
});
Flux<String> result = new TracedWithSpan().flux(flux);
Flux<String> result = newTracedWithSpan().flux(flux);
StepVerifier.create(result).expectNext("Value").verifyComplete();
@ -92,7 +85,7 @@ class FluxWithSpanTest extends AbstractWithSpanTest<Flux<String>, Flux<String>>
"parent",
() -> {
Flux<String> result =
new TracedWithSpan()
newTracedWithSpan()
.flux(
Flux.defer(
() -> {
@ -139,24 +132,5 @@ class FluxWithSpanTest extends AbstractWithSpanTest<Flux<String>, Flux<String>>
.get();
}
static class Traced extends AbstractTraced<Flux<String>, Flux<String>> {
@Override
@WithSpan
protected Flux<String> completable() {
return UnicastProcessor.create();
}
@Override
@WithSpan
protected Flux<String> alreadySucceeded() {
return Flux.just(SUCCESS_VALUE);
}
@Override
@WithSpan
protected Flux<String> alreadyFailed() {
return Flux.error(FAILURE);
}
}
abstract TracedWithSpan newTracedWithSpan();
}

View File

@ -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<String>, Mono<String>> {
@Override
protected AbstractTraced<Mono<String>, Mono<String>> newTraced() {
return new Traced();
}
abstract class BaseMonoWithSpanTest extends AbstractWithSpanTest<Mono<String>, Mono<String>> {
@Override
protected void complete(Mono<String> future, String value) {
@ -65,7 +58,7 @@ class MonoWithSpanTest extends AbstractWithSpanTest<Mono<String>, Mono<String>>
return Mono.just("Value");
});
Mono<String> result = new TracedWithSpan().outer(mono);
Mono<String> result = newTracedWithSpan().outer(mono);
StepVerifier.create(result).expectNext("Value").verifyComplete();
@ -97,7 +90,7 @@ class MonoWithSpanTest extends AbstractWithSpanTest<Mono<String>, Mono<String>>
"parent",
() -> {
Mono<String> result =
new TracedWithSpan()
newTracedWithSpan()
.mono(
Mono.defer(
() -> {
@ -141,25 +134,5 @@ class MonoWithSpanTest extends AbstractWithSpanTest<Mono<String>, Mono<String>>
.get();
}
static class Traced extends AbstractTraced<Mono<String>, Mono<String>> {
@Override
@WithSpan
protected Mono<String> completable() {
UnicastProcessor<String> source = UnicastProcessor.create();
return source.singleOrEmpty();
}
@Override
@WithSpan
protected Mono<String> alreadySucceeded() {
return Mono.just(SUCCESS_VALUE);
}
@Override
@WithSpan
protected Mono<String> alreadyFailed() {
return Mono.error(FAILURE);
}
}
abstract TracedWithSpan newTracedWithSpan();
}

View File

@ -83,7 +83,9 @@ class ContextPropagationOperatorInstrumentationTest {
() -> {
Span span =
testing.getOpenTelemetry().getTracer("test").spanBuilder("parent").startSpan();
Mono<String> outer = Mono.defer(() -> new TracedWithSpan().mono(Mono.just("Value")));
Mono<String> 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<String> outer = Flux.defer(() -> new TracedWithSpan().flux(Flux.just("Value")));
Flux<String> 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 ->

View File

@ -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<String>, Flux<String>> newTraced() {
return new Traced();
}
@Override
TracedWithSpan newTracedWithSpan() {
return new ExtensionAnnotationsTracedWithSpan();
}
static class Traced extends AbstractTraced<Flux<String>, Flux<String>> {
@Override
@WithSpan
protected Flux<String> completable() {
return UnicastProcessor.create();
}
@Override
@WithSpan
protected Flux<String> alreadySucceeded() {
return Flux.just(SUCCESS_VALUE);
}
@Override
@WithSpan
protected Flux<String> alreadyFailed() {
return Flux.error(FAILURE);
}
}
}

View File

@ -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<String>, Mono<String>> newTraced() {
return new Traced();
}
@Override
TracedWithSpan newTracedWithSpan() {
return new ExtensionAnnotationsTracedWithSpan();
}
static class Traced extends AbstractTraced<Mono<String>, Mono<String>> {
@Override
@WithSpan
protected Mono<String> completable() {
UnicastProcessor<String> source = UnicastProcessor.create();
return source.singleOrEmpty();
}
@Override
@WithSpan
protected Mono<String> alreadySucceeded() {
return Mono.just(SUCCESS_VALUE);
}
@Override
@WithSpan
protected Mono<String> alreadyFailed() {
return Mono.error(FAILURE);
}
}
}

View File

@ -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<String> mono(Mono<String> mono) {
return mono;
}
@Override
@WithSpan("TracedWithSpan.outer")
public Mono<String> outer(Mono<String> inner) {
return mono(inner);
}
@Override
@WithSpan("TracedWithSpan.flux")
public Flux<String> flux(Flux<String> flux) {
return flux;
}
}

View File

@ -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<String> mono(Mono<String> mono) {
return mono;
}
public interface TracedWithSpan {
Mono<String> mono(Mono<String> mono);
@WithSpan
public Mono<String> outer(Mono<String> inner) {
return mono(inner);
}
Mono<String> outer(Mono<String> inner);
@WithSpan
public Flux<String> flux(Flux<String> flux) {
return flux;
}
Flux<String> flux(Flux<String> flux);
}

View File

@ -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 {

View File

@ -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"))

View File

@ -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")
}
}

View File

@ -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")
}
}

View File

@ -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")