Browse Source

Use local variable for passing CallDepth between advice enter/exit me… (#3504)

* Use local variable for passing CallDepth between advice enter/exit methods

* fix broken call depth tracking

* checkstyle

* fix javadocs
Mateusz Rzeszutek 3 years ago
parent
commit
c5ba5c3a71
30 changed files with 220 additions and 158 deletions
  1. 12 12
      instrumentation/couchbase/couchbase-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseBucketInstrumentation.java
  2. 6 6
      instrumentation/couchbase/couchbase-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClusterInstrumentation.java
  3. 9 5
      instrumentation/grpc-1.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grpc/v1_6/GrpcServerBuilderInstrumentation.java
  4. 3 3
      instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ClassLoaderInstrumentation.java
  5. 5 2
      instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxRsAnnotationsInstrumentation.java
  6. 5 2
      instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAnnotationsInstrumentation.java
  7. 5 2
      instrumentation/jaxws/jaxws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxws/v2_0/WebServiceProviderInstrumentation.java
  8. 5 2
      instrumentation/jaxws/jws-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxws/jws/v1_1/JwsAnnotationsInstrumentation.java
  9. 5 2
      instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java
  10. 5 2
      instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java
  11. 10 6
      instrumentation/jms-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jms/JmsMessageProducerInstrumentation.java
  12. 43 41
      instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/NettyChannelPipelineInstrumentation.java
  13. 6 6
      instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/NettyChannelPipelineInstrumentation.java
  14. 8 6
      instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/NettyChannelPipelineInstrumentation.java
  15. 6 5
      instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3Instrumentation.java
  16. 11 10
      instrumentation/rabbitmq-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rabbitmq/RabbitChannelInstrumentation.java
  17. 7 4
      instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/HttpClientInstrumentation.java
  18. 7 4
      instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/HttpClientInstrumentation.java
  19. 5 3
      instrumentation/rmi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rmi/server/RemoteServerInstrumentation.java
  20. 3 2
      instrumentation/servlet/servlet-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v2_2/HttpServletResponseInstrumentation.java
  21. 7 3
      instrumentation/servlet/servlet-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v2_2/Servlet2Advice.java
  22. 8 5
      instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/AsyncDispatchAdvice.java
  23. 5 1
      instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/Servlet3Advice.java
  24. 7 5
      instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/Servlet3AsyncStartAdvice.java
  25. 8 5
      instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/async/AsyncDispatchAdvice.java
  26. 6 6
      instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/async/AsyncStartAdvice.java
  27. 5 1
      instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/service/JakartaServletServiceAdvice.java
  28. 0 2
      instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/common/response/HttpServletResponseAdviceHelper.java
  29. 3 3
      instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/common/service/ServletAndFilterAdviceHelper.java
  30. 5 2
      instrumentation/spring/spring-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/ws/AnnotatedMethodInstrumentation.java

+ 12 - 12
instrumentation/couchbase/couchbase-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseBucketInstrumentation.java

@@ -45,20 +45,20 @@ public class CouchbaseBucketInstrumentation implements TypeInstrumentation {
   public static class CouchbaseClientAdvice {
 
     @Advice.OnMethodEnter
-    public static int trackCallDepth() {
-      return CallDepth.forClass(CouchbaseCluster.class).getAndIncrement();
+    public static void trackCallDepth(@Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth = CallDepth.forClass(CouchbaseCluster.class);
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void subscribeResult(
-        @Advice.Enter int callDepth,
         @Advice.Origin Method method,
         @Advice.FieldValue("bucket") String bucket,
-        @Advice.Return(readOnly = false) Observable<?> result) {
-      if (callDepth > 0) {
+        @Advice.Return(readOnly = false) Observable<?> result,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      if (callDepth.decrementAndGet() > 0) {
         return;
       }
-      CallDepth.forClass(CouchbaseCluster.class).reset();
       result = Observable.create(CouchbaseOnSubscribe.create(result, bucket, method));
     }
   }
@@ -67,21 +67,21 @@ public class CouchbaseBucketInstrumentation implements TypeInstrumentation {
   public static class CouchbaseClientQueryAdvice {
 
     @Advice.OnMethodEnter
-    public static int trackCallDepth() {
-      return CallDepth.forClass(CouchbaseCluster.class).getAndIncrement();
+    public static void trackCallDepth(@Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth = CallDepth.forClass(CouchbaseCluster.class);
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class)
     public static void subscribeResult(
-        @Advice.Enter int callDepth,
         @Advice.Origin Method method,
         @Advice.FieldValue("bucket") String bucket,
         @Advice.Argument(value = 0, optional = true) Object query,
-        @Advice.Return(readOnly = false) Observable<?> result) {
-      if (callDepth > 0) {
+        @Advice.Return(readOnly = false) Observable<?> result,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      if (callDepth.decrementAndGet() > 0) {
         return;
       }
-      CallDepth.forClass(CouchbaseCluster.class).reset();
 
       if (query != null) {
         // A query can be of many different types. We could track the creation of them and try to

+ 6 - 6
instrumentation/couchbase/couchbase-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClusterInstrumentation.java

@@ -42,19 +42,19 @@ public class CouchbaseClusterInstrumentation implements TypeInstrumentation {
   public static class CouchbaseClientAdvice {
 
     @Advice.OnMethodEnter
-    public static int trackCallDepth() {
-      return CallDepth.forClass(CouchbaseCluster.class).getAndIncrement();
+    public static void trackCallDepth(@Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth = CallDepth.forClass(CouchbaseCluster.class);
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void subscribeResult(
-        @Advice.Enter int callDepth,
         @Advice.Origin Method method,
-        @Advice.Return(readOnly = false) Observable<?> result) {
-      if (callDepth > 0) {
+        @Advice.Return(readOnly = false) Observable<?> result,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      if (callDepth.decrementAndGet() > 0) {
         return;
       }
-      CallDepth.forClass(CouchbaseCluster.class).reset();
 
       result = Observable.create(CouchbaseOnSubscribe.create(result, null, method));
     }

+ 9 - 5
instrumentation/grpc-1.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grpc/v1_6/GrpcServerBuilderInstrumentation.java

@@ -43,16 +43,20 @@ public class GrpcServerBuilderInstrumentation implements TypeInstrumentation {
   public static class BuildAdvice {
 
     @Advice.OnMethodEnter(suppress = Throwable.class)
-    public static void onEnter(@Advice.This ServerBuilder<?> serverBuilder) {
-      int callDepth = CallDepth.forClass(ServerBuilder.class).getAndIncrement();
-      if (callDepth == 0) {
+    public static void onEnter(
+        @Advice.This ServerBuilder<?> serverBuilder,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth = CallDepth.forClass(ServerBuilder.class);
+      if (callDepth.getAndIncrement() == 0) {
         serverBuilder.intercept(GrpcSingletons.SERVER_INTERCEPTOR);
       }
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
-    public static void onExit(@Advice.This ServerBuilder<?> serverBuilder) {
-      CallDepth.forClass(ServerBuilder.class).decrementAndGet();
+    public static void onExit(
+        @Advice.This ServerBuilder<?> serverBuilder,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth.decrementAndGet();
     }
   }
 }

+ 3 - 3
instrumentation/internal/internal-class-loader/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/internal/classloader/ClassLoaderInstrumentation.java

@@ -107,8 +107,8 @@ public class ClassLoaderInstrumentation implements TypeInstrumentation {
       // because on some JVMs (e.g. IBM's, though IBM bootstrap loader is explicitly excluded above)
       // Class.forName() ends up calling loadClass() on the bootstrap loader which would then come
       // back to this instrumentation over and over, causing a StackOverflowError
-      int callDepth = CallDepth.forClass(ClassLoader.class).getAndIncrement();
-      if (callDepth > 0) {
+      CallDepth callDepth = CallDepth.forClass(ClassLoader.class);
+      if (callDepth.getAndIncrement() > 0) {
         return null;
       }
 
@@ -128,7 +128,7 @@ public class ClassLoaderInstrumentation implements TypeInstrumentation {
         // ends up calling a ClassFileTransformer which ends up calling loadClass() further down the
         // stack on one of our bootstrap packages (since the call depth check would then suppress
         // the nested loadClass instrumentation)
-        CallDepth.forClass(ClassLoader.class).reset();
+        callDepth.reset();
       }
       return null;
     }

+ 5 - 2
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxRsAnnotationsInstrumentation.java

@@ -65,9 +65,11 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
     public static void nameSpan(
         @Advice.This Object target,
         @Advice.Origin Method method,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
-      if (CallDepth.forClass(Path.class).getAndIncrement() > 0) {
+      callDepth = CallDepth.forClass(Path.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
       context = tracer().startSpan(target.getClass(), method);
@@ -77,12 +79,13 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
       if (scope == null) {
         return;
       }
-      CallDepth.forClass(Path.class).reset();
+      callDepth.reset();
 
       scope.close();
       if (throwable == null) {

+ 5 - 2
instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v2_0/JaxRsAnnotationsInstrumentation.java

@@ -71,6 +71,7 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
         @Advice.This Object target,
         @Advice.Origin Method method,
         @Advice.AllArguments Object[] args,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope,
         @Advice.Local("otelAsyncResponse") AsyncResponse asyncResponse) {
@@ -92,7 +93,8 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
         }
       }
 
-      if (CallDepth.forClass(Path.class).getAndIncrement() > 0) {
+      callDepth = CallDepth.forClass(Path.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
 
@@ -109,13 +111,14 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
     public static void stopSpan(
         @Advice.Return(readOnly = false, typing = Typing.DYNAMIC) Object returnValue,
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope,
         @Advice.Local("otelAsyncResponse") AsyncResponse asyncResponse) {
       if (context == null || scope == null) {
         return;
       }
-      CallDepth.forClass(Path.class).reset();
+      callDepth.reset();
 
       if (throwable != null) {
         tracer().endExceptionally(context, throwable);

+ 5 - 2
instrumentation/jaxws/jaxws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxws/v2_0/WebServiceProviderInstrumentation.java

@@ -51,9 +51,11 @@ public class WebServiceProviderInstrumentation implements TypeInstrumentation {
     public static void startSpan(
         @Advice.This Object target,
         @Advice.Origin Method method,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
-      if (CallDepth.forClass(Provider.class).getAndIncrement() > 0) {
+      callDepth = CallDepth.forClass(Provider.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
       context = tracer().startSpan(target.getClass(), method);
@@ -63,12 +65,13 @@ public class WebServiceProviderInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
       if (scope == null) {
         return;
       }
-      CallDepth.forClass(Provider.class).reset();
+      callDepth.reset();
 
       scope.close();
       if (throwable == null) {

+ 5 - 2
instrumentation/jaxws/jws-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxws/jws/v1_1/JwsAnnotationsInstrumentation.java

@@ -62,9 +62,11 @@ public class JwsAnnotationsInstrumentation implements TypeInstrumentation {
     public static void startSpan(
         @Advice.This Object target,
         @Advice.Origin Method method,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
-      if (CallDepth.forClass(WebService.class).getAndIncrement() > 0) {
+      callDepth = CallDepth.forClass(WebService.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
       context = tracer().startSpan(target.getClass(), method);
@@ -74,12 +76,13 @@ public class JwsAnnotationsInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
       if (scope == null) {
         return;
       }
-      CallDepth.forClass(WebService.class).reset();
+      callDepth.reset();
 
       scope.close();
       if (throwable == null) {

+ 5 - 2
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java

@@ -51,6 +51,7 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodEnter(suppress = Throwable.class)
     public static void onEnter(
         @Advice.This PreparedStatement statement,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelRequest") DbRequest request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
@@ -61,7 +62,8 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation {
       // using CallDepth prevents this, because this check happens before Connection#getMetadata()
       // is called - the first recursive Statement call is just skipped and we do not create a span
       // for it
-      if (CallDepth.forClass(Statement.class).getAndIncrement() > 0) {
+      callDepth = CallDepth.forClass(Statement.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
 
@@ -79,13 +81,14 @@ public class PreparedStatementInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelRequest") DbRequest request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
       if (scope == null) {
         return;
       }
-      CallDepth.forClass(Statement.class).reset();
+      callDepth.reset();
 
       scope.close();
       instrumenter().end(context, request, null, throwable);

+ 5 - 2
instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java

@@ -51,6 +51,7 @@ public class StatementInstrumentation implements TypeInstrumentation {
     public static void onEnter(
         @Advice.Argument(0) String sql,
         @Advice.This Statement statement,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelRequest") DbRequest request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
@@ -61,7 +62,8 @@ public class StatementInstrumentation implements TypeInstrumentation {
       // using CallDepth prevents this, because this check happens before Connection#getMetadata()
       // is called - the first recursive Statement call is just skipped and we do not create a span
       // for it
-      if (CallDepth.forClass(Statement.class).getAndIncrement() > 0) {
+      callDepth = CallDepth.forClass(Statement.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
 
@@ -79,13 +81,14 @@ public class StatementInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelRequest") DbRequest request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
       if (scope == null) {
         return;
       }
-      CallDepth.forClass(Statement.class).reset();
+      callDepth.reset();
 
       scope.close();
       instrumenter().end(context, request, null, throwable);

+ 10 - 6
instrumentation/jms-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jms/JmsMessageProducerInstrumentation.java

@@ -59,11 +59,12 @@ public class JmsMessageProducerInstrumentation implements TypeInstrumentation {
     public static void onEnter(
         @Advice.Argument(0) Message message,
         @Advice.This MessageProducer producer,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelRequest") MessageWithDestination request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
-      int callDepth = CallDepth.forClass(MessageProducer.class).getAndIncrement();
-      if (callDepth > 0) {
+      callDepth = CallDepth.forClass(MessageProducer.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
 
@@ -86,6 +87,7 @@ public class JmsMessageProducerInstrumentation implements TypeInstrumentation {
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelRequest") MessageWithDestination request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope,
@@ -93,7 +95,7 @@ public class JmsMessageProducerInstrumentation implements TypeInstrumentation {
       if (scope == null) {
         return;
       }
-      CallDepth.forClass(MessageProducer.class).reset();
+      callDepth.reset();
 
       scope.close();
       producerInstrumenter().end(context, request, null, throwable);
@@ -107,11 +109,12 @@ public class JmsMessageProducerInstrumentation implements TypeInstrumentation {
     public static void onEnter(
         @Advice.Argument(0) Destination destination,
         @Advice.Argument(1) Message message,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelRequest") MessageWithDestination request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
-      int callDepth = CallDepth.forClass(MessageProducer.class).getAndIncrement();
-      if (callDepth > 0) {
+      callDepth = CallDepth.forClass(MessageProducer.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
 
@@ -127,6 +130,7 @@ public class JmsMessageProducerInstrumentation implements TypeInstrumentation {
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelRequest") MessageWithDestination request,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope,
@@ -134,7 +138,7 @@ public class JmsMessageProducerInstrumentation implements TypeInstrumentation {
       if (scope == null) {
         return;
       }
-      CallDepth.forClass(MessageProducer.class).reset();
+      callDepth.reset();
 
       scope.close();
       producerInstrumenter().end(context, request, null, throwable);

+ 43 - 41
instrumentation/netty/netty-3.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v3_8/NettyChannelPipelineInstrumentation.java

@@ -72,35 +72,31 @@ public class NettyChannelPipelineInstrumentation implements TypeInstrumentation
         ContextStore<Channel, ChannelTraceContext> contextStore,
         ChannelPipeline pipeline,
         ChannelHandler handler) {
-      try {
-        // Server pipeline handlers
-        if (handler instanceof HttpServerCodec) {
-          pipeline.addLast(
-              HttpServerTracingHandler.class.getName(), new HttpServerTracingHandler(contextStore));
-        } else if (handler instanceof HttpRequestDecoder) {
-          pipeline.addLast(
-              HttpServerRequestTracingHandler.class.getName(),
-              new HttpServerRequestTracingHandler(contextStore));
-        } else if (handler instanceof HttpResponseEncoder) {
-          pipeline.addLast(
-              HttpServerResponseTracingHandler.class.getName(),
-              new HttpServerResponseTracingHandler(contextStore));
-        } else
-        // Client pipeline handlers
-        if (handler instanceof HttpClientCodec) {
-          pipeline.addLast(
-              HttpClientTracingHandler.class.getName(), new HttpClientTracingHandler(contextStore));
-        } else if (handler instanceof HttpRequestEncoder) {
-          pipeline.addLast(
-              HttpClientRequestTracingHandler.class.getName(),
-              new HttpClientRequestTracingHandler(contextStore));
-        } else if (handler instanceof HttpResponseDecoder) {
-          pipeline.addLast(
-              HttpClientResponseTracingHandler.class.getName(),
-              new HttpClientResponseTracingHandler(contextStore));
-        }
-      } finally {
-        CallDepth.forClass(ChannelPipeline.class).reset();
+      // Server pipeline handlers
+      if (handler instanceof HttpServerCodec) {
+        pipeline.addLast(
+            HttpServerTracingHandler.class.getName(), new HttpServerTracingHandler(contextStore));
+      } else if (handler instanceof HttpRequestDecoder) {
+        pipeline.addLast(
+            HttpServerRequestTracingHandler.class.getName(),
+            new HttpServerRequestTracingHandler(contextStore));
+      } else if (handler instanceof HttpResponseEncoder) {
+        pipeline.addLast(
+            HttpServerResponseTracingHandler.class.getName(),
+            new HttpServerResponseTracingHandler(contextStore));
+      } else
+      // Client pipeline handlers
+      if (handler instanceof HttpClientCodec) {
+        pipeline.addLast(
+            HttpClientTracingHandler.class.getName(), new HttpClientTracingHandler(contextStore));
+      } else if (handler instanceof HttpRequestEncoder) {
+        pipeline.addLast(
+            HttpClientRequestTracingHandler.class.getName(),
+            new HttpClientRequestTracingHandler(contextStore));
+      } else if (handler instanceof HttpResponseDecoder) {
+        pipeline.addLast(
+            HttpClientResponseTracingHandler.class.getName(),
+            new HttpClientResponseTracingHandler(contextStore));
       }
     }
   }
@@ -109,23 +105,26 @@ public class NettyChannelPipelineInstrumentation implements TypeInstrumentation
   public static class ChannelPipelineAdd2ArgsAdvice {
 
     @Advice.OnMethodEnter
-    public static int checkDepth(
-        @Advice.This ChannelPipeline pipeline, @Advice.Argument(1) ChannelHandler handler) {
+    public static void checkDepth(
+        @Advice.This ChannelPipeline pipeline,
+        @Advice.Argument(1) ChannelHandler handler,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
       // Pipelines are created once as a factory and then copied multiple times using the same add
       // methods as we are hooking. If our handler has already been added we need to remove it so we
       // don't end up with duplicates (this throws an exception)
       if (pipeline.get(handler.getClass().getName()) != null) {
         pipeline.remove(handler.getClass().getName());
       }
-      return CallDepth.forClass(ChannelPipeline.class).getAndIncrement();
+      callDepth = CallDepth.forClass(ChannelPipeline.class);
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void addHandler(
-        @Advice.Enter int depth,
         @Advice.This ChannelPipeline pipeline,
-        @Advice.Argument(1) ChannelHandler handler) {
-      if (depth > 0) {
+        @Advice.Argument(1) ChannelHandler handler,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      if (callDepth.decrementAndGet() > 0) {
         return;
       }
 
@@ -140,23 +139,26 @@ public class NettyChannelPipelineInstrumentation implements TypeInstrumentation
   public static class ChannelPipelineAdd3ArgsAdvice {
 
     @Advice.OnMethodEnter
-    public static int checkDepth(
-        @Advice.This ChannelPipeline pipeline, @Advice.Argument(2) ChannelHandler handler) {
+    public static void checkDepth(
+        @Advice.This ChannelPipeline pipeline,
+        @Advice.Argument(2) ChannelHandler handler,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
       // Pipelines are created once as a factory and then copied multiple times using the same add
       // methods as we are hooking. If our handler has already been added we need to remove it so we
       // don't end up with duplicates (this throws an exception)
       if (pipeline.get(handler.getClass().getName()) != null) {
         pipeline.remove(handler.getClass().getName());
       }
-      return CallDepth.forClass(ChannelPipeline.class).getAndIncrement();
+      callDepth = CallDepth.forClass(ChannelPipeline.class);
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void addHandler(
-        @Advice.Enter int depth,
         @Advice.This ChannelPipeline pipeline,
-        @Advice.Argument(2) ChannelHandler handler) {
-      if (depth > 0) {
+        @Advice.Argument(2) ChannelHandler handler,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      if (callDepth.decrementAndGet() > 0) {
         return;
       }
 

+ 6 - 6
instrumentation/netty/netty-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_0/NettyChannelPipelineInstrumentation.java

@@ -60,19 +60,19 @@ public class NettyChannelPipelineInstrumentation
   public static class ChannelPipelineAddAdvice {
 
     @Advice.OnMethodEnter
-    public static int trackCallDepth() {
-      return CallDepth.forClass(ChannelPipeline.class).getAndIncrement();
+    public static void trackCallDepth(@Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth = CallDepth.forClass(ChannelPipeline.class);
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void addHandler(
-        @Advice.Enter int callDepth,
         @Advice.This ChannelPipeline pipeline,
-        @Advice.Argument(2) ChannelHandler handler) {
-      if (callDepth > 0) {
+        @Advice.Argument(2) ChannelHandler handler,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      if (callDepth.decrementAndGet() > 0) {
         return;
       }
-      CallDepth.forClass(ChannelPipeline.class).reset();
 
       ChannelHandler ourHandler = null;
       // Server pipeline handlers

+ 8 - 6
instrumentation/netty/netty-4.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/v4_1/NettyChannelPipelineInstrumentation.java

@@ -63,7 +63,9 @@ public class NettyChannelPipelineInstrumentation
   public static class ChannelPipelineAddAdvice {
 
     @Advice.OnMethodEnter
-    public static int trackCallDepth(@Advice.Argument(2) ChannelHandler handler) {
+    public static void trackCallDepth(
+        @Advice.Argument(2) ChannelHandler handler,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
       // Previously we used one unique call depth tracker for all handlers, using
       // ChannelPipeline.class as a key.
       // The problem with this approach is that it does not work with netty's
@@ -73,19 +75,19 @@ public class NettyChannelPipelineInstrumentation
       // Using the specific handler key instead of the generic ChannelPipeline.class will help us
       // both to handle such cases and avoid adding our additional handlers in case of internal
       // calls of `addLast` to other method overloads with a compatible signature.
-      return CallDepth.forClass(handler.getClass()).getAndIncrement();
+      callDepth = CallDepth.forClass(handler.getClass());
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void addHandler(
-        @Advice.Enter int callDepth,
         @Advice.This ChannelPipeline pipeline,
         @Advice.Argument(1) String handlerName,
-        @Advice.Argument(2) ChannelHandler handler) {
-      if (callDepth > 0) {
+        @Advice.Argument(2) ChannelHandler handler,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      if (callDepth.decrementAndGet() > 0) {
         return;
       }
-      CallDepth.forClass(handler.getClass()).reset();
 
       String name = handlerName;
       if (name == null) {

+ 6 - 5
instrumentation/okhttp/okhttp-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/okhttp/v3_0/OkHttp3Instrumentation.java

@@ -32,19 +32,20 @@ public class OkHttp3Instrumentation implements TypeInstrumentation {
   public static class ConstructorAdvice {
 
     @Advice.OnMethodEnter(suppress = Throwable.class)
-    public static void trackCallDepth(@Advice.Local("callDepth") int callDepth) {
-      callDepth = CallDepth.forClass(OkHttpClient.Builder.class).getAndIncrement();
+    public static void trackCallDepth(@Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth = CallDepth.forClass(OkHttpClient.Builder.class);
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(suppress = Throwable.class)
     public static void addTracingInterceptor(
-        @Advice.This OkHttpClient.Builder builder, @Advice.Local("callDepth") int callDepth) {
+        @Advice.This OkHttpClient.Builder builder,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
       // No-args constructor is automatically called by constructors with args, but we only want to
       // run once from the constructor with args because that is where the dedupe needs to happen.
-      if (callDepth > 0) {
+      if (callDepth.decrementAndGet() > 0) {
         return;
       }
-      CallDepth.forClass(OkHttpClient.Builder.class).reset();
       if (builder.interceptors().contains(OkHttp3Interceptors.TRACING_INTERCEPTOR)) {
         return;
       }

+ 11 - 10
instrumentation/rabbitmq-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rabbitmq/RabbitChannelInstrumentation.java

@@ -92,10 +92,11 @@ public class RabbitChannelInstrumentation implements TypeInstrumentation {
     public static void onEnter(
         @Advice.This Channel channel,
         @Advice.Origin("Channel.#m") String method,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
-      int callDepth = CallDepth.forClass(Channel.class).getAndIncrement();
-      if (callDepth > 0) {
+      callDepth = CallDepth.forClass(Channel.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
 
@@ -107,13 +108,14 @@ public class RabbitChannelInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
       if (scope == null) {
         return;
       }
       scope.close();
-      CallDepth.forClass(Channel.class).reset();
+      callDepth.reset();
 
       CURRENT_RABBIT_CONTEXT.remove();
       if (throwable != null) {
@@ -179,9 +181,9 @@ public class RabbitChannelInstrumentation implements TypeInstrumentation {
   public static class ChannelGetAdvice {
 
     @Advice.OnMethodEnter
-    public static long takeTimestamp(@Advice.Local("callDepth") int callDepth) {
-
-      callDepth = CallDepth.forClass(Channel.class).getAndIncrement();
+    public static long takeTimestamp(@Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth = CallDepth.forClass(Channel.class);
+      callDepth.getAndIncrement();
       return System.currentTimeMillis();
     }
 
@@ -190,13 +192,12 @@ public class RabbitChannelInstrumentation implements TypeInstrumentation {
         @Advice.This Channel channel,
         @Advice.Argument(0) String queue,
         @Advice.Enter long startTime,
-        @Advice.Local("callDepth") int callDepth,
         @Advice.Return GetResponse response,
-        @Advice.Thrown Throwable throwable) {
-      if (callDepth > 0) {
+        @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
+      if (callDepth.decrementAndGet() > 0) {
         return;
       }
-      CallDepth.forClass(Channel.class).reset();
 
       // can't create span and put into scope in method enter above, because can't add parent after
       // span creation

+ 7 - 4
instrumentation/reactor-netty/reactor-netty-0.9/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v0_9/HttpClientInstrumentation.java

@@ -74,15 +74,18 @@ public class HttpClientInstrumentation implements TypeInstrumentation {
   public static class CreateAdvice {
 
     @Advice.OnMethodEnter(suppress = Throwable.class)
-    public static void onEnter() {
-      CallDepth.forClass(HttpClient.class).getAndIncrement();
+    public static void onEnter(@Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth = CallDepth.forClass(HttpClient.class);
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
-        @Advice.Thrown Throwable throwable, @Advice.Return(readOnly = false) HttpClient client) {
+        @Advice.Thrown Throwable throwable,
+        @Advice.Return(readOnly = false) HttpClient client,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
 
-      if (CallDepth.forClass(HttpClient.class).decrementAndGet() == 0 && throwable == null) {
+      if (callDepth.decrementAndGet() == 0 && throwable == null) {
         client = client.doOnRequest(new OnRequest()).mapConnect(new MapConnect());
       }
     }

+ 7 - 4
instrumentation/reactor-netty/reactor-netty-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/reactornetty/v1_0/HttpClientInstrumentation.java

@@ -74,15 +74,18 @@ public class HttpClientInstrumentation implements TypeInstrumentation {
   public static class CreateAdvice {
 
     @Advice.OnMethodEnter(suppress = Throwable.class)
-    public static void onEnter() {
-      CallDepth.forClass(HttpClient.class).getAndIncrement();
+    public static void onEnter(@Advice.Local("otelCallDepth") CallDepth callDepth) {
+      callDepth = CallDepth.forClass(HttpClient.class);
+      callDepth.getAndIncrement();
     }
 
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
-        @Advice.Thrown Throwable throwable, @Advice.Return(readOnly = false) HttpClient client) {
+        @Advice.Thrown Throwable throwable,
+        @Advice.Return(readOnly = false) HttpClient client,
+        @Advice.Local("otelCallDepth") CallDepth callDepth) {
 
-      if (CallDepth.forClass(HttpClient.class).decrementAndGet() == 0 && throwable == null) {
+      if (callDepth.decrementAndGet() == 0 && throwable == null) {
         client = client.doOnRequest(new OnRequest()).mapConnect(new MapConnect());
       }
     }

+ 5 - 3
instrumentation/rmi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rmi/server/RemoteServerInstrumentation.java

@@ -44,10 +44,11 @@ public class RemoteServerInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodEnter(suppress = Throwable.class)
     public static void onEnter(
         @Advice.Origin Method method,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
-      int callDepth = CallDepth.forClass(RemoteServer.class).getAndIncrement();
-      if (callDepth > 0) {
+      callDepth = CallDepth.forClass(RemoteServer.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
 
@@ -61,14 +62,15 @@ public class RemoteServerInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
       if (scope == null) {
         return;
       }
       scope.close();
+      callDepth.reset();
 
-      CallDepth.forClass(RemoteServer.class).reset();
       if (throwable != null) {
         RmiServerTracer.tracer().endExceptionally(context, throwable);
       } else {

+ 3 - 2
instrumentation/servlet/servlet-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v2_2/HttpServletResponseInstrumentation.java

@@ -14,6 +14,7 @@ import io.opentelemetry.context.Context;
 import io.opentelemetry.context.Scope;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
+import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
 import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
@@ -30,8 +31,8 @@ import net.bytebuddy.matcher.ElementMatcher;
  *
  * <p>This instrumentation intercepts status setting methods from Servlet 2.0 specification and
  * stores that status into context store. Then {@link Servlet2Advice#stopSpan(ServletRequest,
- * ServletResponse, Throwable, Context, Scope)} can get it from context and set required span
- * attribute.
+ * ServletResponse, Throwable, CallDepth, Context, Scope)} can get it from context and set required
+ * span attribute.
  */
 public class HttpServletResponseInstrumentation implements TypeInstrumentation {
   @Override

+ 7 - 3
instrumentation/servlet/servlet-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v2_2/Servlet2Advice.java

@@ -28,9 +28,11 @@ public class Servlet2Advice {
   public static void onEnter(
       @Advice.Argument(0) ServletRequest request,
       @Advice.Argument(value = 1, typing = Assigner.Typing.DYNAMIC) ServletResponse response,
+      @Advice.Local("otelCallDepth") CallDepth callDepth,
       @Advice.Local("otelContext") Context context,
       @Advice.Local("otelScope") Scope scope) {
-    CallDepth.forClass(AppServerBridge.getCallDepthKey()).getAndIncrement();
+    callDepth = CallDepth.forClass(AppServerBridge.getCallDepthKey());
+    callDepth.getAndIncrement();
 
     if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
       return;
@@ -60,15 +62,17 @@ public class Servlet2Advice {
       @Advice.Argument(0) ServletRequest request,
       @Advice.Argument(1) ServletResponse response,
       @Advice.Thrown Throwable throwable,
+      @Advice.Local("otelCallDepth") CallDepth callDepth,
       @Advice.Local("otelContext") Context context,
       @Advice.Local("otelScope") Scope scope) {
-    int callDepth = CallDepth.forClass(AppServerBridge.getCallDepthKey()).decrementAndGet();
+
+    callDepth.decrementAndGet();
 
     if (scope != null) {
       scope.close();
     }
 
-    if (context == null && callDepth == 0) {
+    if (context == null && callDepth.get() == 0) {
       Context currentContext = Java8BytecodeBridge.currentContext();
       // Something else is managing the context, we're in the outermost level of Servlet
       // instrumentation and we have an uncaught throwable. Let's add it to the current span.

+ 8 - 5
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/AsyncDispatchAdvice.java

@@ -20,9 +20,11 @@ public class AsyncDispatchAdvice {
 
   @Advice.OnMethodEnter(suppress = Throwable.class)
   public static boolean enter(
-      @Advice.This AsyncContext context, @Advice.AllArguments Object[] args) {
-    int depth = CallDepth.forClass(AsyncContext.class).getAndIncrement();
-    if (depth > 0) {
+      @Advice.This AsyncContext context,
+      @Advice.AllArguments Object[] args,
+      @Advice.Local("otelCallDepth") CallDepth callDepth) {
+    callDepth = CallDepth.forClass(AsyncContext.class);
+    if (callDepth.getAndIncrement() > 0) {
       return false;
     }
 
@@ -45,9 +47,10 @@ public class AsyncDispatchAdvice {
   }
 
   @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
-  public static void exit(@Advice.Enter boolean topLevel) {
+  public static void exit(
+      @Advice.Enter boolean topLevel, @Advice.Local("otelCallDepth") CallDepth callDepth) {
     if (topLevel) {
-      CallDepth.forClass(AsyncContext.class).reset();
+      callDepth.reset();
     }
   }
 }

+ 5 - 1
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/Servlet3Advice.java

@@ -33,9 +33,11 @@ public class Servlet3Advice {
       @Advice.This(typing = Assigner.Typing.DYNAMIC) Object servletOrFilter,
       @Advice.Argument(value = 0, readOnly = false) ServletRequest request,
       @Advice.Argument(value = 1, readOnly = false) ServletResponse response,
+      @Advice.Local("otelCallDepth") CallDepth callDepth,
       @Advice.Local("otelContext") Context context,
       @Advice.Local("otelScope") Scope scope) {
-    CallDepth.forClass(AppServerBridge.getCallDepthKey()).getAndIncrement();
+    callDepth = CallDepth.forClass(AppServerBridge.getCallDepthKey());
+    callDepth.getAndIncrement();
     if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
       return;
     }
@@ -91,6 +93,7 @@ public class Servlet3Advice {
       @Advice.Argument(0) ServletRequest request,
       @Advice.Argument(1) ServletResponse response,
       @Advice.Thrown Throwable throwable,
+      @Advice.Local("otelCallDepth") CallDepth callDepth,
       @Advice.Local("otelContext") Context context,
       @Advice.Local("otelScope") Scope scope) {
 
@@ -103,6 +106,7 @@ public class Servlet3Advice {
         (HttpServletRequest) request,
         (HttpServletResponse) response,
         throwable,
+        callDepth,
         context,
         scope);
   }

+ 7 - 5
instrumentation/servlet/servlet-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v3_0/Servlet3AsyncStartAdvice.java

@@ -17,16 +17,18 @@ import net.bytebuddy.asm.Advice;
 public class Servlet3AsyncStartAdvice {
 
   @Advice.OnMethodEnter(suppress = Throwable.class)
-  public static void startAsyncEnter() {
+  public static void startAsyncEnter(@Advice.Local("otelCallDepth") CallDepth callDepth) {
     // This allows to detect the outermost invocation of startAsync in method exit
-    CallDepth.forClass(AsyncContext.class).getAndIncrement();
+    callDepth = CallDepth.forClass(AsyncContext.class);
+    callDepth.getAndIncrement();
   }
 
   @Advice.OnMethodExit(suppress = Throwable.class)
-  public static void startAsyncExit(@Advice.This ServletRequest servletRequest) {
-    int callDepth = CallDepth.forClass(AsyncContext.class).decrementAndGet();
+  public static void startAsyncExit(
+      @Advice.This ServletRequest servletRequest,
+      @Advice.Local("otelCallDepth") CallDepth callDepth) {
 
-    if (callDepth != 0) {
+    if (callDepth.decrementAndGet() != 0) {
       // This is not the outermost invocation, ignore.
       return;
     }

+ 8 - 5
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/async/AsyncDispatchAdvice.java

@@ -20,9 +20,11 @@ public class AsyncDispatchAdvice {
 
   @Advice.OnMethodEnter(suppress = Throwable.class)
   public static boolean enter(
-      @Advice.This AsyncContext context, @Advice.AllArguments Object[] args) {
-    int depth = CallDepth.forClass(AsyncContext.class).getAndIncrement();
-    if (depth > 0) {
+      @Advice.This AsyncContext context,
+      @Advice.AllArguments Object[] args,
+      @Advice.Local("otelCallDepth") CallDepth callDepth) {
+    callDepth = CallDepth.forClass(AsyncContext.class);
+    if (callDepth.getAndIncrement() > 0) {
       return false;
     }
 
@@ -45,9 +47,10 @@ public class AsyncDispatchAdvice {
   }
 
   @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
-  public static void exit(@Advice.Enter boolean topLevel) {
+  public static void exit(
+      @Advice.Enter boolean topLevel, @Advice.Local("otelCallDepth") CallDepth callDepth) {
     if (topLevel) {
-      CallDepth.forClass(AsyncContext.class).reset();
+      callDepth.reset();
     }
   }
 }

+ 6 - 6
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/async/AsyncStartAdvice.java

@@ -17,18 +17,18 @@ import net.bytebuddy.implementation.bytecode.assign.Assigner;
 public class AsyncStartAdvice {
 
   @Advice.OnMethodEnter(suppress = Throwable.class)
-  public static void startAsyncEnter() {
+  public static void startAsyncEnter(@Advice.Local("otelCallDepth") CallDepth callDepth) {
     // This allows to detect the outermost invocation of startAsync in method exit
-    CallDepth.forClass(AsyncContext.class).getAndIncrement();
+    callDepth = CallDepth.forClass(AsyncContext.class);
+    callDepth.getAndIncrement();
   }
 
   @Advice.OnMethodExit(suppress = Throwable.class)
   public static void startAsyncExit(
-      @Advice.This(typing = Assigner.Typing.DYNAMIC) HttpServletRequest request) {
+      @Advice.This(typing = Assigner.Typing.DYNAMIC) HttpServletRequest request,
+      @Advice.Local("otelCallDepth") CallDepth callDepth) {
 
-    int callDepth = CallDepth.forClass(AsyncContext.class).decrementAndGet();
-
-    if (callDepth != 0) {
+    if (callDepth.decrementAndGet() != 0) {
       // This is not the outermost invocation, ignore.
       return;
     }

+ 5 - 1
instrumentation/servlet/servlet-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/v5_0/service/JakartaServletServiceAdvice.java

@@ -33,10 +33,12 @@ public class JakartaServletServiceAdvice {
       @Advice.This(typing = Assigner.Typing.DYNAMIC) Object servletOrFilter,
       @Advice.Argument(value = 0, readOnly = false) ServletRequest request,
       @Advice.Argument(value = 1, readOnly = false) ServletResponse response,
+      @Advice.Local("otelCallDepth") CallDepth callDepth,
       @Advice.Local("otelContext") Context context,
       @Advice.Local("otelScope") Scope scope) {
 
-    CallDepth.forClass(AppServerBridge.getCallDepthKey()).getAndIncrement();
+    callDepth = CallDepth.forClass(AppServerBridge.getCallDepthKey());
+    callDepth.getAndIncrement();
     if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
       return;
     }
@@ -92,6 +94,7 @@ public class JakartaServletServiceAdvice {
       @Advice.Argument(0) ServletRequest request,
       @Advice.Argument(1) ServletResponse response,
       @Advice.Thrown Throwable throwable,
+      @Advice.Local("otelCallDepth") CallDepth callDepth,
       @Advice.Local("otelContext") Context context,
       @Advice.Local("otelScope") Scope scope) {
     if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
@@ -103,6 +106,7 @@ public class JakartaServletServiceAdvice {
         (HttpServletRequest) request,
         (HttpServletResponse) response,
         throwable,
+        callDepth,
         context,
         scope);
   }

+ 0 - 2
instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/common/response/HttpServletResponseAdviceHelper.java

@@ -14,8 +14,6 @@ public class HttpServletResponseAdviceHelper {
   public static void stopSpan(
       BaseTracer tracer, Throwable throwable, Context context, Scope scope, CallDepth callDepth) {
     if (callDepth.decrementAndGet() == 0 && context != null) {
-      callDepth.reset();
-
       scope.close();
 
       if (throwable != null) {

+ 3 - 3
instrumentation/servlet/servlet-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/servlet/common/service/ServletAndFilterAdviceHelper.java

@@ -7,7 +7,6 @@ package io.opentelemetry.javaagent.instrumentation.servlet.common.service;
 
 import io.opentelemetry.context.Context;
 import io.opentelemetry.context.Scope;
-import io.opentelemetry.instrumentation.api.servlet.AppServerBridge;
 import io.opentelemetry.instrumentation.servlet.ServletHttpServerTracer;
 import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
 import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
@@ -18,15 +17,16 @@ public class ServletAndFilterAdviceHelper {
       REQUEST request,
       RESPONSE response,
       Throwable throwable,
+      CallDepth callDepth,
       Context context,
       Scope scope) {
-    int callDepth = CallDepth.forClass(AppServerBridge.getCallDepthKey()).decrementAndGet();
+    callDepth.decrementAndGet();
 
     if (scope != null) {
       scope.close();
     }
 
-    if (context == null && callDepth == 0) {
+    if (context == null && callDepth.get() == 0) {
       Context currentContext = Java8BytecodeBridge.currentContext();
       // Something else is managing the context, we're in the outermost level of Servlet
       // instrumentation and we have an uncaught throwable. Let's add it to the current span.

+ 5 - 2
instrumentation/spring/spring-ws-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/ws/AnnotatedMethodInstrumentation.java

@@ -54,9 +54,11 @@ public class AnnotatedMethodInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodEnter(suppress = Throwable.class)
     public static void startSpan(
         @Advice.Origin Method method,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
-      if (CallDepth.forClass(PayloadRoot.class).getAndIncrement() > 0) {
+      callDepth = CallDepth.forClass(PayloadRoot.class);
+      if (callDepth.getAndIncrement() > 0) {
         return;
       }
       context = tracer().startSpan(method);
@@ -66,12 +68,13 @@ public class AnnotatedMethodInstrumentation implements TypeInstrumentation {
     @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
     public static void stopSpan(
         @Advice.Thrown Throwable throwable,
+        @Advice.Local("otelCallDepth") CallDepth callDepth,
         @Advice.Local("otelContext") Context context,
         @Advice.Local("otelScope") Scope scope) {
       if (scope == null) {
         return;
       }
-      CallDepth.forClass(PayloadRoot.class).reset();
+      callDepth.reset();
 
       scope.close();
       if (throwable == null) {