From 7e007e8f3232ef07fd654f448f67059a03f809e0 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 9 Aug 2021 21:59:48 -0700 Subject: [PATCH] Update jaxrs-common to Instrumenter API (#3796) --- .../javaagent/build.gradle.kts | 5 +- .../jaxrs/v2_0/AsyncResponseData.java | 21 ++++ .../v2_0/CompletionStageFinishCallback.java | 12 +-- ...ContainerRequestFilterInstrumentation.java | 2 +- .../DefaultRequestContextInstrumentation.java | 57 ++++++++--- ...nnotationsTracer.java => HandlerData.java} | 97 +++---------------- ...a => JaxrsAnnotationsInstrumentation.java} | 50 ++++++---- ...=> JaxrsAsyncResponseInstrumentation.java} | 41 ++++---- .../v2_0/JaxrsCodeAttributesExtractor.java | 31 ++++++ ...e.java => JaxrsInstrumentationModule.java} | 8 +- ...{JaxRsPathUtil.java => JaxrsPathUtil.java} | 4 +- .../jaxrs/v2_0/JaxrsServerSpanNaming.java | 32 ++++++ .../jaxrs/v2_0/JaxrsSingletons.java | 43 ++++++++ .../jaxrs/v2_0/RequestContextHelper.java | 55 +++++------ .../CxfRequestContextInstrumentation.java | 48 +++++---- .../jaxrs/v2_0/CxfTracingUtil.java | 2 +- .../CxfAnnotationInstrumentationTest.groovy | 2 +- .../JerseyRequestContextInstrumentation.java | 35 ++++--- .../jaxrs/v2_0/JerseyTracingUtil.java | 2 +- ...JerseyAnnotationInstrumentationTest.groovy | 2 +- ...steasy30RequestContextInstrumentation.java | 33 ++++--- ...steasyAnnotationInstrumentationTest.groovy | 2 +- ...steasy31RequestContextInstrumentation.java | 33 ++++--- ...steasyAnnotationInstrumentationTest.groovy | 2 +- .../ResteasyRootNodeTypeInstrumentation.java | 2 +- ...axrsAnnotationsInstrumentationTest.groovy} | 26 +---- 26 files changed, 380 insertions(+), 267 deletions(-) create mode 100644 instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/AsyncResponseData.java rename instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/{JaxRsAnnotationsTracer.java => HandlerData.java} (52%) rename instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/{JaxRsAnnotationsInstrumentation.java => JaxrsAnnotationsInstrumentation.java} (76%) rename instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/{JaxRsAsyncResponseInstrumentation.java => JaxrsAsyncResponseInstrumentation.java} (69%) create mode 100644 instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsCodeAttributesExtractor.java rename instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/{JaxRsInstrumentationModule.java => JaxrsInstrumentationModule.java} (83%) rename instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/{JaxRsPathUtil.java => JaxrsPathUtil.java} (89%) create mode 100644 instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsServerSpanNaming.java create mode 100644 instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsSingletons.java rename instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-testing/src/main/groovy/{JaxRsAnnotationsInstrumentationTest.groovy => JaxrsAnnotationsInstrumentationTest.groovy} (85%) diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/build.gradle.kts b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/build.gradle.kts index cebbf54d23..7ad7e1d7c0 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/build.gradle.kts +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/build.gradle.kts @@ -19,4 +19,7 @@ dependencies { compileOnly(project(":instrumentation:jaxrs:bootstrap")) compileOnly("javax.ws.rs:javax.ws.rs-api:2.0") -} \ No newline at end of file + + compileOnly("com.google.auto.value:auto-value-annotations") + annotationProcessor("com.google.auto.value:auto-value") +} diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/AsyncResponseData.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/AsyncResponseData.java new file mode 100644 index 0000000000..0f330b5f2f --- /dev/null +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/AsyncResponseData.java @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; + +import com.google.auto.value.AutoValue; +import io.opentelemetry.context.Context; + +@AutoValue +public abstract class AsyncResponseData { + + public static AsyncResponseData create(Context context, HandlerData handlerData) { + return new AutoValue_AsyncResponseData(context, handlerData); + } + + public abstract Context getContext(); + + public abstract HandlerData getHandlerData(); +} diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CompletionStageFinishCallback.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CompletionStageFinishCallback.java index 26a1728058..eb51422ff7 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CompletionStageFinishCallback.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CompletionStageFinishCallback.java @@ -5,25 +5,23 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; -import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxRsAnnotationsTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsSingletons.instrumenter; import io.opentelemetry.context.Context; import java.util.function.BiFunction; public class CompletionStageFinishCallback implements BiFunction { private final Context context; + private final HandlerData handlerData; - public CompletionStageFinishCallback(Context context) { + public CompletionStageFinishCallback(Context context, HandlerData handlerData) { this.context = context; + this.handlerData = handlerData; } @Override public T apply(T result, Throwable throwable) { - if (throwable == null) { - tracer().end(context); - } else { - tracer().endExceptionally(context, throwable); - } + instrumenter().end(context, handlerData, null, throwable); return result; } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/ContainerRequestFilterInstrumentation.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/ContainerRequestFilterInstrumentation.java index 1100808e73..73ecce8c41 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/ContainerRequestFilterInstrumentation.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/ContainerRequestFilterInstrumentation.java @@ -53,7 +53,7 @@ public class ContainerRequestFilterInstrumentation implements TypeInstrumentatio public static void setFilterClass( @Advice.This ContainerRequestFilter filter, @Advice.Argument(0) ContainerRequestContext context) { - context.setProperty(JaxRsAnnotationsTracer.ABORT_FILTER_CLASS, filter.getClass()); + context.setProperty(JaxrsSingletons.ABORT_FILTER_CLASS, filter.getClass()); } } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/DefaultRequestContextInstrumentation.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/DefaultRequestContextInstrumentation.java index 34abb2cb33..3947c77bea 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/DefaultRequestContextInstrumentation.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/DefaultRequestContextInstrumentation.java @@ -5,10 +5,12 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; -import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxRsAnnotationsTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsSingletons.instrumenter; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming; +import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import java.lang.reflect.Method; import javax.ws.rs.container.ContainerRequestContext; import net.bytebuddy.asm.Advice; @@ -35,30 +37,55 @@ public class DefaultRequestContextInstrumentation extends AbstractRequestContext @Advice.OnMethodEnter(suppress = Throwable.class) public static void createGenericSpan( @Advice.This ContainerRequestContext requestContext, + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope) { - if (requestContext.getProperty(JaxRsAnnotationsTracer.ABORT_HANDLED) == null) { - Class filterClass = - (Class) requestContext.getProperty(JaxRsAnnotationsTracer.ABORT_FILTER_CLASS); - Method method = null; - try { - method = filterClass.getMethod("filter", ContainerRequestContext.class); - } catch (NoSuchMethodException e) { - // Unable to find the filter method. This should not be reachable because the context - // can only be aborted inside the filter method - } - - context = tracer().startSpan(filterClass, method); - scope = context.makeCurrent(); + if (requestContext.getProperty(JaxrsSingletons.ABORT_HANDLED) != null) { + return; } + + Class filterClass = + (Class) requestContext.getProperty(JaxrsSingletons.ABORT_FILTER_CLASS); + Method method = null; + try { + method = filterClass.getMethod("filter", ContainerRequestContext.class); + } catch (NoSuchMethodException e) { + // Unable to find the filter method. This should not be reachable because the context + // can only be aborted inside the filter method + } + + if (filterClass == null || method == null) { + return; + } + + Context parentContext = Java8BytecodeBridge.currentContext(); + handlerData = new HandlerData(filterClass, method); + + ServerSpanNaming.updateServerSpanName( + parentContext, + ServerSpanNaming.Source.CONTROLLER, + JaxrsServerSpanNaming.getServerSpanNameSupplier(parentContext, handlerData)); + + if (!instrumenter().shouldStart(parentContext, handlerData)) { + return; + } + + context = instrumenter().start(parentContext, handlerData); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope, @Advice.Thrown Throwable throwable) { - RequestContextHelper.closeSpanAndScope(context, scope, throwable); + if (scope == null) { + return; + } + + scope.close(); + instrumenter().end(context, handlerData, null, throwable); } } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAnnotationsTracer.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/HandlerData.java similarity index 52% rename from instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAnnotationsTracer.java rename to instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/HandlerData.java index 69c91798f4..775163c8b8 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAnnotationsTracer.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/HandlerData.java @@ -5,40 +5,17 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; -import static io.opentelemetry.api.trace.SpanKind.INTERNAL; - -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming; -import io.opentelemetry.instrumentation.api.servlet.ServletContextPath; -import io.opentelemetry.instrumentation.api.tracer.BaseTracer; -import io.opentelemetry.instrumentation.api.tracer.ServerSpan; -import io.opentelemetry.instrumentation.api.tracer.SpanNames; import io.opentelemetry.javaagent.bootstrap.jaxrs.ClassHierarchyIterable; -import io.opentelemetry.javaagent.bootstrap.jaxrs.JaxrsContextPath; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; import javax.ws.rs.HttpMethod; import javax.ws.rs.Path; -public class JaxRsAnnotationsTracer extends BaseTracer { - public static final String ABORT_FILTER_CLASS = - "io.opentelemetry.javaagent.instrumentation.jaxrs2.filter.abort.class"; - public static final String ABORT_HANDLED = - "io.opentelemetry.javaagent.instrumentation.jaxrs2.filter.abort.handled"; +public class HandlerData { - private static final JaxRsAnnotationsTracer TRACER = new JaxRsAnnotationsTracer(); - - public static JaxRsAnnotationsTracer tracer() { - return TRACER; - } - - private final ClassValue> spanNames = + private static final ClassValue> serverSpanNames = new ClassValue>() { @Override protected Map computeValue(Class type) { @@ -46,61 +23,20 @@ public class JaxRsAnnotationsTracer extends BaseTracer { } }; - public Context startSpan(Class target, Method method) { - return startSpan(Context.current(), target, method); + private final Class target; + private final Method method; + + public HandlerData(Class target, Method method) { + this.target = target; + this.method = method; } - public Context startSpan(Context parentContext, Class target, Method method) { - // We create span and immediately update its name - // We do that in order to reuse logic inside updateSpanNames method, which is used externally as - // well. - SpanBuilder spanBuilder = spanBuilder(parentContext, "jax-rs.request", INTERNAL); - setCodeAttributes(spanBuilder, target, method); - Span span = spanBuilder.startSpan(); - updateSpanNames( - parentContext, span, ServerSpan.fromContextOrNull(parentContext), target, method); - return parentContext.with(span); + public Class codeClass() { + return target; } - public void updateSpanNames( - Context context, Span span, Span serverSpan, Class target, Method method) { - Supplier spanNameSupplier = getPathSpanNameSupplier(context, target, method); - if (serverSpan == null) { - updateSpanName(span, spanNameSupplier.get()); - } else { - ServerSpanNaming.updateServerSpanName( - context, ServerSpanNaming.Source.CONTROLLER, spanNameSupplier); - updateSpanName(span, SpanNames.fromMethod(target, method)); - } - } - - private static void updateSpanName(Span span, String spanName) { - if (!spanName.isEmpty()) { - span.updateName(spanName); - } - } - - private static void setCodeAttributes(SpanBuilder spanBuilder, Class target, Method method) { - spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, target.getName()); - if (method != null) { - spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, method.getName()); - } - } - - private Supplier getPathSpanNameSupplier( - Context context, Class target, Method method) { - return () -> { - String pathBasedSpanName = getPathSpanName(target, method); - // If path based name is empty skip prepending context path so that path based name would - // remain as an empty string for which we skip updating span name. Path base span name is - // empty when method and class don't have a jax-rs path annotation, this can happen when - // creating an "abort" span, see RequestContextHelper. - if (!pathBasedSpanName.isEmpty()) { - pathBasedSpanName = JaxrsContextPath.prepend(context, pathBasedSpanName); - pathBasedSpanName = ServletContextPath.prepend(context, pathBasedSpanName); - } - return pathBasedSpanName; - }; + public String methodName() { + return method.getName(); } /** @@ -109,8 +45,8 @@ public class JaxRsAnnotationsTracer extends BaseTracer { * * @return The result can be an empty string but will never be {@code null}. */ - private String getPathSpanName(Class target, Method method) { - Map classMap = spanNames.get(target); + String getServerSpanName() { + Map classMap = serverSpanNames.get(target); String spanName = classMap.get(method); if (spanName == null) { String httpMethod = null; @@ -222,9 +158,4 @@ public class JaxRsAnnotationsTracer extends BaseTracer { return spanNameBuilder.toString().trim(); } - - @Override - protected String getInstrumentationName() { - return "io.opentelemetry.jaxrs-2.0-common"; - } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAnnotationsInstrumentation.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsAnnotationsInstrumentation.java similarity index 76% rename from instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAnnotationsInstrumentation.java rename to instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsAnnotationsInstrumentation.java index 47136d3018..b9373ed44f 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAnnotationsInstrumentation.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsAnnotationsInstrumentation.java @@ -8,7 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperMethod; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperType; -import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxRsAnnotationsTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; import static net.bytebuddy.matcher.ElementMatchers.isMethod; @@ -17,11 +17,13 @@ import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.instrumentation.api.CallDepth; import io.opentelemetry.javaagent.instrumentation.api.ContextStore; import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext; +import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import java.lang.reflect.Method; import java.util.concurrent.CompletionStage; import javax.ws.rs.Path; @@ -31,7 +33,7 @@ import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.implementation.bytecode.assign.Assigner.Typing; import net.bytebuddy.matcher.ElementMatcher; -public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation { +public class JaxrsAnnotationsInstrumentation implements TypeInstrumentation { @Override public ElementMatcher classLoaderOptimization() { return hasClassesNamed("javax.ws.rs.Path"); @@ -60,7 +62,7 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation { "javax.ws.rs.PATCH", "javax.ws.rs.POST", "javax.ws.rs.PUT")))), - JaxRsAnnotationsInstrumentation.class.getName() + "$JaxRsAnnotationsAdvice"); + JaxrsAnnotationsInstrumentation.class.getName() + "$JaxRsAnnotationsAdvice"); } @SuppressWarnings("unused") @@ -72,6 +74,7 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation { @Advice.Origin Method method, @Advice.AllArguments Object[] args, @Advice.Local("otelCallDepth") CallDepth callDepth, + @Advice.Local("otelHandlerData") HandlerData handlerData, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope, @Advice.Local("otelAsyncResponse") AsyncResponse asyncResponse) { @@ -80,11 +83,11 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation { return; } - ContextStore contextStore = null; + ContextStore contextStore = null; for (Object arg : args) { if (arg instanceof AsyncResponse) { asyncResponse = (AsyncResponse) arg; - contextStore = InstrumentationContext.get(AsyncResponse.class, Context.class); + contextStore = InstrumentationContext.get(AsyncResponse.class, AsyncResponseData.class); if (contextStore.get(asyncResponse) != null) { /* * We are probably in a recursive call and don't want to start a new span because it @@ -98,13 +101,24 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation { } } - context = tracer().startSpan(target.getClass(), method); + Context parentContext = Java8BytecodeBridge.currentContext(); + handlerData = new HandlerData(target.getClass(), method); - if (contextStore != null && asyncResponse != null) { - contextStore.put(asyncResponse, context); + ServerSpanNaming.updateServerSpanName( + parentContext, + ServerSpanNaming.Source.CONTROLLER, + JaxrsServerSpanNaming.getServerSpanNameSupplier(parentContext, handlerData)); + + if (!instrumenter().shouldStart(parentContext, handlerData)) { + return; } + context = instrumenter().start(parentContext, handlerData); scope = context.makeCurrent(); + + if (contextStore != null && asyncResponse != null) { + contextStore.put(asyncResponse, AsyncResponseData.create(context, handlerData)); + } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @@ -112,6 +126,7 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation { @Advice.Return(readOnly = false, typing = Typing.DYNAMIC) Object returnValue, @Advice.Thrown Throwable throwable, @Advice.Local("otelCallDepth") CallDepth callDepth, + @Advice.Local("otelHandlerData") HandlerData handlerData, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope, @Advice.Local("otelAsyncResponse") AsyncResponse asyncResponse) { @@ -119,13 +134,14 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation { return; } - if (context == null || scope == null) { + if (scope == null) { return; } + scope.close(); + if (throwable != null) { - tracer().endExceptionally(context, throwable); - scope.close(); + instrumenter().end(context, handlerData, null, throwable); return; } @@ -134,18 +150,18 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation { if (asyncResponse != null && !asyncResponse.isSuspended()) { // Clear span from the asyncResponse. Logically this should never happen. Added to be safe. - InstrumentationContext.get(AsyncResponse.class, Context.class).put(asyncResponse, null); + InstrumentationContext.get(AsyncResponse.class, AsyncResponseData.class) + .put(asyncResponse, null); } if (asyncReturnValue != null) { // span finished by CompletionStageFinishCallback - asyncReturnValue = asyncReturnValue.handle(new CompletionStageFinishCallback<>(context)); + asyncReturnValue = + asyncReturnValue.handle(new CompletionStageFinishCallback<>(context, handlerData)); } if ((asyncResponse == null || !asyncResponse.isSuspended()) && asyncReturnValue == null) { - tracer().end(context); + instrumenter().end(context, handlerData, null, null); } - // else span finished by AsyncResponseAdvice - - scope.close(); + // else span finished by AsyncResponse*Advice } } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAsyncResponseInstrumentation.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsAsyncResponseInstrumentation.java similarity index 69% rename from instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAsyncResponseInstrumentation.java rename to instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsAsyncResponseInstrumentation.java index adacc979cf..7d4deb4ea0 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAsyncResponseInstrumentation.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsAsyncResponseInstrumentation.java @@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxRsAnnotationsTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -23,7 +23,7 @@ import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; -public class JaxRsAsyncResponseInstrumentation implements TypeInstrumentation { +public class JaxrsAsyncResponseInstrumentation implements TypeInstrumentation { @Override public ElementMatcher classLoaderOptimization() { @@ -39,13 +39,13 @@ public class JaxRsAsyncResponseInstrumentation implements TypeInstrumentation { public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( named("resume").and(takesArgument(0, Object.class)).and(isPublic()), - JaxRsAsyncResponseInstrumentation.class.getName() + "$AsyncResponseAdvice"); + JaxrsAsyncResponseInstrumentation.class.getName() + "$AsyncResponseAdvice"); transformer.applyAdviceToMethod( named("resume").and(takesArgument(0, Throwable.class)).and(isPublic()), - JaxRsAsyncResponseInstrumentation.class.getName() + "$AsyncResponseThrowableAdvice"); + JaxrsAsyncResponseInstrumentation.class.getName() + "$AsyncResponseThrowableAdvice"); transformer.applyAdviceToMethod( named("cancel"), - JaxRsAsyncResponseInstrumentation.class.getName() + "$AsyncResponseCancelAdvice"); + JaxrsAsyncResponseInstrumentation.class.getName() + "$AsyncResponseCancelAdvice"); } @SuppressWarnings("unused") @@ -54,13 +54,13 @@ public class JaxRsAsyncResponseInstrumentation implements TypeInstrumentation { @Advice.OnMethodExit(suppress = Throwable.class) public static void stopSpan(@Advice.This AsyncResponse asyncResponse) { - ContextStore contextStore = - InstrumentationContext.get(AsyncResponse.class, Context.class); + ContextStore contextStore = + InstrumentationContext.get(AsyncResponse.class, AsyncResponseData.class); - Context context = contextStore.get(asyncResponse); - if (context != null) { + AsyncResponseData data = contextStore.get(asyncResponse); + if (data != null) { contextStore.put(asyncResponse, null); - tracer().end(context); + instrumenter().end(data.getContext(), data.getHandlerData(), null, null); } } } @@ -72,13 +72,13 @@ public class JaxRsAsyncResponseInstrumentation implements TypeInstrumentation { public static void stopSpan( @Advice.This AsyncResponse asyncResponse, @Advice.Argument(0) Throwable throwable) { - ContextStore contextStore = - InstrumentationContext.get(AsyncResponse.class, Context.class); + ContextStore contextStore = + InstrumentationContext.get(AsyncResponse.class, AsyncResponseData.class); - Context context = contextStore.get(asyncResponse); - if (context != null) { + AsyncResponseData data = contextStore.get(asyncResponse); + if (data != null) { contextStore.put(asyncResponse, null); - tracer().endExceptionally(context, throwable); + instrumenter().end(data.getContext(), data.getHandlerData(), null, throwable); } } } @@ -89,16 +89,17 @@ public class JaxRsAsyncResponseInstrumentation implements TypeInstrumentation { @Advice.OnMethodExit(suppress = Throwable.class) public static void stopSpan(@Advice.This AsyncResponse asyncResponse) { - ContextStore contextStore = - InstrumentationContext.get(AsyncResponse.class, Context.class); + ContextStore contextStore = + InstrumentationContext.get(AsyncResponse.class, AsyncResponseData.class); - Context context = contextStore.get(asyncResponse); - if (context != null) { + AsyncResponseData data = contextStore.get(asyncResponse); + if (data != null) { contextStore.put(asyncResponse, null); + Context context = data.getContext(); if (JaxrsConfig.CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES) { Java8BytecodeBridge.spanFromContext(context).setAttribute("jaxrs.canceled", true); } - tracer().end(context); + instrumenter().end(context, data.getHandlerData(), null, null); } } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsCodeAttributesExtractor.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsCodeAttributesExtractor.java new file mode 100644 index 0000000000..da5aaa4fc1 --- /dev/null +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsCodeAttributesExtractor.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; + +import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class JaxrsCodeAttributesExtractor extends CodeAttributesExtractor { + @Override + protected @Nullable Class codeClass(HandlerData handlerData) { + return handlerData.codeClass(); + } + + @Override + protected @Nullable String methodName(HandlerData handlerData) { + return handlerData.methodName(); + } + + @Override + protected @Nullable String filePath(HandlerData handlerData) { + return null; + } + + @Override + protected @Nullable Long lineNumber(HandlerData handlerData) { + return null; + } +} diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsInstrumentationModule.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsInstrumentationModule.java similarity index 83% rename from instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsInstrumentationModule.java rename to instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsInstrumentationModule.java index 695349a3b8..83d90eeff1 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsInstrumentationModule.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsInstrumentationModule.java @@ -15,8 +15,8 @@ import java.util.List; import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) -public class JaxRsInstrumentationModule extends InstrumentationModule { - public JaxRsInstrumentationModule() { +public class JaxrsInstrumentationModule extends InstrumentationModule { + public JaxrsInstrumentationModule() { super("jaxrs", "jaxrs-2.0"); } @@ -31,7 +31,7 @@ public class JaxRsInstrumentationModule extends InstrumentationModule { return asList( new ContainerRequestFilterInstrumentation(), new DefaultRequestContextInstrumentation(), - new JaxRsAnnotationsInstrumentation(), - new JaxRsAsyncResponseInstrumentation()); + new JaxrsAnnotationsInstrumentation(), + new JaxrsAsyncResponseInstrumentation()); } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsPathUtil.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsPathUtil.java similarity index 89% rename from instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsPathUtil.java rename to instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsPathUtil.java index 83451f29d3..03695919cc 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsPathUtil.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsPathUtil.java @@ -5,8 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; -public final class JaxRsPathUtil { - private JaxRsPathUtil() {} +public final class JaxrsPathUtil { + private JaxrsPathUtil() {} public static String normalizePath(String path) { // ensure that non-empty path starts with / diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsServerSpanNaming.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsServerSpanNaming.java new file mode 100644 index 0000000000..6468cd4c90 --- /dev/null +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsServerSpanNaming.java @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.servlet.ServletContextPath; +import io.opentelemetry.javaagent.bootstrap.jaxrs.JaxrsContextPath; +import java.util.function.Supplier; + +public class JaxrsServerSpanNaming { + + public static Supplier getServerSpanNameSupplier( + Context context, HandlerData handlerData) { + return () -> { + String pathBasedSpanName = handlerData.getServerSpanName(); + // If path based name is empty skip prepending context path so that path based name would + // remain as an empty string for which we skip updating span name. Path base span name is + // empty when method and class don't have a jax-rs path annotation, this can happen when + // creating an "abort" span, see RequestContextHelper. + if (!pathBasedSpanName.isEmpty()) { + pathBasedSpanName = JaxrsContextPath.prepend(context, pathBasedSpanName); + pathBasedSpanName = ServletContextPath.prepend(context, pathBasedSpanName); + } + return pathBasedSpanName; + }; + } + + private JaxrsServerSpanNaming() {} +} diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsSingletons.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsSingletons.java new file mode 100644 index 0000000000..4cd7632697 --- /dev/null +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsSingletons.java @@ -0,0 +1,43 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.code.CodeSpanNameExtractor; + +public final class JaxrsSingletons { + + public static final String ABORT_FILTER_CLASS = + "io.opentelemetry.javaagent.instrumentation.jaxrs2.filter.abort.class"; + public static final String ABORT_HANDLED = + "io.opentelemetry.javaagent.instrumentation.jaxrs2.filter.abort.handled"; + + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jaxrs-2.0-common"; + + private static final Instrumenter INSTRUMENTER; + + static { + CodeAttributesExtractor codeAttributesExtractor = + new JaxrsCodeAttributesExtractor(); + SpanNameExtractor spanNameExtractor = + CodeSpanNameExtractor.create(codeAttributesExtractor); + + INSTRUMENTER = + Instrumenter.newBuilder( + GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanNameExtractor) + .addAttributesExtractor(codeAttributesExtractor) + .newInstrumenter(); + } + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private JaxrsSingletons() {} +} diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/RequestContextHelper.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/RequestContextHelper.java index e3f33fbd92..9c2c2d5cad 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/RequestContextHelper.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/RequestContextHelper.java @@ -5,51 +5,44 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; -import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxRsAnnotationsTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsSingletons.instrumenter; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming; import io.opentelemetry.instrumentation.api.tracer.ServerSpan; import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; -import java.lang.reflect.Method; import javax.ws.rs.container.ContainerRequestContext; public final class RequestContextHelper { public static Context createOrUpdateAbortSpan( - ContainerRequestContext requestContext, Class resourceClass, Method method) { + ContainerRequestContext requestContext, HandlerData handlerData) { - if (method != null && resourceClass != null) { - requestContext.setProperty(JaxRsAnnotationsTracer.ABORT_HANDLED, true); - Context context = Java8BytecodeBridge.currentContext(); - Span serverSpan = ServerSpan.fromContextOrNull(context); - Span currentSpan = Java8BytecodeBridge.spanFromContext(context); - - // if there's no current span or it's the same as the server (servlet) span we need to start - // a JAX-RS one - // in other case, DefaultRequestContextInstrumentation must have already run so it's enough - // to just update the names - if (currentSpan == null || currentSpan == serverSpan) { - return tracer().startSpan(context, resourceClass, method); - } else { - tracer().updateSpanNames(context, currentSpan, serverSpan, resourceClass, method); - } - } - return null; - } - - public static void closeSpanAndScope(Context context, Scope scope, Throwable throwable) { - if (context == null || scope == null) { - return; + if (handlerData == null) { + return null; } - if (throwable != null) { - tracer().endExceptionally(context, throwable); - } else { - tracer().end(context); + requestContext.setProperty(JaxrsSingletons.ABORT_HANDLED, true); + Context parentContext = Java8BytecodeBridge.currentContext(); + Span serverSpan = ServerSpan.fromContextOrNull(parentContext); + Span currentSpan = Java8BytecodeBridge.spanFromContext(parentContext); + + ServerSpanNaming.updateServerSpanName( + parentContext, + ServerSpanNaming.Source.CONTROLLER, + JaxrsServerSpanNaming.getServerSpanNameSupplier(parentContext, handlerData)); + + if (currentSpan != null && currentSpan != serverSpan) { + // there's already an active span, and it's not the same as the server (servlet) span, + // so we don't want to start a JAX-RS one + return null; } - scope.close(); + if (!instrumenter().shouldStart(parentContext, handlerData)) { + return null; + } + + return instrumenter().start(parentContext, handlerData); } private RequestContextHelper() {} diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CxfRequestContextInstrumentation.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CxfRequestContextInstrumentation.java index bc00968e8b..3c7727bbac 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CxfRequestContextInstrumentation.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CxfRequestContextInstrumentation.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -58,38 +59,47 @@ public class CxfRequestContextInstrumentation implements TypeInstrumentation { @Advice.OnMethodEnter(suppress = Throwable.class) public static void decorateAbortSpan( @Advice.This AbstractRequestContextImpl requestContext, + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope) { - if (requestContext.getProperty(JaxRsAnnotationsTracer.ABORT_HANDLED) == null - && requestContext instanceof ContainerRequestContext) { - Message message = requestContext.getMessage(); - OperationResourceInfoStack resourceInfoStack = - (OperationResourceInfoStack) - message.get("org.apache.cxf.jaxrs.model.OperationResourceInfoStack"); - if (resourceInfoStack == null || resourceInfoStack.isEmpty()) { - return; - } + if (requestContext.getProperty(JaxrsSingletons.ABORT_HANDLED) != null + || !(requestContext instanceof ContainerRequestContext)) { + return; + } - MethodInvocationInfo invocationInfo = resourceInfoStack.peek(); - Method method = invocationInfo.getMethodInfo().getMethodToInvoke(); - Class resourceClass = invocationInfo.getRealClass(); + Message message = requestContext.getMessage(); + OperationResourceInfoStack resourceInfoStack = + (OperationResourceInfoStack) + message.get("org.apache.cxf.jaxrs.model.OperationResourceInfoStack"); + if (resourceInfoStack == null || resourceInfoStack.isEmpty()) { + return; + } - context = - RequestContextHelper.createOrUpdateAbortSpan( - (ContainerRequestContext) requestContext, resourceClass, method); - if (context != null) { - scope = context.makeCurrent(); - } + MethodInvocationInfo invocationInfo = resourceInfoStack.peek(); + Method method = invocationInfo.getMethodInfo().getMethodToInvoke(); + Class resourceClass = invocationInfo.getRealClass(); + + handlerData = new HandlerData(resourceClass, method); + context = + RequestContextHelper.createOrUpdateAbortSpan( + (ContainerRequestContext) requestContext, handlerData); + if (context != null) { + scope = context.makeCurrent(); } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope, @Advice.Thrown Throwable throwable) { - RequestContextHelper.closeSpanAndScope(context, scope, throwable); + if (scope == null) { + return; + } + scope.close(); + instrumenter().end(context, handlerData, null, throwable); } } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CxfTracingUtil.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CxfTracingUtil.java index 0efc7a1d4d..b69a9dd616 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CxfTracingUtil.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/CxfTracingUtil.java @@ -5,7 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; -import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxRsPathUtil.normalizePath; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsPathUtil.normalizePath; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/test/groovy/CxfAnnotationInstrumentationTest.groovy b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/test/groovy/CxfAnnotationInstrumentationTest.groovy index 6e3325d80e..dcffae8a37 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/test/groovy/CxfAnnotationInstrumentationTest.groovy +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-cxf-3.2/javaagent/src/test/groovy/CxfAnnotationInstrumentationTest.groovy @@ -3,5 +3,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -class CxfAnnotationInstrumentationTest extends JaxRsAnnotationsInstrumentationTest { +class CxfAnnotationInstrumentationTest extends JaxrsAnnotationsInstrumentationTest { } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JerseyRequestContextInstrumentation.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JerseyRequestContextInstrumentation.java index 8676214988..336a562a7b 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JerseyRequestContextInstrumentation.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JerseyRequestContextInstrumentation.java @@ -5,6 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsSingletons.instrumenter; + import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import java.lang.reflect.Method; @@ -35,31 +37,42 @@ public class JerseyRequestContextInstrumentation extends AbstractRequestContextI @Advice.OnMethodEnter(suppress = Throwable.class) public static void decorateAbortSpan( @Advice.This ContainerRequestContext requestContext, + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope) { UriInfo uriInfo = requestContext.getUriInfo(); - if (requestContext.getProperty(JaxRsAnnotationsTracer.ABORT_HANDLED) == null - && uriInfo instanceof ResourceInfo) { + if (requestContext.getProperty(JaxrsSingletons.ABORT_HANDLED) != null + || !(uriInfo instanceof ResourceInfo)) { + return; + } - ResourceInfo resourceInfo = (ResourceInfo) uriInfo; - Method method = resourceInfo.getResourceMethod(); - Class resourceClass = resourceInfo.getResourceClass(); + ResourceInfo resourceInfo = (ResourceInfo) uriInfo; + Method method = resourceInfo.getResourceMethod(); + Class resourceClass = resourceInfo.getResourceClass(); - context = - RequestContextHelper.createOrUpdateAbortSpan(requestContext, resourceClass, method); - if (context != null) { - scope = context.makeCurrent(); - } + if (resourceClass == null || method == null) { + return; + } + + handlerData = new HandlerData(resourceClass, method); + context = RequestContextHelper.createOrUpdateAbortSpan(requestContext, handlerData); + if (context != null) { + scope = context.makeCurrent(); } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope, @Advice.Thrown Throwable throwable) { - RequestContextHelper.closeSpanAndScope(context, scope, throwable); + if (scope == null) { + return; + } + scope.close(); + instrumenter().end(context, handlerData, null, throwable); } } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JerseyTracingUtil.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JerseyTracingUtil.java index ece3b9c4a7..093a237a8f 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JerseyTracingUtil.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JerseyTracingUtil.java @@ -5,7 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; -import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxRsPathUtil.normalizePath; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsPathUtil.normalizePath; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/test/groovy/JerseyAnnotationInstrumentationTest.groovy b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/test/groovy/JerseyAnnotationInstrumentationTest.groovy index a171d38b7a..2876a911ae 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/test/groovy/JerseyAnnotationInstrumentationTest.groovy +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/src/test/groovy/JerseyAnnotationInstrumentationTest.groovy @@ -3,5 +3,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -class JerseyAnnotationInstrumentationTest extends JaxRsAnnotationsInstrumentationTest { +class JerseyAnnotationInstrumentationTest extends JaxrsAnnotationsInstrumentationTest { } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/Resteasy30RequestContextInstrumentation.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/Resteasy30RequestContextInstrumentation.java index 94ee2e6420..804dc06653 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/Resteasy30RequestContextInstrumentation.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/Resteasy30RequestContextInstrumentation.java @@ -5,6 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsSingletons.instrumenter; + import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import java.lang.reflect.Method; @@ -36,30 +38,37 @@ public class Resteasy30RequestContextInstrumentation extends AbstractRequestCont @Advice.OnMethodEnter(suppress = Throwable.class) public static void decorateAbortSpan( @Advice.This ContainerRequestContext requestContext, + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope) { - if (requestContext.getProperty(JaxRsAnnotationsTracer.ABORT_HANDLED) == null - && requestContext instanceof PostMatchContainerRequestContext) { + if (requestContext.getProperty(JaxrsSingletons.ABORT_HANDLED) != null + || !(requestContext instanceof PostMatchContainerRequestContext)) { + return; + } - ResourceMethodInvoker resourceMethodInvoker = - ((PostMatchContainerRequestContext) requestContext).getResourceMethod(); - Method method = resourceMethodInvoker.getMethod(); - Class resourceClass = resourceMethodInvoker.getResourceClass(); + ResourceMethodInvoker resourceMethodInvoker = + ((PostMatchContainerRequestContext) requestContext).getResourceMethod(); + Method method = resourceMethodInvoker.getMethod(); + Class resourceClass = resourceMethodInvoker.getResourceClass(); - context = - RequestContextHelper.createOrUpdateAbortSpan(requestContext, resourceClass, method); - if (context != null) { - scope = context.makeCurrent(); - } + handlerData = new HandlerData(resourceClass, method); + context = RequestContextHelper.createOrUpdateAbortSpan(requestContext, handlerData); + if (context != null) { + scope = context.makeCurrent(); } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope, @Advice.Thrown Throwable throwable) { - RequestContextHelper.closeSpanAndScope(context, scope, throwable); + if (scope == null) { + return; + } + scope.close(); + instrumenter().end(context, handlerData, null, throwable); } } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/src/test/groovy/ResteasyAnnotationInstrumentationTest.groovy b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/src/test/groovy/ResteasyAnnotationInstrumentationTest.groovy index f86d3473d4..79bbbccc11 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/src/test/groovy/ResteasyAnnotationInstrumentationTest.groovy +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/src/test/groovy/ResteasyAnnotationInstrumentationTest.groovy @@ -3,5 +3,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -class ResteasyAnnotationInstrumentationTest extends JaxRsAnnotationsInstrumentationTest { +class ResteasyAnnotationInstrumentationTest extends JaxrsAnnotationsInstrumentationTest { } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/Resteasy31RequestContextInstrumentation.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/Resteasy31RequestContextInstrumentation.java index 762cfd8552..c6acfe0e26 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/Resteasy31RequestContextInstrumentation.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/Resteasy31RequestContextInstrumentation.java @@ -5,6 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0; +import static io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxrsSingletons.instrumenter; + import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import java.lang.reflect.Method; @@ -36,30 +38,37 @@ public class Resteasy31RequestContextInstrumentation extends AbstractRequestCont @Advice.OnMethodEnter(suppress = Throwable.class) public static void decorateAbortSpan( @Advice.This ContainerRequestContext requestContext, + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope) { - if (requestContext.getProperty(JaxRsAnnotationsTracer.ABORT_HANDLED) == null - && requestContext instanceof PostMatchContainerRequestContext) { + if (requestContext.getProperty(JaxrsSingletons.ABORT_HANDLED) != null + || !(requestContext instanceof PostMatchContainerRequestContext)) { + return; + } - ResourceMethodInvoker resourceMethodInvoker = - ((PostMatchContainerRequestContext) requestContext).getResourceMethod(); - Method method = resourceMethodInvoker.getMethod(); - Class resourceClass = resourceMethodInvoker.getResourceClass(); + ResourceMethodInvoker resourceMethodInvoker = + ((PostMatchContainerRequestContext) requestContext).getResourceMethod(); + Method method = resourceMethodInvoker.getMethod(); + Class resourceClass = resourceMethodInvoker.getResourceClass(); - context = - RequestContextHelper.createOrUpdateAbortSpan(requestContext, resourceClass, method); - if (context != null) { - scope = context.makeCurrent(); - } + handlerData = new HandlerData(resourceClass, method); + context = RequestContextHelper.createOrUpdateAbortSpan(requestContext, handlerData); + if (context != null) { + scope = context.makeCurrent(); } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( + @Local("otelHandlerData") HandlerData handlerData, @Local("otelContext") Context context, @Local("otelScope") Scope scope, @Advice.Thrown Throwable throwable) { - RequestContextHelper.closeSpanAndScope(context, scope, throwable); + if (scope == null) { + return; + } + scope.close(); + instrumenter().end(context, handlerData, null, throwable); } } } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/src/test/groovy/ResteasyAnnotationInstrumentationTest.groovy b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/src/test/groovy/ResteasyAnnotationInstrumentationTest.groovy index f86d3473d4..79bbbccc11 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/src/test/groovy/ResteasyAnnotationInstrumentationTest.groovy +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/src/test/groovy/ResteasyAnnotationInstrumentationTest.groovy @@ -3,5 +3,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -class ResteasyAnnotationInstrumentationTest extends JaxRsAnnotationsInstrumentationTest { +class ResteasyAnnotationInstrumentationTest extends JaxrsAnnotationsInstrumentationTest { } diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/ResteasyRootNodeTypeInstrumentation.java b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/ResteasyRootNodeTypeInstrumentation.java index f70b6cefca..e214ff1743 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/ResteasyRootNodeTypeInstrumentation.java +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/ResteasyRootNodeTypeInstrumentation.java @@ -47,7 +47,7 @@ public class ResteasyRootNodeTypeInstrumentation implements TypeInstrumentation public static void addInvoker( @Advice.Argument(0) String path, @Advice.Argument(value = 1, typing = Assigner.Typing.DYNAMIC) Object invoker) { - String normalizedPath = JaxRsPathUtil.normalizePath(path); + String normalizedPath = JaxrsPathUtil.normalizePath(path); if (invoker instanceof ResourceLocatorInvoker) { ResourceLocatorInvoker resourceLocatorInvoker = (ResourceLocatorInvoker) invoker; InstrumentationContext.get(ResourceLocatorInvoker.class, String.class) diff --git a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-testing/src/main/groovy/JaxRsAnnotationsInstrumentationTest.groovy b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-testing/src/main/groovy/JaxrsAnnotationsInstrumentationTest.groovy similarity index 85% rename from instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-testing/src/main/groovy/JaxRsAnnotationsInstrumentationTest.groovy rename to instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-testing/src/main/groovy/JaxrsAnnotationsInstrumentationTest.groovy index 8f2dd2c40f..ccbb1121d8 100644 --- a/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-testing/src/main/groovy/JaxRsAnnotationsInstrumentationTest.groovy +++ b/instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-testing/src/main/groovy/JaxrsAnnotationsInstrumentationTest.groovy @@ -18,31 +18,7 @@ import javax.ws.rs.PUT import javax.ws.rs.Path import spock.lang.Unroll -abstract class JaxRsAnnotationsInstrumentationTest extends AgentInstrumentationSpecification { - - def "instrumentation can be used as root span and resource is set to METHOD PATH"() { - setup: - def jax = new Jax() { - @POST - @Path("/a") - void call() { - } - } - jax.call() - - expect: - assertTraces(1) { - trace(0, 1) { - span(0) { - name "/a" - attributes { - "${SemanticAttributes.CODE_NAMESPACE.key}" jax.getClass().getName() - "${SemanticAttributes.CODE_FUNCTION.key}" "call" - } - } - } - } - } +abstract class JaxrsAnnotationsInstrumentationTest extends AgentInstrumentationSpecification { @Unroll def "span named '#paramName' from annotations on class '#className' when is not root span"() {