Browse Source

Disable internal TaskScheduler spans in Spring Kafka instrumentation (#7553)

Resolves #7511

I used the same pattern we already have for suppressing the wrapping of
the Kafka consumer records lists.
Mateusz Rzeszutek 2 years ago
parent
commit
30de9ff266

+ 2 - 0
instrumentation/spring/spring-kafka-2.7/javaagent/build.gradle.kts

@@ -16,12 +16,14 @@ dependencies {
   annotationProcessor("com.google.auto.value:auto-value")
 
   bootstrap(project(":instrumentation:kafka:kafka-clients:kafka-clients-0.11:bootstrap"))
+  bootstrap(project(":instrumentation:spring:spring-scheduling-3.1:bootstrap"))
   implementation(project(":instrumentation:kafka:kafka-clients:kafka-clients-common:library"))
   implementation(project(":instrumentation:spring:spring-kafka-2.7:library"))
 
   library("org.springframework.kafka:spring-kafka:2.7.0")
 
   testInstrumentation(project(":instrumentation:kafka:kafka-clients:kafka-clients-0.11:javaagent"))
+  testInstrumentation(project(":instrumentation:spring:spring-scheduling-3.1:javaagent"))
 
   testImplementation(project(":instrumentation:spring:spring-kafka-2.7:testing"))
 

+ 21 - 1
instrumentation/spring/spring-kafka-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/kafka/SuppressingKafkaClientsInstrumentation.java → instrumentation/spring/spring-kafka-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/kafka/ListenerConsumerInstrumentation.java

@@ -5,16 +5,18 @@
 
 package io.opentelemetry.javaagent.instrumentation.spring.kafka;
 
+import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
 import static net.bytebuddy.matcher.ElementMatchers.named;
 
 import io.opentelemetry.javaagent.bootstrap.kafka.KafkaClientsConsumerProcessTracing;
+import io.opentelemetry.javaagent.bootstrap.spring.SpringSchedulingTaskTracing;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
 import net.bytebuddy.asm.Advice;
 import net.bytebuddy.description.type.TypeDescription;
 import net.bytebuddy.matcher.ElementMatcher;
 
-public class SuppressingKafkaClientsInstrumentation implements TypeInstrumentation {
+public class ListenerConsumerInstrumentation implements TypeInstrumentation {
 
   @Override
   public ElementMatcher<TypeDescription> typeMatcher() {
@@ -25,11 +27,14 @@ public class SuppressingKafkaClientsInstrumentation implements TypeInstrumentati
   @Override
   public void transform(TypeTransformer transformer) {
     transformer.applyAdviceToMethod(named("run"), this.getClass().getName() + "$RunLoopAdvice");
+    transformer.applyAdviceToMethod(
+        isConstructor(), this.getClass().getName() + "$ConstructorAdvice");
   }
 
   // this advice suppresses the CONSUMER spans created by the kafka-clients instrumentation
   @SuppressWarnings("unused")
   public static class RunLoopAdvice {
+
     @Advice.OnMethodEnter(suppress = Throwable.class)
     public static boolean onEnter() {
       return KafkaClientsConsumerProcessTracing.setEnabled(false);
@@ -40,4 +45,19 @@ public class SuppressingKafkaClientsInstrumentation implements TypeInstrumentati
       KafkaClientsConsumerProcessTracing.setEnabled(previousValue);
     }
   }
+
+  // this advice suppresses the spans generated by spring scheduling instrumentation
+  @SuppressWarnings("unused")
+  public static class ConstructorAdvice {
+
+    @Advice.OnMethodEnter(suppress = Throwable.class)
+    public static boolean onEnter() {
+      return SpringSchedulingTaskTracing.setEnabled(false);
+    }
+
+    @Advice.OnMethodExit(suppress = Throwable.class)
+    public static void onExit(@Advice.Enter boolean previousValue) {
+      SpringSchedulingTaskTracing.setEnabled(previousValue);
+    }
+  }
 }

+ 1 - 1
instrumentation/spring/spring-kafka-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/kafka/SpringKafkaInstrumentationModule.java

@@ -22,6 +22,6 @@ public class SpringKafkaInstrumentationModule extends InstrumentationModule {
   public List<TypeInstrumentation> typeInstrumentations() {
     return asList(
         new AbstractMessageListenerContainerInstrumentation(),
-        new SuppressingKafkaClientsInstrumentation());
+        new ListenerConsumerInstrumentation());
   }
 }

+ 3 - 0
instrumentation/spring/spring-scheduling-3.1/bootstrap/build.gradle.kts

@@ -0,0 +1,3 @@
+plugins {
+  id("otel.javaagent-bootstrap")
+}

+ 23 - 0
instrumentation/spring/spring-scheduling-3.1/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/spring/SpringSchedulingTaskTracing.java

@@ -0,0 +1,23 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.bootstrap.spring;
+
+public final class SpringSchedulingTaskTracing {
+
+  private static final ThreadLocal<Boolean> wrappingEnabled = ThreadLocal.withInitial(() -> true);
+
+  private SpringSchedulingTaskTracing() {}
+
+  public static boolean setEnabled(boolean enabled) {
+    boolean previous = wrappingEnabled.get();
+    wrappingEnabled.set(enabled);
+    return previous;
+  }
+
+  public static boolean wrappingEnabled() {
+    return wrappingEnabled.get();
+  }
+}

+ 2 - 0
instrumentation/spring/spring-scheduling-3.1/javaagent/build.gradle.kts

@@ -12,6 +12,8 @@ muzzle {
 }
 
 dependencies {
+  bootstrap(project(":instrumentation:spring:spring-scheduling-3.1:bootstrap"))
+
   // 3.2.3 is the first version with which the tests will run. Lower versions require other
   // classes and packages to be imported. Versions 3.1.0+ work with the instrumentation.
   library("org.springframework:spring-context:3.1.0.RELEASE")

+ 4 - 1
instrumentation/spring/spring-scheduling-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/scheduling/TaskSchedulerInstrumentation.java

@@ -10,6 +10,7 @@ import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
 import static net.bytebuddy.matcher.ElementMatchers.named;
 import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
 
+import io.opentelemetry.javaagent.bootstrap.spring.SpringSchedulingTaskTracing;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
 import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
 import net.bytebuddy.asm.Advice;
@@ -34,7 +35,9 @@ public class TaskSchedulerInstrumentation implements TypeInstrumentation {
 
     @Advice.OnMethodEnter(suppress = Throwable.class)
     public static void onSchedule(@Advice.Argument(value = 0, readOnly = false) Runnable runnable) {
-      runnable = SpringSchedulingRunnableWrapper.wrapIfNeeded(runnable);
+      if (SpringSchedulingTaskTracing.wrappingEnabled()) {
+        runnable = SpringSchedulingRunnableWrapper.wrapIfNeeded(runnable);
+      }
     }
   }
 }

+ 1 - 0
settings.gradle.kts

@@ -445,6 +445,7 @@ hideFromDependabot(":instrumentation:spring:spring-kafka-2.7:library")
 hideFromDependabot(":instrumentation:spring:spring-kafka-2.7:testing")
 hideFromDependabot(":instrumentation:spring:spring-rabbit-1.0:javaagent")
 hideFromDependabot(":instrumentation:spring:spring-rmi-4.0:javaagent")
+hideFromDependabot(":instrumentation:spring:spring-scheduling-3.1:bootstrap")
 hideFromDependabot(":instrumentation:spring:spring-scheduling-3.1:javaagent")
 hideFromDependabot(":instrumentation:spring:spring-web:spring-web-3.1:javaagent")
 hideFromDependabot(":instrumentation:spring:spring-web:spring-web-3.1:library")