-
Notifications
You must be signed in to change notification settings - Fork 277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Aerospike 4 instrumentation #2061
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
f2ba105
Aerospike4 instrumentation
mcculls 3d77965
Aerospike direct NioEventLoop instrumentation
mcculls 1fe34cb
Move DB detail instrumentation from Node to Command/Partition
mcculls 5fc2014
Aerospike client tests
mcculls 62267c4
abstract
mcculls 0e4577d
Wrap cluster.getUser byte array as UTF8BytesString
mcculls 4ba42b3
Use BaseDecorator.onPeerConnection
mcculls f4a5101
Prefer namedOneOf
mcculls 8d755f4
Cleanup aerospike strings
mcculls 03509a9
Merge and simplify listener tracing wrappers
mcculls 4ee0984
Further listener simplification
mcculls e5b6242
Remove redundant check
mcculls ff12cb8
Revert "Further listener simplification" to avoid creating extra runn…
mcculls c69d046
Don't wrap Runnables belonging to NioEventLoop(s) as they want to pro…
mcculls File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
dd-java-agent/instrumentation/aerospike-4/aerospike-4.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
|
||
apply from: "$rootDir/gradle/java.gradle" | ||
|
||
apply plugin: 'org.unbroken-dome.test-sets' | ||
|
||
testSets { | ||
latestDepTest { | ||
dirName = 'test' | ||
} | ||
} | ||
|
||
muzzle { | ||
pass { | ||
group = 'com.aerospike' | ||
module = 'aerospike-client' | ||
versions = "[4,)" | ||
} | ||
} | ||
|
||
dependencies { | ||
compileOnly group: 'com.aerospike', name: 'aerospike-client', version: '4.0.0' | ||
|
||
testCompile group: 'com.aerospike', name: 'aerospike-client', version: '4.0.0' | ||
testCompile group: 'org.testcontainers', name: 'testcontainers', version: '1.15.0' | ||
latestDepTestCompile group: 'com.aerospike', name: 'aerospike-client', version: '+' | ||
} |
106 changes: 106 additions & 0 deletions
106
...ke-4/src/main/java/datadog/trace/instrumentation/aerospike4/AerospikeClientDecorator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package datadog.trace.instrumentation.aerospike4; | ||
|
||
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; | ||
|
||
import com.aerospike.client.AerospikeClient; | ||
import com.aerospike.client.cluster.Cluster; | ||
import com.aerospike.client.cluster.Node; | ||
import com.aerospike.client.cluster.Partition; | ||
import datadog.trace.api.Config; | ||
import datadog.trace.api.DDTags; | ||
import datadog.trace.bootstrap.instrumentation.api.AgentSpan; | ||
import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes; | ||
import datadog.trace.bootstrap.instrumentation.api.Tags; | ||
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; | ||
import datadog.trace.bootstrap.instrumentation.decorator.DBTypeProcessingDatabaseClientDecorator; | ||
|
||
public class AerospikeClientDecorator extends DBTypeProcessingDatabaseClientDecorator<Node> { | ||
public static final UTF8BytesString JAVA_AEROSPIKE = UTF8BytesString.create("java-aerospike"); | ||
public static final UTF8BytesString AEROSPIKE_COMMAND = | ||
UTF8BytesString.create("aerospike.command"); | ||
|
||
public static final AerospikeClientDecorator DECORATE = new AerospikeClientDecorator(); | ||
|
||
@Override | ||
protected String[] instrumentationNames() { | ||
return new String[] {"aerospike"}; | ||
} | ||
|
||
@Override | ||
protected String service() { | ||
return "aerospike"; | ||
} | ||
|
||
@Override | ||
protected CharSequence component() { | ||
return JAVA_AEROSPIKE; | ||
} | ||
|
||
@Override | ||
protected CharSequence spanType() { | ||
return InternalSpanTypes.AEROSPIKE; | ||
} | ||
|
||
@Override | ||
protected String dbType() { | ||
return "aerospike"; | ||
} | ||
|
||
@Override | ||
protected String dbUser(final Node node) { | ||
return null; | ||
} | ||
|
||
@Override | ||
protected String dbInstance(final Node node) { | ||
return null; | ||
} | ||
|
||
@Override | ||
protected String dbHostname(final Node node) { | ||
return null; | ||
} | ||
|
||
public AgentSpan onConnection( | ||
final AgentSpan span, final Node node, final Cluster cluster, final Partition partition) { | ||
|
||
onPeerConnection(span, node.getAddress()); | ||
|
||
if (cluster != null && cluster.getUser() != null) { | ||
span.setTag(Tags.DB_USER, UTF8BytesString.create(cluster.getUser())); | ||
} | ||
|
||
if (partition != null) { | ||
String instanceName = partition.toString(); | ||
richardstartin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
final int namespaceEnd = instanceName.indexOf(':'); | ||
if (namespaceEnd > 0) { | ||
instanceName = instanceName.substring(0, namespaceEnd); | ||
} | ||
span.setTag(Tags.DB_INSTANCE, instanceName); | ||
if (Config.get().isDbClientSplitByInstance()) { | ||
span.setTag(DDTags.SERVICE_NAME, instanceName); | ||
} | ||
} | ||
|
||
return span; | ||
} | ||
|
||
public void withMethod(final AgentSpan span, final String methodName) { | ||
span.setTag(DDTags.RESOURCE_NAME, spanNameForMethod(AerospikeClient.class, methodName)); | ||
} | ||
|
||
public AgentSpan startAerospikeSpan(final String methodName) { | ||
final AgentSpan span = startSpan(AEROSPIKE_COMMAND); | ||
afterStart(span); | ||
withMethod(span, methodName); | ||
return span; | ||
} | ||
|
||
public void finishAerospikeSpan(final AgentSpan span, final Throwable error) { | ||
if (error != null) { | ||
onError(span, error); | ||
} | ||
beforeFinish(span); | ||
span.finish(); | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
...rc/main/java/datadog/trace/instrumentation/aerospike4/AerospikeClientInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package datadog.trace.instrumentation.aerospike4; | ||
|
||
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; | ||
import static datadog.trace.instrumentation.aerospike4.AerospikeClientDecorator.DECORATE; | ||
import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC; | ||
import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
import static net.bytebuddy.matcher.ElementMatchers.isPublic; | ||
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
||
import com.google.auto.service.AutoService; | ||
import datadog.trace.agent.tooling.Instrumenter; | ||
import datadog.trace.bootstrap.instrumentation.api.AgentScope; | ||
import datadog.trace.bootstrap.instrumentation.api.AgentSpan; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.method.MethodDescription; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
@AutoService(Instrumenter.class) | ||
public final class AerospikeClientInstrumentation extends Instrumenter.Default { | ||
public AerospikeClientInstrumentation() { | ||
super("aerospike"); | ||
} | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("com.aerospike.client.AerospikeClient"); | ||
} | ||
|
||
@Override | ||
public String[] helperClassNames() { | ||
return new String[] { | ||
packageName + ".AerospikeClientDecorator", packageName + ".TracingListener", | ||
}; | ||
} | ||
|
||
@Override | ||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() { | ||
final Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>(); | ||
transformers.put( | ||
isMethod() | ||
.and(isPublic()) | ||
.and(takesArgument(0, nameStartsWith("com.aerospike.client.policy"))), | ||
getClass().getName() + "$TraceSyncRequestAdvice"); | ||
transformers.put( | ||
isMethod() | ||
.and(isPublic()) | ||
.and(takesArgument(1, nameStartsWith("com.aerospike.client.listener"))), | ||
getClass().getName() + "$TraceAsyncRequestAdvice"); | ||
return transformers; | ||
} | ||
|
||
public static final class TraceSyncRequestAdvice { | ||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static AgentScope beginRequest(@Advice.Origin("#m") final String methodName) { | ||
AgentSpan clientSpan = DECORATE.startAerospikeSpan(methodName); | ||
return activateSpan(clientSpan); | ||
} | ||
|
||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
public static void exitRequest( | ||
@Advice.Enter final AgentScope scope, @Advice.Thrown final Throwable error) { | ||
DECORATE.finishAerospikeSpan(scope.span(), error); | ||
scope.close(); | ||
} | ||
} | ||
|
||
public static final class TraceAsyncRequestAdvice { | ||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static AgentScope beginRequest( | ||
@Advice.Origin("#m") final String methodName, | ||
@Advice.Argument(value = 1, readOnly = false, typing = DYNAMIC) Object listener) { | ||
AgentSpan clientSpan = DECORATE.startAerospikeSpan(methodName); | ||
AgentScope scope = activateSpan(clientSpan); | ||
// always want to wrap even when there's no listener so we get the true async time | ||
listener = new TracingListener(clientSpan, scope.capture(), listener); | ||
return scope; | ||
} | ||
|
||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
public static void exitRequest( | ||
@Advice.Enter final AgentScope scope, @Advice.Thrown final Throwable error) { | ||
if (error != null) { | ||
DECORATE.finishAerospikeSpan(scope.span(), error); | ||
} else { | ||
// span will be finished in the traced listener | ||
} | ||
scope.close(); | ||
} | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
...pike-4/src/main/java/datadog/trace/instrumentation/aerospike4/CommandInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package datadog.trace.instrumentation.aerospike4; | ||
|
||
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; | ||
import static datadog.trace.instrumentation.aerospike4.AerospikeClientDecorator.DECORATE; | ||
import static java.util.Collections.singletonMap; | ||
import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.returns; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
||
import com.aerospike.client.cluster.Cluster; | ||
import com.aerospike.client.cluster.Node; | ||
import com.aerospike.client.cluster.Partition; | ||
import com.google.auto.service.AutoService; | ||
import datadog.trace.agent.tooling.Instrumenter; | ||
import datadog.trace.api.DDSpanTypes; | ||
import datadog.trace.bootstrap.instrumentation.api.AgentSpan; | ||
import java.util.Map; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.method.MethodDescription; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
@AutoService(Instrumenter.class) | ||
public final class CommandInstrumentation extends Instrumenter.Default { | ||
public CommandInstrumentation() { | ||
super("aerospike"); | ||
} | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("com.aerospike.client.command.Command"); | ||
} | ||
|
||
@Override | ||
public String[] helperClassNames() { | ||
return new String[] { | ||
packageName + ".AerospikeClientDecorator", | ||
}; | ||
} | ||
|
||
@Override | ||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() { | ||
return singletonMap( | ||
isMethod() | ||
.and(named("getNode")) | ||
.and(takesArgument(0, named("com.aerospike.client.cluster.Cluster"))) | ||
.and(returns(named("com.aerospike.client.cluster.Node"))), | ||
getClass().getName() + "$GetNodeAdvice"); | ||
} | ||
|
||
public static final class GetNodeAdvice { | ||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
public static void getNode( | ||
@Advice.Return final Node node, | ||
@Advice.Argument(0) final Cluster cluster, | ||
@Advice.Argument(value = 1, optional = true) final Partition partition) { | ||
final AgentSpan span = activeSpan(); | ||
// capture the connection details in the active Aerospike span | ||
if (span != null && DDSpanTypes.AEROSPIKE.equals(span.getSpanType())) { | ||
DECORATE.onConnection(span, node, cluster, partition); | ||
} | ||
} | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
...4/src/main/java/datadog/trace/instrumentation/aerospike4/NioEventLoopInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package datadog.trace.instrumentation.aerospike4; | ||
|
||
import static datadog.trace.bootstrap.instrumentation.java.concurrent.ExcludeFilter.ExcludeType.RUNNABLE; | ||
import static datadog.trace.bootstrap.instrumentation.java.concurrent.ExcludeFilter.exclude; | ||
import static java.util.Collections.singletonMap; | ||
import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments; | ||
|
||
import com.google.auto.service.AutoService; | ||
import datadog.trace.agent.tooling.Instrumenter; | ||
import java.util.Map; | ||
import java.util.concurrent.FutureTask; | ||
import java.util.concurrent.RunnableFuture; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.method.MethodDescription; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
@AutoService(Instrumenter.class) | ||
public final class NioEventLoopInstrumentation extends Instrumenter.Default { | ||
mcculls marked this conversation as resolved.
Show resolved
Hide resolved
|
||
public NioEventLoopInstrumentation() { | ||
super("aerospike", "java_concurrent"); | ||
} | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("com.aerospike.client.async.NioEventLoop"); | ||
} | ||
|
||
@Override | ||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() { | ||
return singletonMap( | ||
isMethod() | ||
.and(named("execute")) | ||
.and(takesArguments(1)) | ||
.and(takesArgument(0, Runnable.class)), | ||
getClass().getName() + "$WrapAsFutureTaskAdvice"); | ||
} | ||
|
||
public static final class WrapAsFutureTaskAdvice { | ||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void enterExecute(@Advice.Argument(value = 0, readOnly = false) Runnable task) { | ||
if (task == null || task instanceof RunnableFuture || exclude(RUNNABLE, task)) { | ||
return; | ||
} | ||
// don't wrap Runnables belonging to NioEventLoop(s) as they want to propagate CloseException | ||
// outside of the event loop on close() and wrapping them in FutureTask interferes with that | ||
if (task.getClass().getName().startsWith("com.aerospike.client.async.NioEventLoop")) { | ||
return; | ||
} | ||
task = new FutureTask<Void>(task, null); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍