Disable internal TaskScheduler spans in Spring Kafka instrumentation
Resolves
I used the same pattern we already have for suppressing the wrapping of
the Kafka consumer records lists.
MODIFY
instrumentation/spring/spring-kafka-2.7/javaagent/build.gradle.kts
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"))

RENAME
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
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);
+ }
+ }
}

MODIFY
instrumentation/spring/spring-kafka-2.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/kafka/SpringKafkaInstrumentationModule.java
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());
}
}

ADD
instrumentation/spring/spring-scheduling-3.1/bootstrap/build.gradle.kts
+plugins {
+ id("otel.javaagent-bootstrap")
+}

ADD
instrumentation/spring/spring-scheduling-3.1/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/spring/SpringSchedulingTaskTracing.java
+/*
+ * 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();
+ }
+}

MODIFY
instrumentation/spring/spring-scheduling-3.1/javaagent/build.gradle.kts
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")

MODIFY
instrumentation/spring/spring-scheduling-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/scheduling/TaskSchedulerInstrumentation.java
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) {
+ if (SpringSchedulingTaskTracing.wrappingEnabled()) {
runnable = SpringSchedulingRunnableWrapper.wrapIfNeeded(runnable);
}
}
}
+}

MODIFY
settings.gradle.kts
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")

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.