Update jaxrs-common to Instrumenter API (#3796)
This commit is contained in:
parent
19711ca76b
commit
7e007e8f32
|
@ -19,4 +19,7 @@ dependencies {
|
|||
compileOnly(project(":instrumentation:jaxrs:bootstrap"))
|
||||
|
||||
compileOnly("javax.ws.rs:javax.ws.rs-api:2.0")
|
||||
}
|
||||
|
||||
compileOnly("com.google.auto.value:auto-value-annotations")
|
||||
annotationProcessor("com.google.auto.value:auto-value")
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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<T> implements BiFunction<T, Throwable, T> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Map<Method, String>> spanNames =
|
||||
private static final ClassValue<Map<Method, String>> serverSpanNames =
|
||||
new ClassValue<Map<Method, String>>() {
|
||||
@Override
|
||||
protected Map<Method, String> 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<String> 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<String> 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<Method, String> classMap = spanNames.get(target);
|
||||
String getServerSpanName() {
|
||||
Map<Method, String> 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";
|
||||
}
|
||||
}
|
|
@ -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<ClassLoader> 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<AsyncResponse, Context> contextStore = null;
|
||||
ContextStore<AsyncResponse, AsyncResponseData> 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<ClassLoader> 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<AsyncResponse, Context> contextStore =
|
||||
InstrumentationContext.get(AsyncResponse.class, Context.class);
|
||||
ContextStore<AsyncResponse, AsyncResponseData> 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<AsyncResponse, Context> contextStore =
|
||||
InstrumentationContext.get(AsyncResponse.class, Context.class);
|
||||
ContextStore<AsyncResponse, AsyncResponseData> 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<AsyncResponse, Context> contextStore =
|
||||
InstrumentationContext.get(AsyncResponse.class, Context.class);
|
||||
ContextStore<AsyncResponse, AsyncResponseData> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<HandlerData, Void> {
|
||||
@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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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 /
|
|
@ -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<String> 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() {}
|
||||
}
|
|
@ -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<HandlerData, Void> INSTRUMENTER;
|
||||
|
||||
static {
|
||||
CodeAttributesExtractor<HandlerData, Void> codeAttributesExtractor =
|
||||
new JaxrsCodeAttributesExtractor();
|
||||
SpanNameExtractor<HandlerData> spanNameExtractor =
|
||||
CodeSpanNameExtractor.create(codeAttributesExtractor);
|
||||
|
||||
INSTRUMENTER =
|
||||
Instrumenter.<HandlerData, Void>newBuilder(
|
||||
GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanNameExtractor)
|
||||
.addAttributesExtractor(codeAttributesExtractor)
|
||||
.newInstrumenter();
|
||||
}
|
||||
|
||||
public static Instrumenter<HandlerData, Void> instrumenter() {
|
||||
return INSTRUMENTER;
|
||||
}
|
||||
|
||||
private JaxrsSingletons() {}
|
||||
}
|
|
@ -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() {}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
class CxfAnnotationInstrumentationTest extends JaxRsAnnotationsInstrumentationTest {
|
||||
class CxfAnnotationInstrumentationTest extends JaxrsAnnotationsInstrumentationTest {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
class JerseyAnnotationInstrumentationTest extends JaxRsAnnotationsInstrumentationTest {
|
||||
class JerseyAnnotationInstrumentationTest extends JaxrsAnnotationsInstrumentationTest {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
class ResteasyAnnotationInstrumentationTest extends JaxRsAnnotationsInstrumentationTest {
|
||||
class ResteasyAnnotationInstrumentationTest extends JaxrsAnnotationsInstrumentationTest {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
class ResteasyAnnotationInstrumentationTest extends JaxRsAnnotationsInstrumentationTest {
|
||||
class ResteasyAnnotationInstrumentationTest extends JaxrsAnnotationsInstrumentationTest {
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"() {
|
Loading…
Reference in New Issue