|
21 | 21 | import io.opentelemetry.context.Scope; |
22 | 22 | import io.opentelemetry.instrumentation.api.annotation.support.async.AsyncOperationEndSupport; |
23 | 23 | import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; |
24 | | -import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; |
25 | 24 | import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; |
26 | 25 | import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; |
27 | 26 | import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; |
28 | 27 | import io.opentelemetry.javaagent.tooling.config.MethodsConfigurationParser; |
29 | 28 | import java.lang.reflect.Method; |
30 | 29 | import java.util.Map; |
31 | 30 | import java.util.Set; |
| 31 | +import javax.annotation.Nullable; |
32 | 32 | import net.bytebuddy.asm.Advice; |
| 33 | +import net.bytebuddy.asm.Advice.AssignReturned; |
33 | 34 | import net.bytebuddy.description.ByteCodeElement; |
34 | 35 | import net.bytebuddy.description.annotation.AnnotationSource; |
35 | 36 | import net.bytebuddy.description.method.MethodDescription; |
@@ -119,89 +120,117 @@ static ElementMatcher.Junction<MethodDescription> configureExcludedMethods() { |
119 | 120 | @SuppressWarnings("unused") |
120 | 121 | public static class WithSpanAdvice { |
121 | 122 |
|
122 | | - @Advice.OnMethodEnter(suppress = Throwable.class) |
123 | | - public static void onEnter( |
124 | | - @Advice.Origin Method originMethod, |
125 | | - @Advice.Local("otelMethod") Method method, |
126 | | - @Advice.Local("otelContext") Context context, |
127 | | - @Advice.Local("otelScope") Scope scope) { |
128 | | - // Every usage of @Advice.Origin Method is replaced with a call to Class.getMethod, copy it |
129 | | - // to local variable so that there would be only one call to Class.getMethod. |
130 | | - method = originMethod; |
| 123 | + public static class AdviceScope { |
| 124 | + private final Method method; |
| 125 | + private final Context context; |
| 126 | + private final Scope scope; |
| 127 | + |
| 128 | + private AdviceScope(Method method, Context context, Scope scope) { |
| 129 | + this.method = method; |
| 130 | + this.context = context; |
| 131 | + this.scope = scope; |
| 132 | + } |
131 | 133 |
|
132 | | - Instrumenter<Method, Object> instrumenter = WithSpanSingletons.instrumenter(); |
133 | | - Context current = Java8BytecodeBridge.currentContext(); |
| 134 | + @Nullable |
| 135 | + public static AdviceScope start(Method method) { |
| 136 | + Instrumenter<Method, Object> instrumenter = WithSpanSingletons.instrumenter(); |
| 137 | + Context current = Context.current(); |
| 138 | + if (!instrumenter.shouldStart(current, method)) { |
| 139 | + return null; |
| 140 | + } |
| 141 | + Context context = instrumenter.start(current, method); |
| 142 | + return new AdviceScope(method, context, context.makeCurrent()); |
| 143 | + } |
134 | 144 |
|
135 | | - if (instrumenter.shouldStart(current, method)) { |
136 | | - context = instrumenter.start(current, method); |
137 | | - scope = context.makeCurrent(); |
| 145 | + public Object end(Object returnValue, @Nullable Throwable throwable) { |
| 146 | + scope.close(); |
| 147 | + AsyncOperationEndSupport<Method, Object> operationEndSupport = |
| 148 | + AsyncOperationEndSupport.create( |
| 149 | + WithSpanSingletons.instrumenter(), Object.class, method.getReturnType()); |
| 150 | + return operationEndSupport.asyncEnd(context, method, returnValue, throwable); |
138 | 151 | } |
139 | 152 | } |
140 | 153 |
|
| 154 | + @Nullable |
| 155 | + @Advice.OnMethodEnter(suppress = Throwable.class) |
| 156 | + public static AdviceScope onEnter(@Advice.Origin Method originMethod) { |
| 157 | + // Every usage of @Advice.Origin Method is replaced with a call to Class.getMethod, copy it |
| 158 | + // to local variable so that there would be only one call to Class.getMethod. |
| 159 | + return AdviceScope.start(originMethod); |
| 160 | + } |
| 161 | + |
| 162 | + @AssignReturned.ToReturned |
141 | 163 | @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) |
142 | | - public static void stopSpan( |
143 | | - @Advice.Local("otelMethod") Method method, |
144 | | - @Advice.Local("otelContext") Context context, |
145 | | - @Advice.Local("otelScope") Scope scope, |
146 | | - @Advice.Return(typing = Assigner.Typing.DYNAMIC, readOnly = false) Object returnValue, |
147 | | - @Advice.Thrown Throwable throwable) { |
148 | | - if (scope == null) { |
149 | | - return; |
| 164 | + public static Object stopSpan( |
| 165 | + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returnValue, |
| 166 | + @Advice.Thrown @Nullable Throwable throwable, |
| 167 | + @Advice.Enter @Nullable AdviceScope adviceScope) { |
| 168 | + if (adviceScope != null) { |
| 169 | + return adviceScope.end(returnValue, throwable); |
150 | 170 | } |
151 | | - scope.close(); |
152 | | - |
153 | | - AsyncOperationEndSupport<Method, Object> operationEndSupport = |
154 | | - AsyncOperationEndSupport.create( |
155 | | - WithSpanSingletons.instrumenter(), Object.class, method.getReturnType()); |
156 | | - returnValue = operationEndSupport.asyncEnd(context, method, returnValue, throwable); |
| 171 | + return returnValue; |
157 | 172 | } |
158 | 173 | } |
159 | 174 |
|
160 | 175 | @SuppressWarnings("unused") |
161 | 176 | public static class WithSpanAttributesAdvice { |
162 | 177 |
|
| 178 | + public static class AdviceScope { |
| 179 | + private final Method method; |
| 180 | + private final MethodRequest request; |
| 181 | + private final Context context; |
| 182 | + private final Scope scope; |
| 183 | + |
| 184 | + private AdviceScope(Method method, MethodRequest request, Context context, Scope scope) { |
| 185 | + this.method = method; |
| 186 | + this.request = request; |
| 187 | + this.context = context; |
| 188 | + this.scope = scope; |
| 189 | + } |
| 190 | + |
| 191 | + @Nullable |
| 192 | + public static AdviceScope start(Method method, MethodRequest request) { |
| 193 | + Instrumenter<MethodRequest, Object> instrumenter = |
| 194 | + WithSpanSingletons.instrumenterWithAttributes(); |
| 195 | + Context current = Context.current(); |
| 196 | + if (!instrumenter.shouldStart(current, request)) { |
| 197 | + return null; |
| 198 | + } |
| 199 | + Context context = instrumenter.start(current, request); |
| 200 | + return new AdviceScope(method, request, context, context.makeCurrent()); |
| 201 | + } |
| 202 | + |
| 203 | + public Object end(@Nullable Object returnValue, @Nullable Throwable throwable) { |
| 204 | + scope.close(); |
| 205 | + AsyncOperationEndSupport<MethodRequest, Object> operationEndSupport = |
| 206 | + AsyncOperationEndSupport.create( |
| 207 | + WithSpanSingletons.instrumenterWithAttributes(), |
| 208 | + Object.class, |
| 209 | + method.getReturnType()); |
| 210 | + return operationEndSupport.asyncEnd(context, request, returnValue, throwable); |
| 211 | + } |
| 212 | + } |
| 213 | + |
163 | 214 | @Advice.OnMethodEnter(suppress = Throwable.class) |
164 | | - public static void onEnter( |
| 215 | + public static AdviceScope onEnter( |
165 | 216 | @Advice.Origin Method originMethod, |
166 | | - @Advice.Local("otelMethod") Method method, |
167 | | - @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, |
168 | | - @Advice.Local("otelRequest") MethodRequest request, |
169 | | - @Advice.Local("otelContext") Context context, |
170 | | - @Advice.Local("otelScope") Scope scope) { |
171 | | - |
| 217 | + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args) { |
172 | 218 | // Every usage of @Advice.Origin Method is replaced with a call to Class.getMethod, copy it |
173 | 219 | // to local variable so that there would be only one call to Class.getMethod. |
174 | | - method = originMethod; |
175 | | - |
176 | | - Instrumenter<MethodRequest, Object> instrumenter = |
177 | | - WithSpanSingletons.instrumenterWithAttributes(); |
178 | | - Context current = Java8BytecodeBridge.currentContext(); |
179 | | - request = new MethodRequest(method, args); |
180 | | - |
181 | | - if (instrumenter.shouldStart(current, request)) { |
182 | | - context = instrumenter.start(current, request); |
183 | | - scope = context.makeCurrent(); |
184 | | - } |
| 220 | + MethodRequest request = new MethodRequest(originMethod, args); |
| 221 | + return AdviceScope.start(originMethod, request); |
185 | 222 | } |
186 | 223 |
|
| 224 | + @AssignReturned.ToReturned |
187 | 225 | @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) |
188 | | - public static void stopSpan( |
189 | | - @Advice.Local("otelMethod") Method method, |
190 | | - @Advice.Local("otelRequest") MethodRequest request, |
191 | | - @Advice.Local("otelContext") Context context, |
192 | | - @Advice.Local("otelScope") Scope scope, |
193 | | - @Advice.Return(typing = Assigner.Typing.DYNAMIC, readOnly = false) Object returnValue, |
194 | | - @Advice.Thrown Throwable throwable) { |
195 | | - if (scope == null) { |
196 | | - return; |
| 226 | + public static Object stopSpan( |
| 227 | + @Advice.Return @Nullable Object returnValue, |
| 228 | + @Advice.Thrown Throwable throwable, |
| 229 | + @Advice.Enter AdviceScope adviceScope) { |
| 230 | + if (adviceScope != null) { |
| 231 | + return adviceScope.end(returnValue, throwable); |
197 | 232 | } |
198 | | - scope.close(); |
199 | | - AsyncOperationEndSupport<MethodRequest, Object> operationEndSupport = |
200 | | - AsyncOperationEndSupport.create( |
201 | | - WithSpanSingletons.instrumenterWithAttributes(), |
202 | | - Object.class, |
203 | | - method.getReturnType()); |
204 | | - returnValue = operationEndSupport.asyncEnd(context, request, returnValue, throwable); |
| 233 | + return returnValue; |
205 | 234 | } |
206 | 235 | } |
207 | 236 | } |
0 commit comments