Skip to content

Commit c789ae5

Browse files
committed
ServiceTalk async context propagation instrumentation. Support 0.42.56+
1 parent bd7a9c8 commit c789ae5

File tree

14 files changed

+388
-227
lines changed

14 files changed

+388
-227
lines changed

buildSrc/src/main/groovy/MuzzlePlugin.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class MuzzlePlugin implements Plugin<Project> {
5959
RemoteRepository restlet = new RemoteRepository.Builder("restlet", "default", "https://maven.restlet.talend.com/").build()
6060
// Only needed for play-2.3
6161
RemoteRepository typesafe = new RemoteRepository.Builder("typesafe", "default", "https://repo.typesafe.com/typesafe/maven-releases/").build()
62+
//TODO add local repo or use docker to muzzle check and test version when deprecated `saved` will be dropped
6263
MUZZLE_REPOS = Collections.unmodifiableList(Arrays.asList(central, restlet, typesafe))
6364
}
6465

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,3 @@
1-
plugins {
2-
id 'java-test-fixtures'
3-
}
4-
5-
muzzle {
6-
pass {
7-
group = 'io.servicetalk'
8-
module = 'servicetalk-concurrent-api'
9-
// prev versions missing ContextMap
10-
versions = '[0.41.12,)'
11-
assertInverse = true
12-
}
13-
pass {
14-
group = 'io.servicetalk'
15-
module = 'servicetalk-context-api'
16-
versions = '[0.1.0,)'
17-
assertInverse = true
18-
}
19-
}
20-
21-
ext {
22-
minJavaVersionForTests = JavaVersion.VERSION_11
23-
}
24-
251
apply from: "$rootDir/gradle/java.gradle"
262

27-
addTestSuiteForDir('latestDepTest', 'test')
28-
29-
dependencies {
30-
compileOnly group: 'io.servicetalk', name: 'servicetalk-concurrent-api', version: '0.42.45'
31-
compileOnly group: 'io.servicetalk', name: 'servicetalk-context-api', version: '0.42.45'
32-
33-
testImplementation group: 'io.servicetalk', name: 'servicetalk-concurrent-api', version: '0.42.0'
34-
testImplementation group: 'io.servicetalk', name: 'servicetalk-context-api', version: '0.42.0'
35-
36-
latestDepTestImplementation group: 'io.servicetalk', name: 'servicetalk-concurrent-api', version: '+'
37-
latestDepTestImplementation group: 'io.servicetalk', name: 'servicetalk-context-api', version: '+'
38-
}
39-
3+
//TODO generate lock files

dd-java-agent/instrumentation/servicetalk/gradle.lockfile

Lines changed: 0 additions & 184 deletions
This file was deleted.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
plugins {
2+
id 'java-test-fixtures'
3+
}
4+
5+
muzzle {
6+
pass {
7+
group = 'io.servicetalk'
8+
module = 'servicetalk-concurrent-api'
9+
versions = '[0.42.0,0.42.56)'
10+
}
11+
fail {
12+
group = 'io.servicetalk'
13+
module = 'servicetalk-concurrent-api'
14+
versions = '[0.42.56,]' //TODO what's missing in 0.42.56, so I can add a muzzleCheck
15+
}
16+
}
17+
18+
ext {
19+
minJavaVersionForTests = JavaVersion.VERSION_11
20+
}
21+
22+
apply from: "$rootDir/gradle/java.gradle"
23+
24+
addTestSuiteForDir('latestDepTest', 'test')
25+
26+
dependencies {
27+
compileOnly group: 'io.servicetalk', name: 'servicetalk-concurrent-api', version: '0.42.0'
28+
compileOnly group: 'io.servicetalk', name: 'servicetalk-context-api', version: '0.42.0'
29+
30+
testImplementation group: 'io.servicetalk', name: 'servicetalk-concurrent-api', version: '0.42.0'
31+
testImplementation group: 'io.servicetalk', name: 'servicetalk-context-api', version: '0.42.0'
32+
33+
latestDepTestImplementation group: 'io.servicetalk', name: 'servicetalk-concurrent-api', version: '0.42.56'
34+
latestDepTestImplementation group: 'io.servicetalk', name: 'servicetalk-context-api', version: '0.42.56'
35+
}
36+

dd-java-agent/instrumentation/servicetalk/src/main/java/datadog/trace/instrumentation/servicetalk/ContextMapInstrumentation.java renamed to dd-java-agent/instrumentation/servicetalk/servicetalk-0.42.0/src/main/java/datadog/trace/instrumentation/servicetalk/ContextMapInstrumentation.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import net.bytebuddy.asm.Advice;
1717

1818
@AutoService(InstrumenterModule.class)
19-
public class ContextMapInstrumentation extends AbstractAsyncContextInstrumentation
19+
public class ContextMapInstrumentation extends ServiceTalkInstrumentation
2020
implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice {
2121

2222
@Override
@@ -40,6 +40,8 @@ public void methodAdvice(MethodTransformer transformer) {
4040
private static final class Construct {
4141
@Advice.OnMethodExit(suppress = Throwable.class)
4242
public static void exit(@Advice.This ContextMap contextMap) {
43+
// Capture an active span on ST context copy to support versions prior to 0.42.56 that did not
44+
// have captureContext
4345
InstrumentationContext.get(ContextMap.class, AgentSpan.class)
4446
.put(contextMap, AgentTracer.activeSpan());
4547
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package datadog.trace.instrumentation.servicetalk;
2+
3+
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.namedOneOf;
4+
5+
import com.google.auto.service.AutoService;
6+
import datadog.trace.agent.tooling.Instrumenter;
7+
import datadog.trace.agent.tooling.InstrumenterModule;
8+
import datadog.trace.bootstrap.InstrumentationContext;
9+
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
10+
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
11+
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
12+
import io.servicetalk.context.api.ContextMap;
13+
import net.bytebuddy.asm.Advice;
14+
15+
@AutoService(InstrumenterModule.class)
16+
public class ContextPreservingInstrumentation extends ServiceTalkInstrumentation
17+
implements Instrumenter.ForKnownTypes, Instrumenter.HasMethodAdvice {
18+
19+
@Override
20+
public String[] knownMatchingTypes() {
21+
return new String[] {
22+
"io.servicetalk.concurrent.api.ContextPreservingBiConsumer",
23+
"io.servicetalk.concurrent.api.ContextPreservingBiFunction",
24+
"io.servicetalk.concurrent.api.ContextPreservingCallable",
25+
"io.servicetalk.concurrent.api.ContextPreservingCancellable",
26+
"io.servicetalk.concurrent.api.ContextPreservingCompletableSubscriber",
27+
"io.servicetalk.concurrent.api.ContextPreservingConsumer",
28+
"io.servicetalk.concurrent.api.ContextPreservingFunction",
29+
"io.servicetalk.concurrent.api.ContextPreservingRunnable",
30+
"io.servicetalk.concurrent.api.ContextPreservingSingleSubscriber",
31+
"io.servicetalk.concurrent.api.ContextPreservingSubscriber",
32+
"io.servicetalk.concurrent.api.ContextPreservingSubscription",
33+
};
34+
}
35+
36+
@Override
37+
public void methodAdvice(MethodTransformer transformer) {
38+
transformer.applyAdvice(
39+
namedOneOf(
40+
"accept",
41+
"apply",
42+
"call",
43+
"cancel",
44+
"onComplete",
45+
"onError",
46+
"onSuccess",
47+
"request",
48+
"onNext",
49+
"onSubscribe",
50+
"run"),
51+
getClass().getName() + "$Wrapper");
52+
}
53+
54+
public static final class Wrapper {
55+
@Advice.OnMethodEnter(suppress = Throwable.class)
56+
public static AgentScope enter(@Advice.FieldValue("saved") final ContextMap contextMap) {
57+
AgentSpan parent =
58+
InstrumentationContext.get(ContextMap.class, AgentSpan.class).get(contextMap);
59+
if (parent != null) {
60+
return AgentTracer.activateSpan(parent);
61+
}
62+
return null;
63+
}
64+
65+
@Advice.OnMethodExit(suppress = Throwable.class)
66+
public static void exit(@Advice.Enter final AgentScope agentScope) {
67+
if (agentScope != null) {
68+
agentScope.close();
69+
}
70+
}
71+
72+
// TODO muzzle to be applied only for older versions < 0.42.56
73+
public static void muzzleCheck() {
74+
// TODO how to disable this instrumentation for 0.42.56+
75+
// because otherwise it fails to instrument b/o missing "saved" fields
76+
// Also ContextMapInstrumentation shouldn't be applied to 0.42.56+
77+
78+
// We need a class or method that has been deleted in 0.42.56 but was in 0.42.0+
79+
// But there is no such thing comparing 0.42.55 and 0.42.56 of servicetalk-concurrent-api
80+
81+
// Can't check io.servicetalk.concurrent.api.ContextPreservingCallable.saved
82+
// b/o the class is package private and the field is private
83+
84+
}
85+
}
86+
}

dd-java-agent/instrumentation/servicetalk/src/main/java/datadog/trace/instrumentation/servicetalk/AbstractAsyncContextInstrumentation.java renamed to dd-java-agent/instrumentation/servicetalk/servicetalk-0.42.0/src/main/java/datadog/trace/instrumentation/servicetalk/ServiceTalkInstrumentation.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
import java.util.Collections;
66
import java.util.Map;
77

8-
public abstract class AbstractAsyncContextInstrumentation extends InstrumenterModule.Tracing {
8+
public abstract class ServiceTalkInstrumentation extends InstrumenterModule.Tracing {
99

10-
public AbstractAsyncContextInstrumentation() {
10+
public ServiceTalkInstrumentation() {
1111
super("servicetalk", "servicetalk-concurrent");
1212
}
1313

dd-java-agent/instrumentation/servicetalk/src/test/groovy/ContextPreservingInstrumentationTest.groovy renamed to dd-java-agent/instrumentation/servicetalk/servicetalk-0.42.0/src/test/groovy/ContextPreservingInstrumentationTest.groovy

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import datadog.trace.bootstrap.instrumentation.api.AgentScope
33
import datadog.trace.bootstrap.instrumentation.api.AgentTracer
44
import io.servicetalk.concurrent.api.AsyncContext
55
import io.servicetalk.context.api.ContextMap
6-
76
import java.util.concurrent.ExecutorService
87
import java.util.concurrent.Executors
98

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
plugins {
2+
id 'java-test-fixtures'
3+
}
4+
5+
muzzle {
6+
fail {
7+
group = 'io.servicetalk'
8+
module = 'servicetalk-concurrent-api'
9+
versions = '[,0.42.56)'
10+
}
11+
pass {
12+
group = 'io.servicetalk'
13+
module = 'servicetalk-concurrent-api'
14+
// 0.42.56 is the earliest version where CapturedContext is public
15+
versions = '[0.42.56,]'
16+
}
17+
}
18+
19+
ext {
20+
minJavaVersionForTests = JavaVersion.VERSION_11
21+
}
22+
23+
apply from: "$rootDir/gradle/java.gradle"
24+
25+
addTestSuiteForDir('latestDepTest', 'test')
26+
27+
dependencies {
28+
compileOnly group: 'io.servicetalk', name: 'servicetalk-concurrent-api', version: '0.42.56'
29+
compileOnly group: 'io.servicetalk', name: 'servicetalk-context-api', version: '0.42.56'
30+
31+
testImplementation group: 'io.servicetalk', name: 'servicetalk-concurrent-api', version: '0.42.56'
32+
testImplementation group: 'io.servicetalk', name: 'servicetalk-context-api', version: '0.42.56'
33+
34+
latestDepTestImplementation group: 'io.servicetalk', name: 'servicetalk-concurrent-api', version: '+'
35+
latestDepTestImplementation group: 'io.servicetalk', name: 'servicetalk-context-api', version: '+'
36+
}
37+

dd-java-agent/instrumentation/servicetalk/src/main/java/datadog/trace/instrumentation/servicetalk/ContextPreservingInstrumentation.java renamed to dd-java-agent/instrumentation/servicetalk/servicetalk-0.42.56/src/main/java/datadog/trace/instrumentation/servicetalk/ContextPreservingInstrumentation.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
1010
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
1111
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
12+
import io.servicetalk.concurrent.api.CapturedContext;
1213
import io.servicetalk.context.api.ContextMap;
1314
import net.bytebuddy.asm.Advice;
1415

1516
@AutoService(InstrumenterModule.class)
16-
public class ContextPreservingInstrumentation extends AbstractAsyncContextInstrumentation
17+
public class ContextPreservingInstrumentation extends ServiceTalkInstrumentation
1718
implements Instrumenter.ForKnownTypes, Instrumenter.HasMethodAdvice {
1819

1920
@Override
@@ -53,7 +54,9 @@ public void methodAdvice(MethodTransformer transformer) {
5354

5455
public static final class Wrapper {
5556
@Advice.OnMethodEnter(suppress = Throwable.class)
56-
public static AgentScope enter(@Advice.FieldValue("saved") final ContextMap contextMap) {
57+
public static AgentScope enter(
58+
@Advice.FieldValue("capturedContext") final CapturedContext capturedContext) {
59+
ContextMap contextMap = capturedContext.captured();
5760
AgentSpan parent =
5861
InstrumentationContext.get(ContextMap.class, AgentSpan.class).get(contextMap);
5962
if (parent != null) {

0 commit comments

Comments
 (0)