From 35c7678faf1047526ff5373899e77c1201050fe8 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 21 Jan 2022 12:52:37 +0200 Subject: [PATCH 01/10] kotlinx-coroutines-reactor context propagation --- .../javaagent/build.gradle.kts | 1 + ...KotlinCoroutinesInstrumentationModule.java | 9 ++- .../KotlinCoroutinesFluxInstrumentation.java | 43 ++++++++++++++ .../KotlinCoroutinesMonoInstrumentation.java | 43 ++++++++++++++ .../KotlinCoroutineInstrumentationTest.groovy | 56 +++++++++++++++++++ .../src/test/kotlin/KotlinCoroutineTests.kt | 20 +++++++ 6 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesFluxInstrumentation.java create mode 100644 instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesMonoInstrumentation.java diff --git a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts index 95e72f360382..64c09a0be735 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts +++ b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts @@ -26,6 +26,7 @@ dependencies { testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") // Use first version with flow support since we have tests for it. testLibrary("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0") + testLibrary("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.3.0") } tasks { diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java index c5727635527b..2f35b5125e68 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java @@ -5,11 +5,13 @@ package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines; -import static java.util.Collections.singletonList; +import static java.util.Arrays.asList; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor.KotlinCoroutinesFluxInstrumentation; +import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor.KotlinCoroutinesMonoInstrumentation; import java.util.List; @AutoService(InstrumentationModule.class) @@ -26,6 +28,9 @@ public boolean isHelperClass(String className) { @Override public List typeInstrumentations() { - return singletonList(new KotlinCoroutinesInstrumentation()); + return asList( + new KotlinCoroutinesInstrumentation(), + new KotlinCoroutinesMonoInstrumentation(), + new KotlinCoroutinesFluxInstrumentation()); } } diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesFluxInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesFluxInstrumentation.java new file mode 100644 index 000000000000..24bbdf26a149 --- /dev/null +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesFluxInstrumentation.java @@ -0,0 +1,43 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.KotlinCoroutinesInstrumentationHelper; +import kotlin.coroutines.CoroutineContext; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class KotlinCoroutinesFluxInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("kotlinx.coroutines.reactor.FluxKt"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + namedOneOf("flux").and(takesArgument(0, named("kotlin.coroutines.CoroutineContext"))), + this.getClass().getName() + "$FluxAdvice"); + } + + @SuppressWarnings("unused") + public static class FluxAdvice { + + @Advice.OnMethodEnter + public static void enter( + @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext) { + coroutineContext = + KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); + } + } +} diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesMonoInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesMonoInstrumentation.java new file mode 100644 index 000000000000..a56fbbb1b742 --- /dev/null +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesMonoInstrumentation.java @@ -0,0 +1,43 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.KotlinCoroutinesInstrumentationHelper; +import kotlin.coroutines.CoroutineContext; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class KotlinCoroutinesMonoInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return named("kotlinx.coroutines.reactor.MonoKt"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + namedOneOf("mono").and(takesArgument(0, named("kotlin.coroutines.CoroutineContext"))), + this.getClass().getName() + "$MonoAdvice"); + } + + @SuppressWarnings("unused") + public static class MonoAdvice { + + @Advice.OnMethodEnter + public static void enter( + @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext) { + coroutineContext = + KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); + } + } +} diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/test/groovy/KotlinCoroutineInstrumentationTest.groovy b/instrumentation/kotlinx-coroutines/javaagent/src/test/groovy/KotlinCoroutineInstrumentationTest.groovy index fcf9ce792675..3e845ae0d086 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/test/groovy/KotlinCoroutineInstrumentationTest.groovy +++ b/instrumentation/kotlinx-coroutines/javaagent/src/test/groovy/KotlinCoroutineInstrumentationTest.groovy @@ -225,4 +225,60 @@ class KotlinCoroutineInstrumentationTest extends AgentInstrumentationSpecificati assert seenItersA.equals(expectedIters) assert seenItersB.equals(expectedIters) } + + def "kotlin traced mono"() { + setup: + KotlinCoroutineTests kotlinTest = new KotlinCoroutineTests(dispatcher) + + when: + kotlinTest.tracedMono() + + then: + assertTraces(1) { + trace(0, 2) { + span(0) { + name "parent" + attributes { + } + } + span("child") { + childOf span(0) + attributes { + } + } + } + } + + where: + dispatcher << dispatchersToTest + } + + def "kotlin traced flux"() { + setup: + KotlinCoroutineTests kotlinTest = new KotlinCoroutineTests(dispatcher) + + when: + kotlinTest.tracedFlux() + + then: + assertTraces(1) { + trace(0, 4) { + span(0) { + name "parent" + attributes { + } + } + (0..2).each { + span("child_$it") { + childOf span(0) + attributes { + } + } + } + } + } + + where: + dispatcher << dispatchersToTest + } } diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt b/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt index 8e511908bd65..770fd6038af8 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt +++ b/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt @@ -19,6 +19,10 @@ import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import kotlinx.coroutines.reactive.awaitSingle +import kotlinx.coroutines.reactive.collect +import kotlinx.coroutines.reactor.flux +import kotlinx.coroutines.reactor.mono import kotlinx.coroutines.runBlocking import kotlinx.coroutines.selects.select import kotlinx.coroutines.withContext @@ -125,6 +129,22 @@ class KotlinCoroutineTests(private val dispatcher: CoroutineDispatcher) { } } + fun tracedMono(): Unit = runTest { + mono(dispatcher) { + tracedChild("child") + }.awaitSingle() + } + + fun tracedFlux() = runTest { + flux(dispatcher) { + repeat(3) { + tracedChild("child_$it") + send(it) + } + }.collect { + } + } + fun launchConcurrentSuspendFunctions(numIters: Int) { runBlocking { for (i in 0 until numIters) { From 6ca2ff6849a4e634d3b2d3424c2c819ca05465b1 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Mon, 24 Jan 2022 23:35:34 +0200 Subject: [PATCH 02/10] extract context from reactor --- .../javaagent/build.gradle.kts | 7 ++- ...KotlinCoroutinesInstrumentationModule.java | 9 +-- .../KotlinCoroutinesMonoInstrumentation.java | 43 -------------- ...oroutinesReactorInstrumentationModule.java | 32 ++++++++++ ...> KotlinMonoCoroutineInstrumentation.java} | 24 ++++++-- ...tlinPublisherCoroutineInstrumentation.java | 59 +++++++++++++++++++ 6 files changed, 115 insertions(+), 59 deletions(-) delete mode 100644 instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesMonoInstrumentation.java create mode 100644 instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesReactorInstrumentationModule.java rename instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/{KotlinCoroutinesFluxInstrumentation.java => KotlinMonoCoroutineInstrumentation.java} (55%) create mode 100644 instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java diff --git a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts index 64c09a0be735..12f032ec0499 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts +++ b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts @@ -21,12 +21,13 @@ muzzle { dependencies { compileOnly("io.opentelemetry:opentelemetry-extension-kotlin") compileOnly("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + // Use first version with flow support since we have tests for it. + library("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0") + library("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.3.0") + implementation(project(":instrumentation:reactor:reactor-3.1:library")) testImplementation("io.opentelemetry:opentelemetry-extension-kotlin") testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - // Use first version with flow support since we have tests for it. - testLibrary("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0") - testLibrary("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.3.0") } tasks { diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java index 2f35b5125e68..c5727635527b 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java @@ -5,13 +5,11 @@ package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines; -import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor.KotlinCoroutinesFluxInstrumentation; -import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor.KotlinCoroutinesMonoInstrumentation; import java.util.List; @AutoService(InstrumentationModule.class) @@ -28,9 +26,6 @@ public boolean isHelperClass(String className) { @Override public List typeInstrumentations() { - return asList( - new KotlinCoroutinesInstrumentation(), - new KotlinCoroutinesMonoInstrumentation(), - new KotlinCoroutinesFluxInstrumentation()); + return singletonList(new KotlinCoroutinesInstrumentation()); } } diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesMonoInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesMonoInstrumentation.java deleted file mode 100644 index a56fbbb1b742..000000000000 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesMonoInstrumentation.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor; - -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; - -import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.KotlinCoroutinesInstrumentationHelper; -import kotlin.coroutines.CoroutineContext; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; - -public class KotlinCoroutinesMonoInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("kotlinx.coroutines.reactor.MonoKt"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - namedOneOf("mono").and(takesArgument(0, named("kotlin.coroutines.CoroutineContext"))), - this.getClass().getName() + "$MonoAdvice"); - } - - @SuppressWarnings("unused") - public static class MonoAdvice { - - @Advice.OnMethodEnter - public static void enter( - @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext) { - coroutineContext = - KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); - } - } -} diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesReactorInstrumentationModule.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesReactorInstrumentationModule.java new file mode 100644 index 000000000000..52340dd061f9 --- /dev/null +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesReactorInstrumentationModule.java @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor; + +import static java.util.Arrays.asList; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; + +@AutoService(InstrumentationModule.class) +public class KotlinCoroutinesReactorInstrumentationModule extends InstrumentationModule { + + public KotlinCoroutinesReactorInstrumentationModule() { + super("kotlinx-coroutines", "kotlinx-coroutines-reactor"); + } + + @Override + public boolean isHelperClass(String className) { + return className.startsWith("io.opentelemetry.extension.kotlin."); + } + + @Override + public List typeInstrumentations() { + return asList( + new KotlinMonoCoroutineInstrumentation(), new KotlinPublisherCoroutineInstrumentation()); + } +} diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesFluxInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java similarity index 55% rename from instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesFluxInstrumentation.java rename to instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java index 24bbdf26a149..b6b52f30fc81 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesFluxInstrumentation.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java @@ -5,37 +5,49 @@ package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.reactor.ContextPropagationOperator; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.KotlinCoroutinesInstrumentationHelper; import kotlin.coroutines.CoroutineContext; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import reactor.core.publisher.MonoSink; -public class KotlinCoroutinesFluxInstrumentation implements TypeInstrumentation { +public class KotlinMonoCoroutineInstrumentation implements TypeInstrumentation { @Override public ElementMatcher typeMatcher() { - return named("kotlinx.coroutines.reactor.FluxKt"); + return namedOneOf("kotlinx.coroutines.reactor.MonoCoroutine"); } @Override public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( - namedOneOf("flux").and(takesArgument(0, named("kotlin.coroutines.CoroutineContext"))), - this.getClass().getName() + "$FluxAdvice"); + isConstructor() + .and( + takesArgument(0, named("kotlin.coroutines.CoroutineContext")) + .and(takesArgument(1, named("reactor.core.publisher.MonoSink")))), + this.getClass().getName() + "$MonoCoroutineAdvice"); } @SuppressWarnings("unused") - public static class FluxAdvice { + public static class MonoCoroutineAdvice { @Advice.OnMethodEnter public static void enter( - @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext) { + @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext, + @Advice.Argument(1) MonoSink monoSink) { + Context context = + ContextPropagationOperator.getOpenTelemetryContext( + monoSink.currentContext(), Java8BytecodeBridge.currentContext()); coroutineContext = KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); } diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java new file mode 100644 index 000000000000..b3a641259186 --- /dev/null +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java @@ -0,0 +1,59 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor; + +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.reactor.ContextPropagationOperator; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; +import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.KotlinCoroutinesInstrumentationHelper; +import kotlin.coroutines.CoroutineContext; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.reactivestreams.Subscriber; +import reactor.core.CoreSubscriber; + +public class KotlinPublisherCoroutineInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher typeMatcher() { + return namedOneOf("kotlinx.coroutines.reactive.PublisherCoroutine"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor() + .and( + takesArgument(0, named("kotlin.coroutines.CoroutineContext")) + .and(takesArgument(1, named("org.reactivestreams.Subscriber")))), + this.getClass().getName() + "$PublisherCoroutineAdvice"); + } + + @SuppressWarnings("unused") + public static class PublisherCoroutineAdvice { + + @Advice.OnMethodEnter + public static void enter( + @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext, + @Advice.Argument(1) Subscriber subscriber) { + if (subscriber instanceof CoreSubscriber) { + CoreSubscriber coreSubscriber = (CoreSubscriber) subscriber; + Context context = + ContextPropagationOperator.getOpenTelemetryContext( + coreSubscriber.currentContext(), Java8BytecodeBridge.currentContext()); + coroutineContext = + KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); + } + } + } +} From fb8ca35acdf34d3ba22540eaba4c3728cfa9b25d Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Mon, 24 Jan 2022 23:53:58 +0200 Subject: [PATCH 03/10] add generics --- .../reactor/KotlinMonoCoroutineInstrumentation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java index b6b52f30fc81..f6e6661a5432 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java @@ -44,7 +44,7 @@ public static class MonoCoroutineAdvice { @Advice.OnMethodEnter public static void enter( @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext, - @Advice.Argument(1) MonoSink monoSink) { + @Advice.Argument(1) MonoSink monoSink) { Context context = ContextPropagationOperator.getOpenTelemetryContext( monoSink.currentContext(), Java8BytecodeBridge.currentContext()); From 4cfedc4084e65a82241a7cd18246712d4913640f Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 25 Jan 2022 00:59:26 +0200 Subject: [PATCH 04/10] muzzle --- instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts index 12f032ec0499..c63c2341399d 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts +++ b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts @@ -10,12 +10,16 @@ muzzle { group.set("org.jetbrains.kotlinx") module.set("kotlinx-coroutines-core") versions.set("[1.0.0,1.3.8)") + extraDependency("io.projectreactor:reactor-core:3.1.10.RELEASE") + extraDependency("org.reactivestreams:reactive-streams:1.0.2") } // 1.3.9 (and beyond?) have changed how artifact names are resolved due to multiplatform variants pass { group.set("org.jetbrains.kotlinx") module.set("kotlinx-coroutines-core-jvm") versions.set("[1.3.9,)") + extraDependency("io.projectreactor:reactor-core:3.1.10.RELEASE") + extraDependency("org.reactivestreams:reactive-streams:1.0.2") } } dependencies { From 5a2585c8b3b275e54e7f730fb4cfc13f1582ccca Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 25 Jan 2022 13:47:20 +0200 Subject: [PATCH 05/10] actually use the context extracted from reactor --- .../KotlinCoroutinesInstrumentationHelper.java | 9 +++++++-- .../reactor/KotlinMonoCoroutineInstrumentation.java | 2 +- .../reactor/KotlinPublisherCoroutineInstrumentation.java | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationHelper.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationHelper.java index 0f5f8e3a085e..c03869c96297 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationHelper.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationHelper.java @@ -13,11 +13,16 @@ public final class KotlinCoroutinesInstrumentationHelper { public static CoroutineContext addOpenTelemetryContext(CoroutineContext coroutineContext) { Context current = Context.current(); + return addOpenTelemetryContext(coroutineContext, current); + } + + public static CoroutineContext addOpenTelemetryContext( + CoroutineContext coroutineContext, Context otelContext) { Context inCoroutine = ContextExtensionsKt.getOpenTelemetryContext(coroutineContext); - if (current == inCoroutine) { + if (otelContext == inCoroutine) { return coroutineContext; } - return coroutineContext.plus(ContextExtensionsKt.asContextElement(current)); + return coroutineContext.plus(ContextExtensionsKt.asContextElement(otelContext)); } private KotlinCoroutinesInstrumentationHelper() {} diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java index f6e6661a5432..7fd95407c843 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java @@ -49,7 +49,7 @@ public static void enter( ContextPropagationOperator.getOpenTelemetryContext( monoSink.currentContext(), Java8BytecodeBridge.currentContext()); coroutineContext = - KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); + KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext, context); } } } diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java index b3a641259186..a095eba2474c 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java @@ -52,7 +52,8 @@ public static void enter( ContextPropagationOperator.getOpenTelemetryContext( coreSubscriber.currentContext(), Java8BytecodeBridge.currentContext()); coroutineContext = - KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); + KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext( + coroutineContext, context); } } } From a6438c6fd2a6242a8a7e27b8a32312a683b55e20 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 25 Jan 2022 15:25:20 +0200 Subject: [PATCH 06/10] test context propagation operator --- .../javaagent/build.gradle.kts | 3 +++ .../KotlinCoroutineInstrumentationTest.groovy | 27 +++++++++++++++++++ .../src/test/kotlin/KotlinCoroutineTests.kt | 19 +++++++++++++ 3 files changed, 49 insertions(+) diff --git a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts index c63c2341399d..a54d1b0cddf3 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts +++ b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts @@ -22,6 +22,7 @@ muzzle { extraDependency("org.reactivestreams:reactive-streams:1.0.2") } } + dependencies { compileOnly("io.opentelemetry:opentelemetry-extension-kotlin") compileOnly("org.jetbrains.kotlin:kotlin-stdlib-jdk8") @@ -30,6 +31,8 @@ dependencies { library("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.3.0") implementation(project(":instrumentation:reactor:reactor-3.1:library")) + testInstrumentation(project(":instrumentation:reactor:reactor-3.1:javaagent")) + testImplementation("io.opentelemetry:opentelemetry-extension-kotlin") testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") } diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/test/groovy/KotlinCoroutineInstrumentationTest.groovy b/instrumentation/kotlinx-coroutines/javaagent/src/test/groovy/KotlinCoroutineInstrumentationTest.groovy index 3e845ae0d086..8ab030cf46be 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/test/groovy/KotlinCoroutineInstrumentationTest.groovy +++ b/instrumentation/kotlinx-coroutines/javaagent/src/test/groovy/KotlinCoroutineInstrumentationTest.groovy @@ -253,6 +253,33 @@ class KotlinCoroutineInstrumentationTest extends AgentInstrumentationSpecificati dispatcher << dispatchersToTest } + def "kotlin traced mono with context propagation operator"() { + setup: + KotlinCoroutineTests kotlinTest = new KotlinCoroutineTests(dispatcher) + + when: + kotlinTest.tracedMonoContextPropagationOperator() + + then: + assertTraces(1) { + trace(0, 2) { + span(0) { + name "parent" + attributes { + } + } + span("child") { + childOf span(0) + attributes { + } + } + } + } + + where: + dispatcher << dispatchersToTest + } + def "kotlin traced flux"() { setup: KotlinCoroutineTests kotlinTest = new KotlinCoroutineTests(dispatcher) diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt b/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt index 770fd6038af8..d8f63db5069c 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt +++ b/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt @@ -5,7 +5,9 @@ import io.opentelemetry.api.GlobalOpenTelemetry import io.opentelemetry.api.trace.Tracer +import io.opentelemetry.context.Context import io.opentelemetry.extension.kotlin.asContextElement +import io.opentelemetry.instrumentation.reactor.ContextPropagationOperator import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope @@ -21,6 +23,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactive.collect +import kotlinx.coroutines.reactor.ReactorContext import kotlinx.coroutines.reactor.flux import kotlinx.coroutines.reactor.mono import kotlinx.coroutines.runBlocking @@ -135,6 +138,22 @@ class KotlinCoroutineTests(private val dispatcher: CoroutineDispatcher) { }.awaitSingle() } + fun tracedMonoContextPropagationOperator(): Unit = runTest { + val currentContext = Context.current() + // clear current context to ensure that ContextPropagationOperator is used for context propagation + withContext(Context.root().asContextElement()) { + val mono = mono(dispatcher) { + // extract context from reactor and propagate it coroutine + val reactorContext = coroutineContext[ReactorContext.Key]?.context + val otelContext = ContextPropagationOperator.getOpenTelemetryContext(reactorContext, Context.current()) + withContext(otelContext.asContextElement()) { + tracedChild("child") + } + } + ContextPropagationOperator.runWithContext(mono, currentContext).awaitSingle() + } + } + fun tracedFlux() = runTest { flux(dispatcher) { repeat(3) { From a4f4b0b09ad8a73ce37ebc7aa9ec63a9bb0bd4fb Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 25 Jan 2022 16:50:52 +0200 Subject: [PATCH 07/10] typo --- .../javaagent/src/test/kotlin/KotlinCoroutineTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt b/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt index d8f63db5069c..4afd2e48c67c 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt +++ b/instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt @@ -143,7 +143,7 @@ class KotlinCoroutineTests(private val dispatcher: CoroutineDispatcher) { // clear current context to ensure that ContextPropagationOperator is used for context propagation withContext(Context.root().asContextElement()) { val mono = mono(dispatcher) { - // extract context from reactor and propagate it coroutine + // extract context from reactor and propagate it into coroutine val reactorContext = coroutineContext[ReactorContext.Key]?.context val otelContext = ContextPropagationOperator.getOpenTelemetryContext(reactorContext, Context.current()) withContext(otelContext.asContextElement()) { From cbb096fa7ed43373d8fbaff14faf61cb7838e74d Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 25 Jan 2022 18:35:38 +0200 Subject: [PATCH 08/10] used named instead of namedOneOf --- .../reactor/KotlinMonoCoroutineInstrumentation.java | 3 +-- .../reactor/KotlinPublisherCoroutineInstrumentation.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java index 7fd95407c843..2e2f935faa27 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java @@ -7,7 +7,6 @@ import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import io.opentelemetry.context.Context; @@ -25,7 +24,7 @@ public class KotlinMonoCoroutineInstrumentation implements TypeInstrumentation { @Override public ElementMatcher typeMatcher() { - return namedOneOf("kotlinx.coroutines.reactor.MonoCoroutine"); + return named("kotlinx.coroutines.reactor.MonoCoroutine"); } @Override diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java index a095eba2474c..28cb64e5de16 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java @@ -7,7 +7,6 @@ import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import io.opentelemetry.context.Context; @@ -26,7 +25,7 @@ public class KotlinPublisherCoroutineInstrumentation implements TypeInstrumentation { @Override public ElementMatcher typeMatcher() { - return namedOneOf("kotlinx.coroutines.reactive.PublisherCoroutine"); + return named("kotlinx.coroutines.reactive.PublisherCoroutine"); } @Override From 45e82393ab527fdc47810c649facf50bebf545c7 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 27 Jan 2022 19:58:46 +0200 Subject: [PATCH 09/10] instrument newCoroutineContext, remove reactor specific code --- .../javaagent/build.gradle.kts | 13 ++-- .../KotlinCoroutinesInstrumentation.java | 30 +++------- ...oroutinesReactorInstrumentationModule.java | 32 ---------- .../KotlinMonoCoroutineInstrumentation.java | 54 ----------------- ...tlinPublisherCoroutineInstrumentation.java | 59 ------------------- 5 files changed, 13 insertions(+), 175 deletions(-) delete mode 100644 instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesReactorInstrumentationModule.java delete mode 100644 instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java delete mode 100644 instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java diff --git a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts index a54d1b0cddf3..2a4293ad9f9f 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts +++ b/instrumentation/kotlinx-coroutines/javaagent/build.gradle.kts @@ -10,31 +10,28 @@ muzzle { group.set("org.jetbrains.kotlinx") module.set("kotlinx-coroutines-core") versions.set("[1.0.0,1.3.8)") - extraDependency("io.projectreactor:reactor-core:3.1.10.RELEASE") - extraDependency("org.reactivestreams:reactive-streams:1.0.2") } // 1.3.9 (and beyond?) have changed how artifact names are resolved due to multiplatform variants pass { group.set("org.jetbrains.kotlinx") module.set("kotlinx-coroutines-core-jvm") versions.set("[1.3.9,)") - extraDependency("io.projectreactor:reactor-core:3.1.10.RELEASE") - extraDependency("org.reactivestreams:reactive-streams:1.0.2") } } dependencies { compileOnly("io.opentelemetry:opentelemetry-extension-kotlin") compileOnly("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - // Use first version with flow support since we have tests for it. - library("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0") - library("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.3.0") - implementation(project(":instrumentation:reactor:reactor-3.1:library")) testInstrumentation(project(":instrumentation:reactor:reactor-3.1:javaagent")) testImplementation("io.opentelemetry:opentelemetry-extension-kotlin") testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + testImplementation(project(":instrumentation:reactor:reactor-3.1:library")) + + // Use first version with flow support since we have tests for it. + testLibrary("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0") + testLibrary("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.3.0") } tasks { diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentation.java index ae1134a6ea9e..9910a0c53503 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentation.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentation.java @@ -6,7 +6,6 @@ package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; @@ -19,40 +18,27 @@ public class KotlinCoroutinesInstrumentation implements TypeInstrumentation { @Override public ElementMatcher typeMatcher() { - return named("kotlinx.coroutines.BuildersKt"); + return named("kotlinx.coroutines.CoroutineContextKt"); } @Override public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( - namedOneOf("launch", "launch$default") + named("newCoroutineContext") .and(takesArgument(1, named("kotlin.coroutines.CoroutineContext"))), - this.getClass().getName() + "$LaunchAdvice"); - transformer.applyAdviceToMethod( - namedOneOf("runBlocking", "runBlocking$default") - .and(takesArgument(0, named("kotlin.coroutines.CoroutineContext"))), - this.getClass().getName() + "$RunBlockingAdvice"); + this.getClass().getName() + "$ContextAdvice"); } @SuppressWarnings("unused") - public static class LaunchAdvice { + public static class ContextAdvice { @Advice.OnMethodEnter public static void enter( @Advice.Argument(value = 1, readOnly = false) CoroutineContext coroutineContext) { - coroutineContext = - KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); - } - } - - @SuppressWarnings("unused") - public static class RunBlockingAdvice { - - @Advice.OnMethodEnter - public static void enter( - @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext) { - coroutineContext = - KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); + if (coroutineContext != null) { + coroutineContext = + KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext); + } } } } diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesReactorInstrumentationModule.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesReactorInstrumentationModule.java deleted file mode 100644 index 52340dd061f9..000000000000 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinCoroutinesReactorInstrumentationModule.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor; - -import static java.util.Arrays.asList; - -import com.google.auto.service.AutoService; -import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; -import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import java.util.List; - -@AutoService(InstrumentationModule.class) -public class KotlinCoroutinesReactorInstrumentationModule extends InstrumentationModule { - - public KotlinCoroutinesReactorInstrumentationModule() { - super("kotlinx-coroutines", "kotlinx-coroutines-reactor"); - } - - @Override - public boolean isHelperClass(String className) { - return className.startsWith("io.opentelemetry.extension.kotlin."); - } - - @Override - public List typeInstrumentations() { - return asList( - new KotlinMonoCoroutineInstrumentation(), new KotlinPublisherCoroutineInstrumentation()); - } -} diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java deleted file mode 100644 index 2e2f935faa27..000000000000 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinMonoCoroutineInstrumentation.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor; - -import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; - -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.reactor.ContextPropagationOperator; -import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; -import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.KotlinCoroutinesInstrumentationHelper; -import kotlin.coroutines.CoroutineContext; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import reactor.core.publisher.MonoSink; - -public class KotlinMonoCoroutineInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("kotlinx.coroutines.reactor.MonoCoroutine"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isConstructor() - .and( - takesArgument(0, named("kotlin.coroutines.CoroutineContext")) - .and(takesArgument(1, named("reactor.core.publisher.MonoSink")))), - this.getClass().getName() + "$MonoCoroutineAdvice"); - } - - @SuppressWarnings("unused") - public static class MonoCoroutineAdvice { - - @Advice.OnMethodEnter - public static void enter( - @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext, - @Advice.Argument(1) MonoSink monoSink) { - Context context = - ContextPropagationOperator.getOpenTelemetryContext( - monoSink.currentContext(), Java8BytecodeBridge.currentContext()); - coroutineContext = - KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext(coroutineContext, context); - } - } -} diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java deleted file mode 100644 index 28cb64e5de16..000000000000 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/reactor/KotlinPublisherCoroutineInstrumentation.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.reactor; - -import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; - -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.reactor.ContextPropagationOperator; -import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; -import io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.KotlinCoroutinesInstrumentationHelper; -import kotlin.coroutines.CoroutineContext; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import org.reactivestreams.Subscriber; -import reactor.core.CoreSubscriber; - -public class KotlinPublisherCoroutineInstrumentation implements TypeInstrumentation { - @Override - public ElementMatcher typeMatcher() { - return named("kotlinx.coroutines.reactive.PublisherCoroutine"); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isConstructor() - .and( - takesArgument(0, named("kotlin.coroutines.CoroutineContext")) - .and(takesArgument(1, named("org.reactivestreams.Subscriber")))), - this.getClass().getName() + "$PublisherCoroutineAdvice"); - } - - @SuppressWarnings("unused") - public static class PublisherCoroutineAdvice { - - @Advice.OnMethodEnter - public static void enter( - @Advice.Argument(value = 0, readOnly = false) CoroutineContext coroutineContext, - @Advice.Argument(1) Subscriber subscriber) { - if (subscriber instanceof CoreSubscriber) { - CoreSubscriber coreSubscriber = (CoreSubscriber) subscriber; - Context context = - ContextPropagationOperator.getOpenTelemetryContext( - coreSubscriber.currentContext(), Java8BytecodeBridge.currentContext()); - coroutineContext = - KotlinCoroutinesInstrumentationHelper.addOpenTelemetryContext( - coroutineContext, context); - } - } - } -} From df59d72e7926bdfd4279a437481a72e21869a67c Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 28 Jan 2022 11:06:00 +0200 Subject: [PATCH 10/10] revert changes --- .../KotlinCoroutinesInstrumentationHelper.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationHelper.java b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationHelper.java index c03869c96297..0f5f8e3a085e 100644 --- a/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationHelper.java +++ b/instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationHelper.java @@ -13,16 +13,11 @@ public final class KotlinCoroutinesInstrumentationHelper { public static CoroutineContext addOpenTelemetryContext(CoroutineContext coroutineContext) { Context current = Context.current(); - return addOpenTelemetryContext(coroutineContext, current); - } - - public static CoroutineContext addOpenTelemetryContext( - CoroutineContext coroutineContext, Context otelContext) { Context inCoroutine = ContextExtensionsKt.getOpenTelemetryContext(coroutineContext); - if (otelContext == inCoroutine) { + if (current == inCoroutine) { return coroutineContext; } - return coroutineContext.plus(ContextExtensionsKt.asContextElement(otelContext)); + return coroutineContext.plus(ContextExtensionsKt.asContextElement(current)); } private KotlinCoroutinesInstrumentationHelper() {}