Skip to content

Commit a0e340b

Browse files
authored
Valkey intrumentation support (#8228)
* Initial valkey-java support * Use newer embedded redis * Remove fail muzzle block
1 parent 0b239ae commit a0e340b

File tree

7 files changed

+520
-0
lines changed

7 files changed

+520
-0
lines changed
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
muzzle {
3+
pass {
4+
group = "io.valkey"
5+
module = "valkey-java"
6+
versions = "[5.3.0,)"
7+
}
8+
}
9+
10+
apply from: "$rootDir/gradle/java.gradle"
11+
12+
addTestSuiteForDir('latestDepTest', 'test')
13+
14+
dependencies {
15+
compileOnly group: 'io.valkey', name: 'valkey-java', version: '5.3.0'
16+
17+
testImplementation group: 'com.github.codemonstur', name: 'embedded-redis', version: '1.4.3'
18+
testImplementation group: 'io.valkey', name: 'valkey-java', version: '5.3.0'
19+
latestDepTestImplementation group: 'io.valkey', name: 'valkey-java', version: '5.+'
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package datadog.trace.instrumentation.valkey;
2+
3+
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named;
4+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan;
5+
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan;
6+
import static io.valkey.ValkeyClientDecorator.DECORATE;
7+
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
8+
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
9+
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
10+
11+
import com.google.auto.service.AutoService;
12+
import datadog.trace.agent.tooling.Instrumenter;
13+
import datadog.trace.agent.tooling.InstrumenterModule;
14+
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
15+
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
16+
import io.valkey.CommandObject;
17+
import io.valkey.Connection;
18+
import io.valkey.Protocol;
19+
import io.valkey.ValkeyClientDecorator;
20+
import io.valkey.commands.ProtocolCommand;
21+
import net.bytebuddy.asm.Advice;
22+
23+
@AutoService(InstrumenterModule.class)
24+
public final class ValkeyInstrumentation extends InstrumenterModule.Tracing
25+
implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice {
26+
27+
public ValkeyInstrumentation() {
28+
super("valkey");
29+
}
30+
31+
@Override
32+
public String instrumentedType() {
33+
return "io.valkey.Connection";
34+
}
35+
36+
@Override
37+
public String[] helperClassNames() {
38+
return new String[] {
39+
"io.valkey.ValkeyClientDecorator",
40+
};
41+
}
42+
43+
@Override
44+
public void methodAdvice(MethodTransformer transformer) {
45+
transformer.applyAdvice(
46+
isMethod()
47+
.and(isPublic())
48+
.and(named("executeCommand"))
49+
.and(takesArgument(0, named("io.valkey.CommandObject"))),
50+
ValkeyInstrumentation.class.getName() + "$ValkeyAdvice");
51+
}
52+
53+
public static class ValkeyAdvice {
54+
55+
@Advice.OnMethodEnter(suppress = Throwable.class)
56+
public static AgentScope onEnter(
57+
@Advice.Argument(0) final CommandObject<?> commandObject,
58+
@Advice.This final Connection thiz) {
59+
final AgentSpan span = startSpan("valkey", ValkeyClientDecorator.OPERATION_NAME);
60+
DECORATE.afterStart(span);
61+
DECORATE.onConnection(span, thiz);
62+
63+
final ProtocolCommand command = commandObject.getArguments().getCommand();
64+
65+
if (command instanceof Protocol.Command) {
66+
DECORATE.onStatement(span, ((Protocol.Command) command).name());
67+
} else {
68+
DECORATE.onStatement(span, new String(command.getRaw()));
69+
}
70+
return activateSpan(span);
71+
}
72+
73+
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
74+
public static void stopSpan(
75+
@Advice.Enter final AgentScope scope, @Advice.Thrown final Throwable throwable) {
76+
DECORATE.onError(scope.span(), throwable);
77+
DECORATE.beforeFinish(scope.span());
78+
scope.close();
79+
scope.span().finish();
80+
}
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package io.valkey;
2+
3+
import datadog.trace.api.naming.SpanNaming;
4+
import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes;
5+
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
6+
import datadog.trace.bootstrap.instrumentation.decorator.DBTypeProcessingDatabaseClientDecorator;
7+
8+
public class ValkeyClientDecorator extends DBTypeProcessingDatabaseClientDecorator<Connection> {
9+
public static final ValkeyClientDecorator DECORATE = new ValkeyClientDecorator();
10+
11+
private static final String VALKEY = "valkey";
12+
public static final CharSequence OPERATION_NAME =
13+
UTF8BytesString.create(SpanNaming.instance().namingSchema().cache().operation(VALKEY));
14+
private static final String SERVICE_NAME =
15+
SpanNaming.instance().namingSchema().cache().service(VALKEY);
16+
private static final CharSequence COMPONENT_NAME = UTF8BytesString.create("valkey-command");
17+
18+
@Override
19+
protected String[] instrumentationNames() {
20+
return new String[] {"valkey", VALKEY};
21+
}
22+
23+
@Override
24+
protected String service() {
25+
return SERVICE_NAME;
26+
}
27+
28+
@Override
29+
protected CharSequence component() {
30+
return COMPONENT_NAME;
31+
}
32+
33+
@Override
34+
protected CharSequence spanType() {
35+
return InternalSpanTypes.VALKEY;
36+
}
37+
38+
@Override
39+
protected String dbType() {
40+
return VALKEY;
41+
}
42+
43+
@Override
44+
protected String dbUser(final Connection connection) {
45+
return null;
46+
}
47+
48+
@Override
49+
protected String dbInstance(final Connection connection) {
50+
return null;
51+
}
52+
53+
@Override
54+
protected String dbHostname(Connection connection) {
55+
return connection.getHostAndPort().getHost();
56+
}
57+
}

0 commit comments

Comments
 (0)