Skip to content

Commit 2f2aca1

Browse files
committed
jaxrs-3.0-annotations
1 parent ef81cdd commit 2f2aca1

File tree

3 files changed

+158
-110
lines changed

3 files changed

+158
-110
lines changed

instrumentation/jaxrs/jaxrs-3.0/jaxrs-3.0-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v3_0/DefaultRequestContextInstrumentation.java

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import io.opentelemetry.javaagent.instrumentation.jaxrs.JaxrsServerSpanNaming;
1717
import jakarta.ws.rs.container.ContainerRequestContext;
1818
import java.lang.reflect.Method;
19+
import javax.annotation.Nullable;
1920
import net.bytebuddy.asm.Advice;
20-
import net.bytebuddy.asm.Advice.Local;
2121

2222
/**
2323
* Default context instrumentation.
@@ -37,59 +37,82 @@ protected String abortAdviceName() {
3737
@SuppressWarnings("unused")
3838
public static class ContainerRequestContextAdvice {
3939

40+
public static class AdviceScope {
41+
private final Jaxrs3HandlerData handlerData;
42+
private final Context context;
43+
private final Scope scope;
44+
45+
private AdviceScope(Context context, Scope scope, Jaxrs3HandlerData handlerData) {
46+
this.context = context;
47+
this.scope = scope;
48+
this.handlerData = handlerData;
49+
}
50+
51+
@Nullable
52+
public static AdviceScope start(
53+
Class<?> filterClass, Method method, ContainerRequestContext requestContext) {
54+
Context parentContext = Java8BytecodeBridge.currentContext();
55+
Jaxrs3HandlerData handlerData = new Jaxrs3HandlerData(filterClass, method);
56+
57+
HttpServerRoute.update(
58+
parentContext,
59+
HttpServerRouteSource.CONTROLLER,
60+
JaxrsServerSpanNaming.SERVER_SPAN_NAME,
61+
handlerData);
62+
63+
if (!instrumenter().shouldStart(parentContext, handlerData)) {
64+
return null;
65+
}
66+
67+
Context context = instrumenter().start(parentContext, handlerData);
68+
Scope scope = context.makeCurrent();
69+
return new AdviceScope(context, scope, handlerData);
70+
}
71+
72+
public void exit(@Nullable Throwable throwable) {
73+
if (scope == null) {
74+
return;
75+
}
76+
77+
scope.close();
78+
instrumenter().end(context, handlerData, null, throwable);
79+
}
80+
}
81+
82+
@Nullable
4083
@Advice.OnMethodEnter(suppress = Throwable.class)
41-
public static void createGenericSpan(
42-
@Advice.This ContainerRequestContext requestContext,
43-
@Local("otelHandlerData") Jaxrs3HandlerData handlerData,
44-
@Local("otelContext") Context context,
45-
@Local("otelScope") Scope scope) {
84+
public static AdviceScope createGenericSpan(
85+
@Advice.This ContainerRequestContext requestContext) {
86+
4687
if (requestContext.getProperty(JaxrsConstants.ABORT_HANDLED) != null) {
47-
return;
88+
return null;
4889
}
49-
5090
Class<?> filterClass =
5191
(Class<?>) requestContext.getProperty(JaxrsConstants.ABORT_FILTER_CLASS);
92+
if (filterClass != null) {
93+
return null;
94+
}
5295
Method method = null;
5396
try {
5497
method = filterClass.getMethod("filter", ContainerRequestContext.class);
5598
} catch (NoSuchMethodException e) {
5699
// Unable to find the filter method. This should not be reachable because the context
57100
// can only be aborted inside the filter method
58101
}
59-
60-
if (filterClass == null || method == null) {
61-
return;
102+
if (method == null) {
103+
return null;
62104
}
63105

64-
Context parentContext = Java8BytecodeBridge.currentContext();
65-
handlerData = new Jaxrs3HandlerData(filterClass, method);
66-
67-
HttpServerRoute.update(
68-
parentContext,
69-
HttpServerRouteSource.CONTROLLER,
70-
JaxrsServerSpanNaming.SERVER_SPAN_NAME,
71-
handlerData);
72-
73-
if (!instrumenter().shouldStart(parentContext, handlerData)) {
74-
return;
75-
}
76-
77-
context = instrumenter().start(parentContext, handlerData);
78-
scope = context.makeCurrent();
106+
return AdviceScope.start(filterClass, method, requestContext);
79107
}
80108

81109
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
82110
public static void stopSpan(
83-
@Local("otelHandlerData") Jaxrs3HandlerData handlerData,
84-
@Local("otelContext") Context context,
85-
@Local("otelScope") Scope scope,
86-
@Advice.Thrown Throwable throwable) {
87-
if (scope == null) {
88-
return;
89-
}
111+
@Advice.Thrown Throwable throwable, @Advice.Enter AdviceScope adviceScope) {
90112

91-
scope.close();
92-
instrumenter().end(context, handlerData, null, throwable);
113+
if (adviceScope != null) {
114+
adviceScope.exit(throwable);
115+
}
93116
}
94117
}
95118
}

instrumentation/jaxrs/jaxrs-3.0/jaxrs-3.0-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v3_0/JaxrsAnnotationsInstrumentation.java

Lines changed: 92 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
import jakarta.ws.rs.container.AsyncResponse;
3333
import java.lang.reflect.Method;
3434
import java.util.concurrent.CompletionStage;
35+
import javax.annotation.Nullable;
3536
import net.bytebuddy.asm.Advice;
37+
import net.bytebuddy.asm.Advice.AssignReturned;
3638
import net.bytebuddy.description.type.TypeDescription;
3739
import net.bytebuddy.implementation.bytecode.assign.Assigner.Typing;
3840
import net.bytebuddy.matcher.ElementMatcher;
@@ -69,96 +71,112 @@ public void transform(TypeTransformer transformer) {
6971
@SuppressWarnings("unused")
7072
public static class JaxRsAnnotationsAdvice {
7173

72-
@Advice.OnMethodEnter(suppress = Throwable.class)
73-
public static void nameSpan(
74-
@Advice.This Object target,
75-
@Advice.Origin Method method,
76-
@Advice.AllArguments Object[] args,
77-
@Advice.Local("otelCallDepth") CallDepth callDepth,
78-
@Advice.Local("otelHandlerData") Jaxrs3HandlerData handlerData,
79-
@Advice.Local("otelContext") Context context,
80-
@Advice.Local("otelScope") Scope scope,
81-
@Advice.Local("otelAsyncResponse") AsyncResponse asyncResponse) {
82-
callDepth = CallDepth.forClass(Path.class);
83-
if (callDepth.getAndIncrement() > 0) {
84-
return;
74+
public static class AdviceScope {
75+
public Jaxrs3HandlerData handlerData;
76+
public AsyncResponse asyncResponse;
77+
public CallDepth callDepth;
78+
public Context context;
79+
public Scope scope;
80+
81+
public AdviceScope(CallDepth callDepth) {
82+
this.callDepth = callDepth;
8583
}
8684

87-
VirtualField<AsyncResponse, AsyncResponseData> virtualField = null;
88-
for (Object arg : args) {
89-
if (arg instanceof AsyncResponse) {
90-
asyncResponse = (AsyncResponse) arg;
91-
virtualField = VirtualField.find(AsyncResponse.class, AsyncResponseData.class);
92-
if (virtualField.get(asyncResponse) != null) {
93-
/*
94-
* We are probably in a recursive call and don't want to start a new span because it
95-
* would replace the existing span in the asyncResponse and cause it to never finish. We
96-
* could work around this by using a list instead, but we likely don't want the extra
97-
* span anyway.
98-
*/
99-
return;
100-
}
101-
break;
85+
public AdviceScope enter(Class<?> type, Method method, Object[] args) {
86+
if (callDepth.getAndIncrement() > 0) {
87+
return this;
10288
}
103-
}
10489

105-
Context parentContext = Java8BytecodeBridge.currentContext();
106-
handlerData = new Jaxrs3HandlerData(target.getClass(), method);
90+
VirtualField<AsyncResponse, AsyncResponseData> virtualField = null;
91+
for (Object arg : args) {
92+
if (arg instanceof AsyncResponse) {
93+
asyncResponse = (AsyncResponse) arg;
94+
virtualField = VirtualField.find(AsyncResponse.class, AsyncResponseData.class);
95+
if (virtualField.get(asyncResponse) != null) {
96+
/*
97+
* We are probably in a recursive call and don't want to start a new span because it
98+
* would replace the existing span in the asyncResponse and cause it to never finish. We
99+
* could work around this by using a list instead, but we likely don't want the extra
100+
* span anyway.
101+
*/
102+
return this;
103+
}
104+
break;
105+
}
106+
}
107107

108-
HttpServerRoute.update(
109-
parentContext,
110-
HttpServerRouteSource.CONTROLLER,
111-
JaxrsServerSpanNaming.SERVER_SPAN_NAME,
112-
handlerData);
108+
Context parentContext = Java8BytecodeBridge.currentContext();
109+
handlerData = new Jaxrs3HandlerData(type, method);
113110

114-
if (!instrumenter().shouldStart(parentContext, handlerData)) {
115-
return;
116-
}
111+
HttpServerRoute.update(
112+
parentContext,
113+
HttpServerRouteSource.CONTROLLER,
114+
JaxrsServerSpanNaming.SERVER_SPAN_NAME,
115+
handlerData);
117116

118-
context = instrumenter().start(parentContext, handlerData);
119-
scope = context.makeCurrent();
117+
if (!instrumenter().shouldStart(parentContext, handlerData)) {
118+
return this;
119+
}
120120

121-
if (virtualField != null && asyncResponse != null) {
122-
virtualField.set(asyncResponse, AsyncResponseData.create(context, handlerData));
123-
}
124-
}
121+
context = instrumenter().start(parentContext, handlerData);
122+
scope = context.makeCurrent();
125123

126-
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
127-
public static void stopSpan(
128-
@Advice.Return(readOnly = false, typing = Typing.DYNAMIC) Object returnValue,
129-
@Advice.Thrown Throwable throwable,
130-
@Advice.Local("otelCallDepth") CallDepth callDepth,
131-
@Advice.Local("otelHandlerData") Jaxrs3HandlerData handlerData,
132-
@Advice.Local("otelContext") Context context,
133-
@Advice.Local("otelScope") Scope scope,
134-
@Advice.Local("otelAsyncResponse") AsyncResponse asyncResponse) {
135-
if (callDepth.decrementAndGet() > 0) {
136-
return;
124+
if (virtualField != null && asyncResponse != null) {
125+
virtualField.set(asyncResponse, AsyncResponseData.create(context, handlerData));
126+
}
127+
return this;
137128
}
138129

139-
if (scope == null) {
140-
return;
141-
}
130+
@Nullable
131+
public Object exit(@Nullable Object returnValue, @Nullable Throwable throwable) {
132+
if (callDepth.decrementAndGet() > 0) {
133+
return returnValue;
134+
}
135+
if (scope == null) {
136+
return returnValue;
137+
}
138+
scope.close();
142139

143-
scope.close();
140+
if (throwable != null) {
141+
instrumenter().end(context, handlerData, null, throwable);
142+
return returnValue;
143+
}
144144

145-
if (throwable != null) {
146-
instrumenter().end(context, handlerData, null, throwable);
147-
return;
145+
CompletionStage<?> asyncReturnValue =
146+
returnValue instanceof CompletionStage ? (CompletionStage<?>) returnValue : null;
147+
if (asyncReturnValue != null) {
148+
// span finished by CompletionStageFinishCallback
149+
asyncReturnValue =
150+
asyncReturnValue.handle(
151+
new CompletionStageFinishCallback<>(instrumenter(), context, handlerData));
152+
}
153+
if (asyncResponse == null && asyncReturnValue == null) {
154+
instrumenter().end(context, handlerData, null, null);
155+
}
156+
// else span finished by AsyncResponse*Advice
157+
return returnValue;
148158
}
159+
}
149160

150-
CompletionStage<?> asyncReturnValue =
151-
returnValue instanceof CompletionStage ? (CompletionStage<?>) returnValue : null;
152-
if (asyncReturnValue != null) {
153-
// span finished by CompletionStageFinishCallback
154-
asyncReturnValue =
155-
asyncReturnValue.handle(
156-
new CompletionStageFinishCallback<>(instrumenter(), context, handlerData));
157-
}
158-
if (asyncResponse == null && asyncReturnValue == null) {
159-
instrumenter().end(context, handlerData, null, null);
161+
@Advice.OnMethodEnter(suppress = Throwable.class)
162+
public static AdviceScope nameSpan(
163+
@Advice.This Object target,
164+
@Advice.Origin Method method,
165+
@Advice.AllArguments Object[] args) {
166+
AdviceScope adviceScope = new AdviceScope(CallDepth.forClass(Path.class));
167+
return adviceScope.enter(target.getClass(), method, args);
168+
}
169+
170+
@AssignReturned.ToReturned
171+
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
172+
public static Object stopSpan(
173+
@Advice.Return(typing = Typing.DYNAMIC) Object returnValue,
174+
@Advice.Thrown @Nullable Throwable throwable,
175+
@Advice.Enter @Nullable AdviceScope adviceScope) {
176+
if (adviceScope == null) {
177+
return returnValue;
160178
}
161-
// else span finished by AsyncResponse*Advice
179+
return adviceScope.exit(returnValue, throwable);
162180
}
163181
}
164182
}

instrumentation/jaxrs/jaxrs-3.0/jaxrs-3.0-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v3_0/JaxrsAnnotationsInstrumentationModule.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
import io.opentelemetry.javaagent.bootstrap.internal.ExperimentalConfig;
1313
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
1414
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
15+
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
1516
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
1617
import java.util.List;
1718
import net.bytebuddy.matcher.ElementMatcher;
1819

1920
@AutoService(InstrumentationModule.class)
20-
public class JaxrsAnnotationsInstrumentationModule extends InstrumentationModule {
21+
public class JaxrsAnnotationsInstrumentationModule extends InstrumentationModule
22+
implements ExperimentalInstrumentationModule {
2123
public JaxrsAnnotationsInstrumentationModule() {
2224
super("jaxrs", "jaxrs-3.0", "jaxrs-annotations", "jaxrs-3.0-annotations");
2325
}
@@ -44,4 +46,9 @@ public boolean defaultEnabled(ConfigProperties config) {
4446
// This instrumentation uses complex type matcher, disabling it can improve startup performance.
4547
return super.defaultEnabled(config) && ExperimentalConfig.get().controllerTelemetryEnabled();
4648
}
49+
50+
@Override
51+
public boolean isIndyReady() {
52+
return true;
53+
}
4754
}

0 commit comments

Comments
 (0)