Convert Mongo instrumentation to ByteBuddy
MODIFY
.gitignore
.gitignore
@@ -51,3 +51,4 @@ Thumbs.db
*/out
dd-java-agent/integrations/*/out
dd-trace-examples/*/out
+derby.log

MODIFY
dd-java-agent/dd-java-agent.gradle
dd-java-agent/dd-java-agent.gradle
@@ -30,6 +30,9 @@ dependencies {
compile(project(':dd-java-agent:integrations:jms-2')) {
transitive = false
}
+ compile(project(':dd-java-agent:integrations:mongo')) {
+ transitive = false
+ }
compile(project(':dd-java-agent:integrations:servlet-2')) {
transitive = false
}
@@ -51,7 +54,6 @@ dependencies {
testCompile deps.testLogging
testCompile deps.opentracingMock
- testCompile group: 'org.mongodb', name: 'mongo-java-driver', version: '3.4.2'
testCompile(project(path: ':dd-java-agent:integrations:helpers')) {
transitive = false

MODIFY
dd-java-agent/integrations/mongo/mongo.gradle
dd-java-agent/integrations/mongo/mongo.gradle
@@ -9,3 +9,15 @@ versionScan {
"com.mongodb.client.model.MapReduceAction": null,
]
}
+
+apply from: "${rootDir}/gradle/java.gradle"
+
+dependencies {
+ compile group: 'org.mongodb', name: 'mongo-java-driver', version: '3.4.2'
+
+ compile project(':dd-trace')
+ compile project(':dd-java-agent:tooling')
+
+ compile deps.bytebuddy
+ compile deps.opentracing
+}

RENAME
dd-java-agent/integrations/helpers/src/main/java/com/datadoghq/agent/integration/MongoHelper.java
dd-java-agent/integrations/mongo/src/main/java/dd/inst/mongo/MongoClientInstrumentation.java
-package com.datadoghq.agent.integration;
+package dd.inst.mongo;
+
+import static dd.trace.ExceptionHandlers.defaultExceptionHandler;
+import static net.bytebuddy.matcher.ElementMatchers.*;
import com.datadoghq.trace.DDTags;
+import com.google.auto.service.AutoService;
import com.mongodb.MongoClientOptions;
import com.mongodb.event.CommandFailedEvent;
import com.mongodb.event.CommandListener;
import com.mongodb.event.CommandStartedEvent;
import com.mongodb.event.CommandSucceededEvent;
+import dd.trace.Instrumenter;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.tag.Tags;
+import io.opentracing.util.GlobalTracer;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
@@ -18,39 +24,40 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.extern.slf4j.Slf4j;
+import net.bytebuddy.agent.builder.AgentBuilder;
+import net.bytebuddy.asm.Advice;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.bson.BsonValue;
-import org.jboss.byteman.rule.Rule;
-/** Patch the Mongo builder before constructing the final client */
@Slf4j
-public class MongoHelper extends DDAgentTracingHelper<MongoClientOptions.Builder> {
-
- public MongoHelper(final Rule rule) {
- super(rule);
- }
+@AutoService(Instrumenter.class)
+public final class MongoClientInstrumentation implements Instrumenter {
- /**
- * Strategy: Just before com.mongodb.MongoClientOptions$Builder.build() method is called, we add a
- * new command listener in charge of the tracing.
- *
- * @param builder The builder instance
- * @return The same builder instance with a new tracing command listener that will be use for the
- * client construction
- * @throws Exception
- */
@Override
- protected MongoClientOptions.Builder doPatch(final MongoClientOptions.Builder builder)
- throws Exception {
-
- final DDTracingCommandListener listener = new DDTracingCommandListener(tracer);
+ public AgentBuilder instrument(AgentBuilder agentBuilder) {
+ return agentBuilder
+ .type(named("com.mongodb.MongoClientOptions$Builder"))
+ .transform(
+ new AgentBuilder.Transformer.ForAdvice()
+ .advice(
+ isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)),
+ MongoClientAdvice.class.getName())
+ .withExceptionHandler(defaultExceptionHandler()))
+ .asDecorator();
+ }
+
+ public static class MongoClientAdvice {
+
+ @Advice.OnMethodEnter(suppress = Throwable.class)
+ public static void injectTraceListener(@Advice.This final Object dis) {
+ // referencing "this" in the method args causes the class to load under a transformer.
+ // This bypasses the Builder instrumentation. Casting as a workaround.
+ MongoClientOptions.Builder builder = (MongoClientOptions.Builder) dis;
+ final DDTracingCommandListener listener = new DDTracingCommandListener(GlobalTracer.get());
builder.addCommandListener(listener);
-
- setState(builder, 1);
-
- return builder;
+ }
}
public static class DDTracingCommandListener implements CommandListener {

RENAME
dd-java-agent/src/test/java/com/datadoghq/agent/integration/MongoHelperTest.java
dd-java-agent/integrations/mongo/src/test/java/dd/inst/mongo/MongoClientInstrumentationTest.java
-package com.datadoghq.agent.integration;
+package dd.inst.mongo;
import static org.assertj.core.api.Java6Assertions.assertThat;
@@ -9,6 +9,7 @@ import com.mongodb.connection.ClusterId;
import com.mongodb.connection.ConnectionDescription;
import com.mongodb.connection.ServerId;
import com.mongodb.event.CommandStartedEvent;
+import dd.inst.mongo.MongoClientInstrumentation.DDTracingCommandListener;
import io.opentracing.tag.Tags;
import java.util.Arrays;
import java.util.List;
@@ -17,7 +18,7 @@ import org.bson.BsonDocument;
import org.bson.BsonString;
import org.junit.Test;
-public class MongoHelperTest {
+public class MongoClientInstrumentationTest {
private static ConnectionDescription makeConnection() {
return new ConnectionDescription(new ServerId(new ClusterId(), new ServerAddress()));
@@ -29,7 +30,7 @@ public class MongoHelperTest {
new CommandStartedEvent(1, makeConnection(), "databasename", "query", new BsonDocument());
final DDSpan span = new DDTracer().buildSpan("foo").startManual();
- MongoHelper.DDTracingCommandListener.decorate(span, cmd);
+ DDTracingCommandListener.decorate(span, cmd);
assertThat(span.context().getSpanType()).isEqualTo("mongodb");
assertThat(span.context().getResourceName())
@@ -51,7 +52,7 @@ public class MongoHelperTest {
new CommandStartedEvent(1, makeConnection(), "databasename", "query", query);
final DDSpan span = new DDTracer().buildSpan("foo").startManual();
- MongoHelper.DDTracingCommandListener.decorate(span, cmd);
+ DDTracingCommandListener.decorate(span, cmd);
assertThat(span.getTags().get(Tags.DB_STATEMENT.getKey()))
.isEqualTo(query.toString().replaceAll("secret", "?"));

MODIFY
dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml
dd-java-agent/src/main/resources/dd-trace-supported-framework.yaml
@@ -47,32 +47,6 @@ opentracing-jms-2_consumer:
javax.jms.JMSContext:
javax.jms.CompletionListener:
-opentracing-mongo-driver:
- - artifact: mongo-java-driver
- supported_version: 3\..*
- identifying_present_classes:
- com.mongodb.operation.AsyncReadOperation:
- com.mongodb.client.model.MapReduceAction:
-
- - artifact: mongodb-driver-async
- supported_version: 3\..*
- identifying_present_classes:
- com.mongodb.operation.AsyncReadOperation:
- com.mongodb.client.model.MapReduceAction:
-
-opentracing-mongo-driver-helper:
- - artifact: mongo-java-driver
- supported_version: 3\..*
- identifying_present_classes:
- com.mongodb.operation.AsyncReadOperation:
- com.mongodb.client.model.MapReduceAction:
-
- - artifact: mongodb-driver-async
- supported_version: 3\..*
- identifying_present_classes:
- com.mongodb.operation.AsyncReadOperation:
- com.mongodb.client.model.MapReduceAction:
-
opentracing-okhttp3:
- artifact: okhttp
supported_version: 3\..*

MODIFY
dd-java-agent/src/main/resources/initializer-rules.btm
dd-java-agent/src/main/resources/initializer-rules.btm
@@ -25,18 +25,6 @@ DO
ENDRULE
-# Instrument Mongo client
-# ========================
-RULE MongoClientOptions$Builder-init
-CLASS com.mongodb.MongoClientOptions$Builder
-METHOD <init>
-AT EXIT
-IF TRUE
-DO
- com.datadoghq.agent.InstrumentationRulesManager.registerClassLoad($0);
-ENDRULE
-
-
# Instrument OkHttp
# ===========================
RULE OkHttpClient$Builder-init

MODIFY
dd-java-agent/src/main/resources/integration-rules.btm
dd-java-agent/src/main/resources/integration-rules.btm
@@ -34,19 +34,6 @@ DO
ENDRULE
-# Instrument Mongo client
-# ========================
-RULE opentracing-mongo-driver
-CLASS com.mongodb.MongoClientOptions$Builder
-METHOD build
-HELPER com.datadoghq.agent.integration.MongoHelper
-AT ENTRY
-IF getState($0) == 0
-DO
- patch($0);
-ENDRULE
-
-
# Instrument OkHttp
# ===========================
RULE opentracing-okhttp3

Convert Mongo instrumentation to ByteBuddy