Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4d0b113

Browse files
akshaypatidar1999amarziali
andauthored
Add Vert.x 4 Redis client instrumentation (DataDog#6233)
* feat: add vertx4 redis instrumentation * feat: add test cases Signed-off-by: Akshay Patidar <akshaypatidar1999@gmail.com> * fix: muzzle and latest dependency forked test Signed-off-by: Akshay Patidar <akshaypatidar1999@gmail.com> * chore: rename test classes Signed-off-by: Akshay Patidar <akshaypatidar1999@gmail.com> * chore: make variables final Signed-off-by: Akshay Patidar <akshaypatidar1999@gmail.com> * chore: address pr comments Signed-off-by: Akshay Patidar <akshaypatidar1999@gmail.com> * Clean up - minimize code duplication and remove flaky annotation on tests * fix tests --------- Signed-off-by: Akshay Patidar <akshaypatidar1999@gmail.com> Co-authored-by: Andrea Marziali <andrea.marziali@datadoghq.com>
1 parent 21e5b46 commit 4d0b113

15 files changed

+230
-162
lines changed
Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
1-
2-
apply from: "$rootDir/gradle/java.gradle"
3-
41
muzzle {
52
pass {
63
group = 'io.vertx'
74
module = 'vertx-redis-client'
8-
versions = '[3.9.0,4)'
5+
versions = '[3.9.0,)'
96
assertInverse = true
107
}
118
}
129

10+
apply from: "$rootDir/gradle/java.gradle"
11+
apply from: "$rootDir/gradle/configure_tests.gradle"
12+
1313
addTestSuiteForDir('latestDepTest', 'test')
1414
addTestSuiteExtendingForDir('latestDepForkedTest', 'latestDepTest', 'test')
15+
addTestSuiteForDir('redis4xTest', 'test')
16+
addTestSuiteExtendingForDir('redis4xForkedTest', 'redis4xTest', 'test')
1517

16-
apply from: "$rootDir/gradle/configure_tests.gradle"
17-
18-
latestDepTest {
19-
finalizedBy 'latestDepForkedTest'
20-
}
2118

2219
dependencies {
2320
compileOnly project(':dd-java-agent:instrumentation:vertx-redis-client-3.9:stubs')
@@ -27,8 +24,15 @@ dependencies {
2724
testImplementation project(':dd-java-agent:instrumentation:vertx-rx-3.5')
2825
testImplementation group: 'io.vertx', name: 'vertx-redis-client', version: '3.9.0'
2926
testImplementation group: 'io.vertx', name: 'vertx-rx-java2', version: '3.9.0'
30-
testImplementation group: 'com.github.kstyrc', name: 'embedded-redis', version: '0.6'
27+
testImplementation group: 'com.redis.testcontainers', name: 'testcontainers-redis', version: '1.6.2'
28+
testImplementation deps.testcontainers
29+
30+
redis4xTestImplementation group: 'io.vertx', name: 'vertx-redis-client', version: '4.0.0'
31+
redis4xTestImplementation group: 'io.vertx', name: 'vertx-rx-java2', version: '4.0.0'
32+
latestDepTestImplementation group: 'io.vertx', name: 'vertx-redis-client', version: '4.+'
33+
latestDepTestImplementation group: 'io.vertx', name: 'vertx-rx-java2', version: '4.+'
34+
}
3135

32-
latestDepTestImplementation group: 'io.vertx', name: 'vertx-redis-client', version: '3.9+'
33-
latestDepTestImplementation group: 'io.vertx', name: 'vertx-rx-java2', version: '3.9+'
36+
tasks.withType(Test).configureEach {
37+
usesService(testcontainersLimit)
3438
}

‎dd-java-agent/instrumentation/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/CommandImplConstructorAdvice.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import datadog.trace.bootstrap.InstrumentationContext;
44
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
5-
import io.vertx.redis.RedisClient;
65
import io.vertx.redis.client.Command;
76
import io.vertx.redis.client.Redis;
87
import io.vertx.redis.client.impl.CommandImpl;
@@ -16,9 +15,7 @@ public static void afterConstructor(
1615
.put(zis, UTF8BytesString.create(command.toUpperCase()));
1716
}
1817

19-
// Only apply this advice for versions that we instrument 3.9.x
2018
private static void muzzleCheck() {
21-
RedisClient.create(null); // removed in 4.0.x
2219
Redis.createClient(null, "somehost"); // added in 3.9.x
2320
}
2421
}

‎dd-java-agent/instrumentation/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/RedisAPICallAdvice.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
1212
import io.vertx.core.AsyncResult;
1313
import io.vertx.core.Handler;
14-
import io.vertx.redis.RedisClient;
1514
import io.vertx.redis.client.Redis;
1615
import io.vertx.redis.client.RedisAPI;
1716
import io.vertx.redis.client.Response;
@@ -159,7 +158,6 @@ public static void afterCall(
159158

160159
// Only apply this advice for versions that we instrument 3.9.x
161160
private static void muzzleCheck() {
162-
RedisClient.create(null); // removed in 4.0.x
163161
Redis.createClient(null, "somehost"); // added in 3.9.x
164162
}
165163
}

‎dd-java-agent/instrumentation/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/RedisAPIImplSendAdvice.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
99
import io.vertx.core.Future;
1010
import io.vertx.core.net.SocketAddress;
11-
import io.vertx.redis.RedisClient;
1211
import io.vertx.redis.client.Redis;
1312
import io.vertx.redis.client.RedisAPI;
1413
import io.vertx.redis.client.RedisConnection;
@@ -44,7 +43,7 @@ public static void afterSend(
4443
}
4544
if (!future.isComplete()) {
4645
// Add the handler only when the future is not already completed
47-
future.setHandler(handler);
46+
future.onComplete(handler);
4847
} else {
4948
// Check whether the future has completed some time when adding the handler.
5049
// This might lead to executing the handler twice so the handler must be able to deal with
@@ -57,7 +56,6 @@ public static void afterSend(
5756

5857
// Only apply this advice for versions that we instrument 3.9.x
5958
private static void muzzleCheck() {
60-
RedisClient.create(null); // removed in 4.0.x
6159
Redis.createClient(null, "somehost"); // added in 3.9.x
6260
}
6361
}

‎dd-java-agent/instrumentation/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/RedisConnectAdvice.java

Lines changed: 0 additions & 26 deletions
This file was deleted.

‎dd-java-agent/instrumentation/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/RedisConnectionConstructAdvice.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@
33
import datadog.trace.bootstrap.InstrumentationContext;
44
import io.vertx.core.net.NetSocket;
55
import io.vertx.core.net.SocketAddress;
6-
import io.vertx.redis.RedisClient;
76
import io.vertx.redis.client.Redis;
87
import io.vertx.redis.client.RedisConnection;
9-
import io.vertx.redis.client.impl.RedisConnectionImpl;
108
import net.bytebuddy.asm.Advice;
119

1210
public class RedisConnectionConstructAdvice {
1311
@Advice.OnMethodExit(suppress = Throwable.class)
1412
public static void afterConstructor(
15-
@Advice.Argument(3) final NetSocket netSocket, @Advice.This final RedisConnectionImpl thiz) {
13+
@Advice.Argument(3) final NetSocket netSocket, @Advice.This final RedisConnection thiz) {
1614
if (netSocket != null && netSocket.remoteAddress() != null) {
1715
InstrumentationContext.get(RedisConnection.class, SocketAddress.class)
1816
.put(thiz, netSocket.remoteAddress());
@@ -21,7 +19,6 @@ public static void afterConstructor(
2119

2220
// Only apply this advice for versions that we instrument 3.9.x
2321
private static void muzzleCheck() {
24-
RedisClient.create(null); // removed in 4.0.x
2522
Redis.createClient(null, "somehost"); // added in 3.9.x
2623
}
2724
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package datadog.trace.instrumentation.vertx_redis_client;
2+
3+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan;
4+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan;
5+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.captureSpan;
6+
import static datadog.trace.instrumentation.vertx_redis_client.VertxRedisClientDecorator.DECORATE;
7+
import static datadog.trace.instrumentation.vertx_redis_client.VertxRedisClientDecorator.REDIS_COMMAND;
8+
9+
import datadog.trace.bootstrap.CallDepthThreadLocalMap;
10+
import datadog.trace.bootstrap.ContextStore;
11+
import datadog.trace.bootstrap.InstrumentationContext;
12+
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
13+
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
14+
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
15+
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
16+
import io.vertx.core.Future;
17+
import io.vertx.core.Promise;
18+
import io.vertx.core.net.SocketAddress;
19+
import io.vertx.redis.client.Command;
20+
import io.vertx.redis.client.RedisAPI;
21+
import io.vertx.redis.client.RedisConnection;
22+
import io.vertx.redis.client.Request;
23+
import io.vertx.redis.client.Response;
24+
import io.vertx.redis.client.impl.RequestImpl;
25+
import net.bytebuddy.asm.Advice;
26+
27+
public class RedisFutureSendAdvice {
28+
@Advice.OnMethodEnter(suppress = Throwable.class)
29+
public static AgentScope beforeSend(
30+
@Advice.Argument(value = 0, readOnly = false) Request request,
31+
@Advice.Local("ddParentContinuation") AgentScope.Continuation parentContinuation)
32+
throws Throwable {
33+
ContextStore<Request, Boolean> ctxt = InstrumentationContext.get(Request.class, Boolean.class);
34+
Boolean handled = ctxt.get(request);
35+
if (null != handled && handled) {
36+
return null;
37+
}
38+
// Create a shallow copy of the Request here to make sure that reused Requests get spans
39+
if (request instanceof Cloneable) {
40+
// Other library code do this downcast, so we can do it as well
41+
request = (Request) ((RequestImpl) request).clone();
42+
}
43+
ctxt.put(request, Boolean.TRUE);
44+
45+
// If we had already wrapped the innermost handler in the RedisAPI call, then we should
46+
// not wrap it again here. See comment in RedisAPICallAdvice
47+
if (CallDepthThreadLocalMap.incrementCallDepth(RedisAPI.class) > 0) {
48+
return AgentTracer.NoopAgentScope.INSTANCE;
49+
}
50+
51+
AgentSpan parentSpan = activeSpan();
52+
53+
if (parentSpan != null && REDIS_COMMAND.equals(parentSpan.getOperationName())) {
54+
// FIXME: this is not the best way to do it but in 4.5.0 there can be race conditions
55+
return null;
56+
}
57+
58+
parentContinuation = null == parentSpan ? null : captureSpan(parentSpan);
59+
final AgentSpan clientSpan =
60+
DECORATE.startAndDecorateSpan(
61+
request.command(), InstrumentationContext.get(Command.class, UTF8BytesString.class));
62+
63+
return activateSpan(clientSpan, true);
64+
}
65+
66+
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
67+
public static void afterSend(
68+
@Advice.Return(readOnly = false) Future<Response> responseFuture,
69+
@Advice.Local("ddParentContinuation") AgentScope.Continuation parentContinuation,
70+
@Advice.Enter final AgentScope clientScope,
71+
@Advice.This final Object thiz) {
72+
if (thiz instanceof RedisConnection) {
73+
final SocketAddress socketAddress =
74+
InstrumentationContext.get(RedisConnection.class, SocketAddress.class)
75+
.get((RedisConnection) thiz);
76+
final AgentSpan span = clientScope != null ? clientScope.span() : activeSpan();
77+
78+
if (socketAddress != null && span != null) {
79+
final AgentSpan spanWithConnection =
80+
clientScope == AgentTracer.NoopAgentScope.INSTANCE ? activeSpan() : span;
81+
DECORATE.onConnection(spanWithConnection, socketAddress);
82+
DECORATE.setPeerPort(spanWithConnection, socketAddress.port());
83+
}
84+
}
85+
if (clientScope != null) {
86+
CallDepthThreadLocalMap.decrementCallDepth(RedisAPI.class);
87+
Promise<Response> promise = Promise.promise();
88+
responseFuture.onComplete(
89+
new ResponseHandler(promise, clientScope.span(), parentContinuation));
90+
responseFuture = promise.future();
91+
clientScope.close();
92+
}
93+
}
94+
}

‎dd-java-agent/instrumentation/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/RedisInstrumentation.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package datadog.trace.instrumentation.vertx_redis_client;
22

33
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named;
4+
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.namedOneOf;
45
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
56
import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
67
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
78
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
89
import static net.bytebuddy.matcher.ElementMatchers.returns;
910
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
11+
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
1012

1113
import com.google.auto.service.AutoService;
1214
import datadog.trace.agent.tooling.Instrumenter;
@@ -33,7 +35,9 @@ public Map<String, String> contextStore() {
3335
@Override
3436
public String[] helperClassNames() {
3537
return new String[] {
36-
packageName + ".ResponseHandlerWrapper", packageName + ".VertxRedisClientDecorator",
38+
packageName + ".ResponseHandlerWrapper",
39+
packageName + ".ResponseHandler",
40+
packageName + ".VertxRedisClientDecorator",
3741
};
3842
}
3943

@@ -45,12 +49,14 @@ public String[] knownMatchingTypes() {
4549
"io.vertx.redis.client.impl.RedisClusterClient",
4650
"io.vertx.redis.client.impl.RedisSentinelClient",
4751
"io.vertx.redis.client.impl.RedisConnectionImpl",
48-
"io.vertx.redis.client.impl.RedisClusterConnection"
52+
"io.vertx.redis.client.impl.RedisClusterConnection",
53+
"io.vertx.redis.client.impl.RedisStandaloneConnection", // added in 4.x
4954
};
5055
}
5156

5257
@Override
5358
public void adviceTransformations(AdviceTransformation transformation) {
59+
5460
transformation.applyAdvice(
5561
isMethod()
5662
.and(isPublic())
@@ -60,16 +66,20 @@ public void adviceTransformations(AdviceTransformation transformation) {
6066
packageName + ".RedisSendAdvice");
6167

6268
transformation.applyAdvice(
63-
isDeclaredBy(named("io.vertx.redis.client.impl.RedisConnectionImpl"))
69+
isDeclaredBy(
70+
namedOneOf(
71+
"io.vertx.redis.client.impl.RedisConnectionImpl",
72+
"io.vertx.redis.client.impl.RedisStandaloneConnection"))
6473
.and(isConstructor())
6574
.and(takesArgument(3, named("io.vertx.core.net.NetSocket"))),
6675
packageName + ".RedisConnectionConstructAdvice");
6776

6877
transformation.applyAdvice(
69-
isMethod()
70-
.and(isPublic())
71-
.and(named("connect"))
72-
.and(returns(named("io.vertx.redis.client.Redis"))),
73-
packageName + ".RedisConnectAdvice");
78+
isPublic()
79+
.and(named("send"))
80+
.and(takesArguments(1))
81+
.and(takesArgument(0, named("io.vertx.redis.client.Request")))
82+
.and(returns(named("io.vertx.core.Future"))),
83+
packageName + ".RedisFutureSendAdvice");
7484
}
7585
}

‎dd-java-agent/instrumentation/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/RedisSendAdvice.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import io.vertx.core.AsyncResult;
1616
import io.vertx.core.Handler;
1717
import io.vertx.core.net.SocketAddress;
18-
import io.vertx.redis.RedisClient;
1918
import io.vertx.redis.client.Command;
2019
import io.vertx.redis.client.Redis;
2120
import io.vertx.redis.client.RedisAPI;
@@ -65,9 +64,7 @@ public static AgentScope beforeSend(
6564

6665
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
6766
public static void afterSend(
68-
@Advice.Thrown final Throwable throwable,
69-
@Advice.Enter final AgentScope clientScope,
70-
@Advice.This final Object thiz) {
67+
@Advice.Enter final AgentScope clientScope, @Advice.This final Object thiz) {
7168
if (thiz instanceof RedisConnection) {
7269
final SocketAddress socketAddress =
7370
InstrumentationContext.get(RedisConnection.class, SocketAddress.class)
@@ -86,7 +83,6 @@ public static void afterSend(
8683

8784
// Only apply this advice for versions that we instrument 3.9.x
8885
private static void muzzleCheck() {
89-
RedisClient.create(null); // removed in 4.0.x
9086
Redis.createClient(null, "somehost"); // added in 3.9.x
9187
}
9288
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
package datadog.trace.instrumentation.vertx_redis_client;
22

3-
import io.vertx.redis.RedisClient;
43
import io.vertx.redis.client.Redis;
54
import net.bytebuddy.asm.Advice;
65

76
public class RequestImplMuzzle {
87
@Advice.OnMethodEnter // This advice will never be applied
98
public static void muzzleCheck() {
10-
RedisClient.create(null); // removed in 4.0.x
119
Redis.createClient(null, "somehost"); // added in 3.9.x
1210
}
1311
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /