|
5 | 5 |
|
6 | 6 | package io.opentelemetry.javaagent.instrumentation.twilio; |
7 | 7 |
|
8 | | -import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext; |
9 | 8 | import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; |
10 | 9 | import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; |
11 | 10 | import static io.opentelemetry.javaagent.instrumentation.twilio.TwilioSingletons.instrumenter; |
|
26 | 25 | import io.opentelemetry.context.Scope; |
27 | 26 | import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; |
28 | 27 | import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; |
| 28 | +import javax.annotation.Nullable; |
29 | 29 | import net.bytebuddy.asm.Advice; |
30 | 30 | import net.bytebuddy.description.type.TypeDescription; |
31 | 31 | import net.bytebuddy.matcher.ElementMatcher; |
@@ -71,47 +71,63 @@ we found that there were certain methods declared on the base class (particularl |
71 | 71 | @SuppressWarnings("unused") |
72 | 72 | public static class TwilioClientAsyncAdvice { |
73 | 73 |
|
74 | | - /** Method entry instrumentation. */ |
75 | | - @Advice.OnMethodEnter(suppress = Throwable.class) |
76 | | - public static void methodEnter( |
77 | | - @Advice.This Object that, |
78 | | - @Advice.Origin("#m") String methodName, |
79 | | - @Advice.Local("otelContext") Context context, |
80 | | - @Advice.Local("otelScope") Scope scope, |
81 | | - @Advice.Local("otelSpanName") String spanName) { |
82 | | - Context parentContext = currentContext(); |
83 | | - spanName = spanName(that, methodName); |
84 | | - if (!instrumenter().shouldStart(parentContext, spanName)) { |
85 | | - return; |
| 74 | + public static class AdviceScope { |
| 75 | + private final Context context; |
| 76 | + private final Scope scope; |
| 77 | + private final String spanName; |
| 78 | + |
| 79 | + private AdviceScope(Context context, Scope scope, String spanName) { |
| 80 | + this.context = context; |
| 81 | + this.scope = scope; |
| 82 | + this.spanName = spanName; |
| 83 | + } |
| 84 | + |
| 85 | + @Nullable |
| 86 | + public static AdviceScope start(Object target, String methodName) { |
| 87 | + Context parentContext = Context.current(); |
| 88 | + String spanName = spanName(target, methodName); |
| 89 | + if (!instrumenter().shouldStart(parentContext, spanName)) { |
| 90 | + return null; |
| 91 | + } |
| 92 | + |
| 93 | + Context context = instrumenter().start(parentContext, spanName); |
| 94 | + context = TwilioAsyncMarker.markAsync(context); |
| 95 | + return new AdviceScope(context, context.makeCurrent(), spanName); |
| 96 | + } |
| 97 | + |
| 98 | + public void end(Throwable throwable, ListenableFuture<?> response) { |
| 99 | + scope.close(); |
| 100 | + if (throwable != null) { |
| 101 | + // There was a synchronous error, |
| 102 | + // which means we shouldn't wait for a callback to close the span. |
| 103 | + instrumenter().end(context, spanName, null, throwable); |
| 104 | + } else { |
| 105 | + // We're calling an async operation, we still need to finish the span when it's |
| 106 | + // complete and report the results; set an appropriate callback |
| 107 | + Futures.addCallback( |
| 108 | + response, |
| 109 | + new SpanFinishingCallback<>(context, spanName), |
| 110 | + Twilio.getExecutorService()); |
| 111 | + } |
86 | 112 | } |
| 113 | + } |
87 | 114 |
|
88 | | - context = instrumenter().start(parentContext, spanName); |
89 | | - context = TwilioAsyncMarker.markAsync(context); |
90 | | - scope = context.makeCurrent(); |
| 115 | + /** Method entry instrumentation. */ |
| 116 | + @Nullable |
| 117 | + @Advice.OnMethodEnter(suppress = Throwable.class) |
| 118 | + public static AdviceScope methodEnter( |
| 119 | + @Advice.This Object that, @Advice.Origin("#m") String methodName) { |
| 120 | + return AdviceScope.start(that, methodName); |
91 | 121 | } |
92 | 122 |
|
93 | 123 | /** Method exit instrumentation. */ |
94 | 124 | @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) |
95 | 125 | public static void methodExit( |
96 | | - @Advice.Thrown Throwable throwable, |
97 | | - @Advice.Return ListenableFuture<?> response, |
98 | | - @Advice.Local("otelContext") Context context, |
99 | | - @Advice.Local("otelScope") Scope scope, |
100 | | - @Advice.Local("otelSpanName") String spanName) { |
101 | | - if (scope == null) { |
102 | | - return; |
103 | | - } |
104 | | - |
105 | | - scope.close(); |
106 | | - if (throwable != null) { |
107 | | - // There was an synchronous error, |
108 | | - // which means we shouldn't wait for a callback to close the span. |
109 | | - instrumenter().end(context, spanName, null, throwable); |
110 | | - } else { |
111 | | - // We're calling an async operation, we still need to finish the span when it's |
112 | | - // complete and report the results; set an appropriate callback |
113 | | - Futures.addCallback( |
114 | | - response, new SpanFinishingCallback<>(context, spanName), Twilio.getExecutorService()); |
| 126 | + @Advice.Thrown @Nullable Throwable throwable, |
| 127 | + @Advice.Enter @Nullable AdviceScope adviceScope, |
| 128 | + @Advice.Return ListenableFuture<?> response) { |
| 129 | + if (adviceScope != null) { |
| 130 | + adviceScope.end(throwable, response); |
115 | 131 | } |
116 | 132 | } |
117 | 133 | } |
|
0 commit comments