|
1 | | -package com.datadoghq.agent.integration; |
| 1 | +package dd.inst.mongo; |
| 2 | + |
| 3 | +import static dd.trace.ExceptionHandlers.defaultExceptionHandler; |
| 4 | +import static net.bytebuddy.matcher.ElementMatchers.*; |
2 | 5 |
|
3 | 6 | import com.datadoghq.trace.DDTags; |
| 7 | +import com.google.auto.service.AutoService; |
4 | 8 | import com.mongodb.MongoClientOptions; |
5 | 9 | import com.mongodb.event.CommandFailedEvent; |
6 | 10 | import com.mongodb.event.CommandListener; |
7 | 11 | import com.mongodb.event.CommandStartedEvent; |
8 | 12 | import com.mongodb.event.CommandSucceededEvent; |
| 13 | +import dd.trace.Instrumenter; |
9 | 14 | import io.opentracing.Span; |
10 | 15 | import io.opentracing.Tracer; |
11 | 16 | import io.opentracing.tag.Tags; |
| 17 | +import io.opentracing.util.GlobalTracer; |
12 | 18 | import java.net.Inet4Address; |
13 | 19 | import java.net.InetAddress; |
14 | 20 | import java.nio.ByteBuffer; |
|
18 | 24 | import java.util.Map; |
19 | 25 | import java.util.concurrent.ConcurrentHashMap; |
20 | 26 | import lombok.extern.slf4j.Slf4j; |
| 27 | +import net.bytebuddy.agent.builder.AgentBuilder; |
| 28 | +import net.bytebuddy.asm.Advice; |
21 | 29 | import org.bson.BsonArray; |
22 | 30 | import org.bson.BsonDocument; |
23 | 31 | import org.bson.BsonString; |
24 | 32 | import org.bson.BsonValue; |
25 | | -import org.jboss.byteman.rule.Rule; |
26 | 33 |
|
27 | | -/** Patch the Mongo builder before constructing the final client */ |
28 | 34 | @Slf4j |
29 | | -public class MongoHelper extends DDAgentTracingHelper<MongoClientOptions.Builder> { |
30 | | - |
31 | | - public MongoHelper(final Rule rule) { |
32 | | - super(rule); |
33 | | - } |
| 35 | +@AutoService(Instrumenter.class) |
| 36 | +public final class MongoClientInstrumentation implements Instrumenter { |
34 | 37 |
|
35 | | - /** |
36 | | - * Strategy: Just before com.mongodb.MongoClientOptions$Builder.build() method is called, we add a |
37 | | - * new command listener in charge of the tracing. |
38 | | - * |
39 | | - * @param builder The builder instance |
40 | | - * @return The same builder instance with a new tracing command listener that will be use for the |
41 | | - * client construction |
42 | | - * @throws Exception |
43 | | - */ |
44 | 38 | @Override |
45 | | - protected MongoClientOptions.Builder doPatch(final MongoClientOptions.Builder builder) |
46 | | - throws Exception { |
47 | | - |
48 | | - final DDTracingCommandListener listener = new DDTracingCommandListener(tracer); |
49 | | - builder.addCommandListener(listener); |
| 39 | + public AgentBuilder instrument(AgentBuilder agentBuilder) { |
| 40 | + return agentBuilder |
| 41 | + .type(named("com.mongodb.MongoClientOptions$Builder")) |
| 42 | + .transform( |
| 43 | + new AgentBuilder.Transformer.ForAdvice() |
| 44 | + .advice( |
| 45 | + isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)), |
| 46 | + MongoClientAdvice.class.getName()) |
| 47 | + .withExceptionHandler(defaultExceptionHandler())) |
| 48 | + .asDecorator(); |
| 49 | + } |
50 | 50 |
|
51 | | - setState(builder, 1); |
| 51 | + public static class MongoClientAdvice { |
52 | 52 |
|
53 | | - return builder; |
| 53 | + @Advice.OnMethodEnter(suppress = Throwable.class) |
| 54 | + public static void injectTraceListener(@Advice.This final Object dis) { |
| 55 | + // referencing "this" in the method args causes the class to load under a transformer. |
| 56 | + // This bypasses the Builder instrumentation. Casting as a workaround. |
| 57 | + MongoClientOptions.Builder builder = (MongoClientOptions.Builder) dis; |
| 58 | + final DDTracingCommandListener listener = new DDTracingCommandListener(GlobalTracer.get()); |
| 59 | + builder.addCommandListener(listener); |
| 60 | + } |
54 | 61 | } |
55 | 62 |
|
56 | 63 | public static class DDTracingCommandListener implements CommandListener { |
|
0 commit comments