Skip to content

Commit 0ff7fbb

Browse files
committed
jaxrs-2.0 annotations
1 parent def3f87 commit 0ff7fbb

File tree

3 files changed

+158
-109
lines changed

3 files changed

+158
-109
lines changed

instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/DefaultRequestContextInstrumentation.java

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
import io.opentelemetry.javaagent.instrumentation.jaxrs.JaxrsConstants;
1616
import io.opentelemetry.javaagent.instrumentation.jaxrs.JaxrsServerSpanNaming;
1717
import java.lang.reflect.Method;
18+
import javax.annotation.Nullable;
1819
import javax.ws.rs.container.ContainerRequestContext;
1920
import net.bytebuddy.asm.Advice;
20-
import net.bytebuddy.asm.Advice.Local;
2121

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

40+
public static class AdviceScope {
41+
private final Context context;
42+
private final Scope scope;
43+
private final Jaxrs2HandlerData handlerData;
44+
45+
private AdviceScope(Context context, Scope scope, Jaxrs2HandlerData handlerData) {
46+
this.context = context;
47+
this.scope = scope;
48+
this.handlerData = handlerData;
49+
}
50+
51+
@Nullable
52+
public static AdviceScope enter(Class<?> filterClass, Method method) {
53+
54+
Context parentContext = Java8BytecodeBridge.currentContext();
55+
Jaxrs2HandlerData handlerData = new Jaxrs2HandlerData(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+
Context context = instrumenter().start(parentContext, handlerData);
67+
return new AdviceScope(context, context.makeCurrent(), handlerData);
68+
}
69+
70+
public void end(Throwable throwable) {
71+
if (scope == null) {
72+
return;
73+
}
74+
scope.close();
75+
instrumenter().end(context, handlerData, null, throwable);
76+
}
77+
}
78+
79+
@Nullable
4080
@Advice.OnMethodEnter(suppress = Throwable.class)
41-
public static void createGenericSpan(
42-
@Advice.This ContainerRequestContext requestContext,
43-
@Local("otelHandlerData") Jaxrs2HandlerData handlerData,
44-
@Local("otelContext") Context context,
45-
@Local("otelScope") Scope scope) {
81+
public static AdviceScope createGenericSpan(
82+
@Advice.This ContainerRequestContext requestContext) {
83+
4684
if (requestContext.getProperty(JaxrsConstants.ABORT_HANDLED) != null) {
47-
return;
85+
return null;
4886
}
4987

5088
Class<?> filterClass =
5189
(Class<?>) requestContext.getProperty(JaxrsConstants.ABORT_FILTER_CLASS);
90+
if (filterClass == null) {
91+
return null;
92+
}
93+
5294
Method method = null;
5395
try {
5496
method = filterClass.getMethod("filter", ContainerRequestContext.class);
@@ -57,39 +99,20 @@ public static void createGenericSpan(
5799
// can only be aborted inside the filter method
58100
}
59101

60-
if (filterClass == null || method == null) {
61-
return;
62-
}
63-
64-
Context parentContext = Java8BytecodeBridge.currentContext();
65-
handlerData = new Jaxrs2HandlerData(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;
102+
if (method == null) {
103+
return null;
75104
}
76-
77-
context = instrumenter().start(parentContext, handlerData);
78-
scope = context.makeCurrent();
105+
return AdviceScope.enter(filterClass, method);
79106
}
80107

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

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

instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxrsAnnotationsInstrumentation.java

Lines changed: 93 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@
3030
import io.opentelemetry.javaagent.instrumentation.jaxrs.JaxrsServerSpanNaming;
3131
import java.lang.reflect.Method;
3232
import java.util.concurrent.CompletionStage;
33+
import javax.annotation.Nullable;
3334
import javax.ws.rs.Path;
3435
import javax.ws.rs.container.AsyncResponse;
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,113 @@ 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") Jaxrs2HandlerData 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+
private final CallDepth callDepth;
76+
private Jaxrs2HandlerData handlerData;
77+
private AsyncResponse asyncResponse;
78+
private Context context;
79+
private 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;
85+
public AdviceScope enter(Object[] args, Object target, Method method) {
86+
if (callDepth.getAndIncrement() > 0) {
87+
return this;
88+
}
89+
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;
100105
}
101-
break;
102106
}
103-
}
104107

105-
Context parentContext = Java8BytecodeBridge.currentContext();
106-
handlerData = new Jaxrs2HandlerData(target.getClass(), method);
108+
Context parentContext = Java8BytecodeBridge.currentContext();
109+
handlerData = new Jaxrs2HandlerData(target.getClass(), method);
107110

108-
HttpServerRoute.update(
109-
parentContext,
110-
HttpServerRouteSource.CONTROLLER,
111-
JaxrsServerSpanNaming.SERVER_SPAN_NAME,
112-
handlerData);
111+
HttpServerRoute.update(
112+
parentContext,
113+
HttpServerRouteSource.CONTROLLER,
114+
JaxrsServerSpanNaming.SERVER_SPAN_NAME,
115+
handlerData);
113116

114-
if (!instrumenter().shouldStart(parentContext, handlerData)) {
115-
return;
116-
}
117+
if (!instrumenter().shouldStart(parentContext, handlerData)) {
118+
return this;
119+
}
117120

118-
context = instrumenter().start(parentContext, handlerData);
119-
scope = context.makeCurrent();
121+
context = instrumenter().start(parentContext, handlerData);
122+
scope = context.makeCurrent();
120123

121-
if (virtualField != null && asyncResponse != null) {
122-
virtualField.set(asyncResponse, AsyncResponseData.create(context, handlerData));
124+
if (virtualField != null && asyncResponse != null) {
125+
virtualField.set(asyncResponse, AsyncResponseData.create(context, handlerData));
126+
}
127+
return this;
123128
}
124-
}
125129

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") Jaxrs2HandlerData 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;
137-
}
130+
@Nullable
131+
public Object exit(@Nullable Throwable throwable, @Nullable Object returnValue) {
138132

139-
if (scope == null) {
140-
return;
141-
}
133+
if (callDepth.decrementAndGet() > 0) {
134+
return returnValue;
135+
}
142136

143-
scope.close();
137+
if (scope == null) {
138+
return returnValue;
139+
}
144140

145-
if (throwable != null) {
146-
instrumenter().end(context, handlerData, null, throwable);
147-
return;
148-
}
141+
scope.close();
149142

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

instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_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-2.0", "jaxrs-annotations", "jaxrs-2.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)