|
23 | 23 | import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; |
24 | 24 | import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; |
25 | 25 | import io.opentelemetry.javaagent.instrumentation.spring.webmvc.IsGrailsHandler; |
| 26 | +import javax.annotation.Nullable; |
26 | 27 | import javax.servlet.http.HttpServletRequest; |
27 | 28 | import net.bytebuddy.asm.Advice; |
28 | 29 | import net.bytebuddy.description.type.TypeDescription; |
@@ -54,49 +55,61 @@ public void transform(TypeTransformer transformer) { |
54 | 55 | @SuppressWarnings("unused") |
55 | 56 | public static class ControllerAdvice { |
56 | 57 |
|
| 58 | + public static class AdviceScope { |
| 59 | + private final Context context; |
| 60 | + private final Scope scope; |
| 61 | + |
| 62 | + public AdviceScope(Context context, Scope scope) { |
| 63 | + this.context = context; |
| 64 | + this.scope = scope; |
| 65 | + } |
| 66 | + |
| 67 | + public void exit(Object handler, @Nullable Throwable throwable) { |
| 68 | + scope.close(); |
| 69 | + handlerInstrumenter().end(context, handler, null, throwable); |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + @Nullable |
57 | 74 | @Advice.OnMethodEnter(suppress = Throwable.class) |
58 | | - public static void nameResourceAndStartSpan( |
59 | | - @Advice.Argument(0) HttpServletRequest request, |
60 | | - @Advice.Argument(2) Object handler, |
61 | | - @Advice.Local("otelContext") Context context, |
62 | | - @Advice.Local("otelScope") Scope scope) { |
| 75 | + public static AdviceScope nameResourceAndStartSpan( |
| 76 | + @Advice.Argument(0) HttpServletRequest request, @Advice.Argument(2) Object handler) { |
| 77 | + |
63 | 78 | // TODO (trask) should there be a way to customize Instrumenter.shouldStart()? |
64 | 79 | if (IsGrailsHandler.isGrailsHandler(handler)) { |
65 | 80 | // skip creating handler span for grails, grails instrumentation will take care of it |
66 | | - return; |
| 81 | + return null; |
67 | 82 | } |
68 | 83 |
|
69 | 84 | Context parentContext = Java8BytecodeBridge.currentContext(); |
70 | 85 |
|
71 | 86 | // don't start a new top-level span |
72 | 87 | if (!Java8BytecodeBridge.spanFromContext(parentContext).getSpanContext().isValid()) { |
73 | | - return; |
| 88 | + return null; |
74 | 89 | } |
75 | 90 |
|
76 | 91 | // Name the parent span based on the matching pattern |
77 | 92 | HttpServerRoute.update( |
78 | 93 | parentContext, CONTROLLER, SpringWebMvcServerSpanNaming.SERVER_SPAN_NAME, request); |
79 | 94 |
|
80 | 95 | if (!handlerInstrumenter().shouldStart(parentContext, handler)) { |
81 | | - return; |
| 96 | + return null; |
82 | 97 | } |
83 | 98 |
|
84 | 99 | // Now create a span for handler/controller execution. |
85 | | - context = handlerInstrumenter().start(parentContext, handler); |
86 | | - scope = context.makeCurrent(); |
| 100 | + Context context = handlerInstrumenter().start(parentContext, handler); |
| 101 | + return new AdviceScope(context, context.makeCurrent()); |
87 | 102 | } |
88 | 103 |
|
89 | 104 | @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) |
90 | 105 | public static void stopSpan( |
91 | 106 | @Advice.Argument(2) Object handler, |
92 | | - @Advice.Thrown Throwable throwable, |
93 | | - @Advice.Local("otelContext") Context context, |
94 | | - @Advice.Local("otelScope") Scope scope) { |
95 | | - if (scope == null) { |
96 | | - return; |
| 107 | + @Advice.Thrown @Nullable Throwable throwable, |
| 108 | + @Advice.Enter @Nullable AdviceScope adviceScope) { |
| 109 | + |
| 110 | + if (adviceScope != null) { |
| 111 | + adviceScope.exit(handler, throwable); |
97 | 112 | } |
98 | | - scope.close(); |
99 | | - handlerInstrumenter().end(context, handler, null, throwable); |
100 | 113 | } |
101 | 114 | } |
102 | 115 | } |
0 commit comments