diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/ClientAdvice.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientAdvice.java similarity index 82% rename from dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/ClientAdvice.java rename to dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientAdvice.java index 9504bb828a..2819807937 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/ClientAdvice.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientAdvice.java @@ -3,7 +3,7 @@ package datadog.trace.instrumentation.rmi.client; import static datadog.trace.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.instrumentation.api.AgentTracer.startSpan; -import static datadog.trace.instrumentation.rmi.client.ClientDecorator.DECORATE; +import static datadog.trace.instrumentation.rmi.client.RmiClientDecorator.DECORATE; import datadog.trace.api.DDTags; import datadog.trace.instrumentation.api.AgentScope; @@ -11,7 +11,7 @@ import datadog.trace.instrumentation.api.AgentSpan; import java.lang.reflect.Method; import net.bytebuddy.asm.Advice; -public class ClientAdvice { +public class RmiClientAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static AgentScope onEnter(@Advice.Argument(value = 1) final Method method) { if (activeSpan() == null) { @@ -19,9 +19,7 @@ public class ClientAdvice { } final AgentSpan span = startSpan("rmi.invoke") - .setTag( - DDTags.RESOURCE_NAME, - method.getDeclaringClass().getSimpleName() + "#" + method.getName()) + .setTag(DDTags.RESOURCE_NAME, DECORATE.spanNameForMethod(method)) .setTag("span.origin.type", method.getDeclaringClass().getCanonicalName()); DECORATE.afterStart(span); diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/ClientDecorator.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientDecorator.java similarity index 57% rename from dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/ClientDecorator.java rename to dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientDecorator.java index b07029e04c..e11102c443 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/ClientDecorator.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientDecorator.java @@ -1,10 +1,10 @@ package datadog.trace.instrumentation.rmi.client; -import datadog.trace.agent.decorator.BaseDecorator; +import datadog.trace.agent.decorator.ClientDecorator; import datadog.trace.api.DDSpanTypes; -public class ClientDecorator extends BaseDecorator { - public static final ClientDecorator DECORATE = new ClientDecorator(); +public class RmiClientDecorator extends ClientDecorator { + public static final RmiClientDecorator DECORATE = new RmiClientDecorator(); @Override protected String[] instrumentationNames() { @@ -20,4 +20,9 @@ public class ClientDecorator extends BaseDecorator { protected String component() { return "rmi-client"; } + + @Override + protected String service() { + return "rmi"; + } } diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientInstrumentation.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientInstrumentation.java index 9dbc044331..76a8e92a08 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientInstrumentation.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientInstrumentation.java @@ -31,8 +31,8 @@ public final class RmiClientInstrumentation extends Instrumenter.Default { public String[] helperClassNames() { return new String[] { "datadog.trace.agent.decorator.BaseDecorator", - packageName + ".ClientDecorator", - packageName + ".ClientAdvice" + "datadog.trace.agent.decorator.ClientDecorator", + packageName + ".RmiClientDecorator" }; } @@ -43,6 +43,6 @@ public final class RmiClientInstrumentation extends Instrumenter.Default { .and(named("invoke")) .and(takesArgument(0, named("java.rmi.Remote"))) .and(takesArgument(1, named("java.lang.reflect.Method"))), - packageName + ".ClientAdvice"); + packageName + ".RmiClientAdvice"); } } diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/StreamRemoteCallConstructorAdvice.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/ContextPropagator.java similarity index 55% rename from dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/StreamRemoteCallConstructorAdvice.java rename to dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/ContextPropagator.java index 992c147f00..7b8aae8548 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/StreamRemoteCallConstructorAdvice.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/ContextPropagator.java @@ -1,78 +1,38 @@ package datadog.trace.instrumentation.rmi.context; -import static datadog.trace.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.instrumentation.api.AgentTracer.propagate; import static datadog.trace.instrumentation.rmi.context.ContextPayload.SETTER; import datadog.trace.bootstrap.ContextStore; -import datadog.trace.bootstrap.InstrumentationContext; import datadog.trace.instrumentation.api.AgentSpan; import java.io.IOException; import java.io.ObjectOutput; import java.rmi.NoSuchObjectException; import java.rmi.server.ObjID; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.asm.Advice; import sun.rmi.transport.Connection; import sun.rmi.transport.StreamRemoteCall; import sun.rmi.transport.TransportConstants; -/** - * Main entry point for transferring context between RMI service. - * - *

It injects into StreamRemoteCall constructor used for invoking remote tasks and performs a - * backwards compatible check to ensure if the other side is prepared to receive context propagation - * messages then if successful sends a context propagation message - * - *

Context propagation consist of a Serialized HashMap with all data set by usual context - * injection, which includes things like sampling priority, trace and parent id - * - *

As well as optional baggage items - * - *

On the other side of the communication a special Dispatcher is created when a message with - * DD_CONTEXT_CALL_ID is received. - * - *

If the server is not instrumented first call will gracefully fail just like any other unknown - * call. With small caveat that this first call needs to *not* have any parameters, since those will - * not be read from connection and instead will be interpreted as another remote instruction, but - * that instruction will essentially be garbage data and will cause the parsing loop to throw - * exception and shutdown the connection which we do not want - */ @Slf4j -public class StreamRemoteCallConstructorAdvice { - public static final ObjID ACTIVATOR_ID = new ObjID(ObjID.ACTIVATOR_ID); - public static final ObjID DGC_ID = new ObjID(ObjID.DGC_ID); - public static final ObjID REGISTRY_ID = new ObjID(ObjID.REGISTRY_ID); - public static final ObjID DD_CONTEXT_CALL_ID = new ObjID("Datadog.context_call.v2".hashCode()); - public static final int CONTEXT_CHECK_CALL_OP_ID = -1; +public class ContextPropagator { + private static final ObjID ACTIVATOR_ID = new ObjID(ObjID.ACTIVATOR_ID); + private static final ObjID DGC_ID = new ObjID(ObjID.DGC_ID); + private static final ObjID REGISTRY_ID = new ObjID(ObjID.REGISTRY_ID); + public static final ObjID DD_CONTEXT_CALL_ID = new ObjID("Datadog.v1.context_call".hashCode()); + private static final int CONTEXT_CHECK_CALL_OP_ID = -1; public static final int CONTEXT_PASS_OPERATION_ID = -2; - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.Argument(value = 0) final Connection c, @Advice.Argument(value = 1) final ObjID id) { - if (!c.isReusable()) { - return; - } - if (isRMIInternalObject(id)) { - return; - } - - final ContextStore contextStore = - InstrumentationContext.get(Connection.class, Boolean.class); - attemptToPropagateContext(contextStore, c); - } - public static boolean isRMIInternalObject(final ObjID id) { return ACTIVATOR_ID.equals(id) || DGC_ID.equals(id) || REGISTRY_ID.equals(id); } - public static void attemptToPropagateContext( - final ContextStore contextStore, final Connection c) { - final AgentSpan span = activeSpan(); - if (span == null) { - return; - } + public static final ContextPropagator PROPAGATOR = new ContextPropagator(); + public void attemptToPropagateContext( + final ContextStore contextStore, + final Connection c, + final AgentSpan span) { if (checkIfContextCanBePassed(contextStore, c)) { final ContextPayload payload = new ContextPayload(); propagate().inject(span, payload, SETTER); @@ -82,7 +42,7 @@ public class StreamRemoteCallConstructorAdvice { } } - private static boolean checkIfContextCanBePassed( + private boolean checkIfContextCanBePassed( final ContextStore contextStore, final Connection c) { final Boolean storedResult = contextStore.get(c); if (storedResult != null) { @@ -94,7 +54,7 @@ public class StreamRemoteCallConstructorAdvice { return result; } - private static boolean syntheticCall( + private boolean syntheticCall( final Connection c, final ContextPayload payload, final int operationId) { final StreamRemoteCall shareContextCall = new StreamRemoteCall(c); try { diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/RmiContextInstrumentation.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/RmiContextInstrumentation.java deleted file mode 100644 index 05042f0ce4..0000000000 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/RmiContextInstrumentation.java +++ /dev/null @@ -1,80 +0,0 @@ -package datadog.trace.instrumentation.rmi.context; - -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; -import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.isStatic; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; - -import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.Instrumenter; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; - -@AutoService(Instrumenter.class) -public class RmiContextInstrumentation extends Instrumenter.Default { - - public RmiContextInstrumentation() { - super("rmi", "rmi-context-propagator"); - } - - @Override - public ElementMatcher typeMatcher() { - return not(isInterface()) - .and( - safeHasSuperType( - named("sun.rmi.transport.StreamRemoteCall") - .or(named("sun.rmi.transport.ObjectTable")) - .or(named("sun.rmi.transport.ObjectEndpoint")))); - } - - @Override - public Map contextStore() { - final HashMap contextStore = new HashMap<>(); - // thread context that stores distributed context - contextStore.put("java.lang.Thread", "datadog.trace.instrumentation.api.AgentSpan$Context"); - - // caching if a connection can support enhanced format - contextStore.put("sun.rmi.transport.Connection", "java.lang.Boolean"); - return contextStore; - } - - @Override - public String[] helperClassNames() { - return new String[] { - packageName + ".ContextPayload", - packageName + ".ContextPayload$InjectAdapter", - packageName + ".ContextPayload$ExtractAdapter", - packageName + ".ContextDispatcher", - packageName + ".StreamRemoteCallConstructorAdvice", - packageName + ".ObjectTableAdvice", - packageName + ".ObjectTableAdvice$DummyRemote" - }; - } - - @Override - public Map, String> transformers() { - final Map, String> transformers = new HashMap<>(); - transformers.put( - isConstructor() - .and(takesArgument(0, named("sun.rmi.transport.Connection"))) - .and(takesArgument(1, named("java.rmi.server.ObjID"))), - packageName + ".StreamRemoteCallConstructorAdvice"); - - transformers.put( - isMethod() - .and(isStatic()) - .and(named("getTarget")) - .and((takesArgument(0, named("sun.rmi.transport.ObjectEndpoint")))), - packageName + ".ObjectTableAdvice"); - - return Collections.unmodifiableMap(transformers); - } -} diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/RmiClientContextInstrumentation.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/RmiClientContextInstrumentation.java new file mode 100644 index 0000000000..818930a5e3 --- /dev/null +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/RmiClientContextInstrumentation.java @@ -0,0 +1,54 @@ +package datadog.trace.instrumentation.rmi.context.client; + +import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import java.util.Map; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(Instrumenter.class) +public class RmiClientContextInstrumentation extends Instrumenter.Default { + + public RmiClientContextInstrumentation() { + super("rmi", "rmi-context-propagator", "rmi-client-context-propagator"); + } + + @Override + public ElementMatcher typeMatcher() { + return not(isInterface()).and(safeHasSuperType(named("sun.rmi.transport.StreamRemoteCall"))); + } + + @Override + public Map contextStore() { + // caching if a connection can support enhanced format + return singletonMap("sun.rmi.transport.Connection", "java.lang.Boolean"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.rmi.context.ContextPayload$InjectAdapter", + "datadog.trace.instrumentation.rmi.context.ContextPayload$ExtractAdapter", + "datadog.trace.instrumentation.rmi.context.ContextPayload", + "datadog.trace.instrumentation.rmi.context.ContextPropagator" + }; + } + + @Override + public Map, String> transformers() { + return singletonMap( + isConstructor() + .and(takesArgument(0, named("sun.rmi.transport.Connection"))) + .and(takesArgument(1, named("java.rmi.server.ObjID"))), + packageName + ".StreamRemoteCallConstructorAdvice"); + } +} diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/StreamRemoteCallConstructorAdvice.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/StreamRemoteCallConstructorAdvice.java new file mode 100644 index 0000000000..dc457b979f --- /dev/null +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/StreamRemoteCallConstructorAdvice.java @@ -0,0 +1,56 @@ +package datadog.trace.instrumentation.rmi.context.client; + +import static datadog.trace.instrumentation.api.AgentTracer.activeSpan; +import static datadog.trace.instrumentation.rmi.context.ContextPropagator.PROPAGATOR; + +import datadog.trace.bootstrap.ContextStore; +import datadog.trace.bootstrap.InstrumentationContext; +import datadog.trace.instrumentation.api.AgentSpan; +import datadog.trace.instrumentation.rmi.context.ContextPropagator; +import java.rmi.server.ObjID; +import net.bytebuddy.asm.Advice; +import sun.rmi.transport.Connection; + +/** + * Main entry point for transferring context between RMI service. + * + *

It injects into StreamRemoteCall constructor used for invoking remote tasks and performs a + * backwards compatible check to ensure if the other side is prepared to receive context propagation + * messages then if successful sends a context propagation message + * + *

Context propagation consist of a Serialized HashMap with all data set by usual context + * injection, which includes things like sampling priority, trace and parent id + * + *

As well as optional baggage items + * + *

On the other side of the communication a special Dispatcher is created when a message with + * DD_CONTEXT_CALL_ID is received. + * + *

If the server is not instrumented first call will gracefully fail just like any other unknown + * call. With small caveat that this first call needs to *not* have any parameters, since those will + * not be read from connection and instead will be interpreted as another remote instruction, but + * that instruction will essentially be garbage data and will cause the parsing loop to throw + * exception and shutdown the connection which we do not want + */ +public class StreamRemoteCallConstructorAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0) final Connection c, @Advice.Argument(value = 1) final ObjID id) { + if (!c.isReusable()) { + return; + } + if (ContextPropagator.isRMIInternalObject(id)) { + return; + } + final AgentSpan activeSpan = activeSpan(); + if (activeSpan == null) { + return; + } + + final ContextStore contextStore = + InstrumentationContext.get(Connection.class, Boolean.class); + + PROPAGATOR.attemptToPropagateContext(contextStore, c, activeSpan); + } +} diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/ContextDispatcher.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/ContextDispatcher.java similarity index 84% rename from dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/ContextDispatcher.java rename to dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/ContextDispatcher.java index b676ab51e6..d3a11bc177 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/ContextDispatcher.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/ContextDispatcher.java @@ -1,10 +1,12 @@ -package datadog.trace.instrumentation.rmi.context; +package datadog.trace.instrumentation.rmi.context.server; import static datadog.trace.instrumentation.api.AgentTracer.propagate; import static datadog.trace.instrumentation.rmi.context.ContextPayload.GETTER; import datadog.trace.bootstrap.ContextStore; import datadog.trace.instrumentation.api.AgentSpan; +import datadog.trace.instrumentation.rmi.context.ContextPayload; +import datadog.trace.instrumentation.rmi.context.ContextPropagator; import java.io.IOException; import java.io.ObjectInput; import java.rmi.Remote; @@ -25,7 +27,7 @@ public class ContextDispatcher implements Dispatcher { final int operationId = in.readInt(); in.readLong(); // skip 8 bytes - if (operationId == StreamRemoteCallConstructorAdvice.CONTEXT_PASS_OPERATION_ID) { + if (operationId == ContextPropagator.CONTEXT_PASS_OPERATION_ID) { final ContextPayload payload = ContextPayload.read(in); if (payload != null) { final AgentSpan.Context context = propagate().extract(payload, GETTER); diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/ObjectTableAdvice.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/ObjectTableAdvice.java similarity index 74% rename from dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/ObjectTableAdvice.java rename to dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/ObjectTableAdvice.java index 1a7a088ac7..f187c2ef7f 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/ObjectTableAdvice.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/ObjectTableAdvice.java @@ -1,18 +1,15 @@ -package datadog.trace.instrumentation.rmi.context; +package datadog.trace.instrumentation.rmi.context.server; -import static datadog.trace.instrumentation.rmi.context.StreamRemoteCallConstructorAdvice.DD_CONTEXT_CALL_ID; +import static datadog.trace.instrumentation.rmi.context.ContextPropagator.DD_CONTEXT_CALL_ID; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; import datadog.trace.instrumentation.api.AgentSpan; import java.rmi.Remote; -import lombok.extern.slf4j.Slf4j; import net.bytebuddy.asm.Advice; import sun.rmi.transport.Target; -@Slf4j public class ObjectTableAdvice { - public static final DummyRemote DUMMY_REMOTE = new DummyRemote(); @Advice.OnMethodExit(suppress = Throwable.class) public static void methodExit( @@ -31,12 +28,14 @@ public class ObjectTableAdvice { result = new Target( - DUMMY_REMOTE, + NoopRemote.NOOP_REMOTE, new ContextDispatcher(callableContextStore), - DUMMY_REMOTE, + NoopRemote.NOOP_REMOTE, DD_CONTEXT_CALL_ID, false); } - public static class DummyRemote implements Remote {} + public static class NoopRemote implements Remote { + public static final NoopRemote NOOP_REMOTE = new NoopRemote(); + } } diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/RmiServerContextInstrumentation.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/RmiServerContextInstrumentation.java new file mode 100644 index 0000000000..3eb276bb7b --- /dev/null +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/RmiServerContextInstrumentation.java @@ -0,0 +1,57 @@ +package datadog.trace.instrumentation.rmi.context.server; + +import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import java.util.Map; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(Instrumenter.class) +public class RmiServerContextInstrumentation extends Instrumenter.Default { + + public RmiServerContextInstrumentation() { + super("rmi", "rmi-context-propagator", "rmi-server-context-propagator"); + } + + @Override + public ElementMatcher typeMatcher() { + return not(isInterface()).and(safeHasSuperType(named("sun.rmi.transport.ObjectTable"))); + } + + @Override + public Map contextStore() { + return singletonMap("java.lang.Thread", "datadog.trace.instrumentation.api.AgentSpan$Context"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.rmi.context.ContextPayload$InjectAdapter", + "datadog.trace.instrumentation.rmi.context.ContextPayload$ExtractAdapter", + "datadog.trace.instrumentation.rmi.context.ContextPayload", + "datadog.trace.instrumentation.rmi.context.ContextPropagator", + packageName + ".ContextDispatcher", + packageName + ".ObjectTableAdvice$NoopRemote" + }; + } + + @Override + public Map, String> transformers() { + return singletonMap( + isMethod() + .and(isStatic()) + .and(named("getTarget")) + .and((takesArgument(0, named("sun.rmi.transport.ObjectEndpoint")))), + packageName + ".ObjectTableAdvice"); + } +} diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerDecorator.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerDecorator.java new file mode 100644 index 0000000000..edd09cad90 --- /dev/null +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerDecorator.java @@ -0,0 +1,43 @@ +package datadog.trace.instrumentation.rmi.server; + +import static datadog.trace.instrumentation.api.AgentTracer.activeSpan; +import static datadog.trace.instrumentation.api.AgentTracer.startSpan; + +import datadog.trace.agent.decorator.ServerDecorator; +import datadog.trace.api.DDSpanTypes; +import datadog.trace.bootstrap.ContextStore; +import datadog.trace.instrumentation.api.AgentSpan; + +public class RmiServerDecorator extends ServerDecorator { + public static final RmiServerDecorator DECORATE = new RmiServerDecorator(); + + public AgentSpan startSpanWithContext( + final ContextStore contextStore) { + if (activeSpan() != null) { + return startSpan("rmi.request"); + } + + final AgentSpan.Context context = contextStore.get(Thread.currentThread()); + + if (context == null) { + return startSpan("rmi.request"); + } else { + return startSpan("rmi.request", context); + } + } + + @Override + protected String[] instrumentationNames() { + return new String[] {"rmi"}; + } + + @Override + protected String spanType() { + return DDSpanTypes.RPC; + } + + @Override + protected String component() { + return "rmi-server"; + } +} diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerInstrumentation.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerInstrumentation.java index 97e6e53a6d..f479120483 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerInstrumentation.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerInstrumentation.java @@ -2,8 +2,7 @@ package datadog.trace.instrumentation.rmi.server; import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; import static datadog.trace.instrumentation.api.AgentTracer.activateSpan; -import static datadog.trace.instrumentation.api.AgentTracer.activeSpan; -import static datadog.trace.instrumentation.rmi.server.ServerDecorator.DECORATE; +import static datadog.trace.instrumentation.rmi.server.RmiServerDecorator.DECORATE; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; @@ -19,7 +18,7 @@ import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; import datadog.trace.instrumentation.api.AgentScope; import datadog.trace.instrumentation.api.AgentSpan; -import datadog.trace.instrumentation.api.AgentTracer; +import java.lang.reflect.Method; import java.util.Collections; import java.util.Map; import net.bytebuddy.asm.Advice; @@ -42,9 +41,9 @@ public final class RmiServerInstrumentation extends Instrumenter.Default { @Override public String[] helperClassNames() { return new String[] { - packageName + ".ServerDecorator", - packageName + ".RmiServerInstrumentation$ServerAdvice", - "datadog.trace.agent.decorator.BaseDecorator" + "datadog.trace.agent.decorator.ServerDecorator", + "datadog.trace.agent.decorator.BaseDecorator", + packageName + ".RmiServerDecorator" }; } @@ -63,33 +62,20 @@ public final class RmiServerInstrumentation extends Instrumenter.Default { public static class ServerAdvice { @Advice.OnMethodEnter(suppress = Throwable.class, inline = true) public static AgentScope onEnter( - @Advice.This final Object thiz, @Advice.Origin(value = "#m") final String method) { - final ContextStore callableContextStore = + @Advice.This final Object thiz, @Advice.Origin final Method method) { + final ContextStore threadContextStore = InstrumentationContext.get(Thread.class, AgentSpan.Context.class); final AgentSpan span = - startSpan(callableContextStore) - .setTag(DDTags.RESOURCE_NAME, thiz.getClass().getSimpleName() + "#" + method) + DECORATE + .startSpanWithContext(threadContextStore) + .setTag(DDTags.RESOURCE_NAME, DECORATE.spanNameForMethod(method)) .setTag("span.origin.type", thiz.getClass().getCanonicalName()); + DECORATE.afterStart(span); return activateSpan(span, true); } - public static AgentSpan startSpan( - final ContextStore callableContextStore) { - if (activeSpan() != null) { - return AgentTracer.startSpan("rmi.request"); - } - - final AgentSpan.Context context = callableContextStore.get(Thread.currentThread()); - - if (context == null) { - return AgentTracer.startSpan("rmi.request"); - } else { - return AgentTracer.startSpan("rmi.request", context); - } - } - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( @Advice.Enter final AgentScope scope, @Advice.Thrown final Throwable throwable) { diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/ServerDecorator.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/ServerDecorator.java deleted file mode 100644 index 73870eccfe..0000000000 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/ServerDecorator.java +++ /dev/null @@ -1,23 +0,0 @@ -package datadog.trace.instrumentation.rmi.server; - -import datadog.trace.agent.decorator.BaseDecorator; -import datadog.trace.api.DDSpanTypes; - -public class ServerDecorator extends BaseDecorator { - public static final ServerDecorator DECORATE = new ServerDecorator(); - - @Override - protected String[] instrumentationNames() { - return new String[] {"rmi"}; - } - - @Override - protected String spanType() { - return DDSpanTypes.RPC; - } - - @Override - protected String component() { - return "rmi-server"; - } -} diff --git a/dd-java-agent/instrumentation/rmi/src/test/groovy/RmiTest.groovy b/dd-java-agent/instrumentation/rmi/src/test/groovy/RmiTest.groovy index 203704fc5d..cb5a874b65 100644 --- a/dd-java-agent/instrumentation/rmi/src/test/groovy/RmiTest.groovy +++ b/dd-java-agent/instrumentation/rmi/src/test/groovy/RmiTest.groovy @@ -39,12 +39,13 @@ class RmiTest extends AgentTestRunner { trace(1, 2) { basicSpan(it, 0, "parent") span(1) { - resourceName "Greeter#hello" + resourceName "Greeter.hello" operationName "rmi.invoke" childOf span(0) spanType DDSpanTypes.RPC tags { + "$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT "$Tags.COMPONENT" "rmi-client" "span.origin.type" Greeter.canonicalName defaultTags() @@ -53,21 +54,23 @@ class RmiTest extends AgentTestRunner { } trace(0, 2) { span(0) { - resourceName "Server#hello" + resourceName "Server.hello" operationName "rmi.request" spanType DDSpanTypes.RPC tags { - "span.origin.type" server.class.canonicalName + "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER "$Tags.COMPONENT" "rmi-server" + "span.origin.type" server.class.canonicalName defaultTags(true) } } span(1) { - resourceName "Server#someMethod" + resourceName "Server.someMethod" operationName "rmi.request" spanType DDSpanTypes.RPC tags { + "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER "$Tags.COMPONENT" "rmi-server" "span.origin.type" server.class.canonicalName defaultTags() @@ -116,13 +119,14 @@ class RmiTest extends AgentTestRunner { trace(1, 2) { basicSpan(it, 0, "parent", null, thrownException) span(1) { - resourceName "Greeter#exceptional" + resourceName "Greeter.exceptional" operationName "rmi.invoke" childOf span(0) errored true spanType DDSpanTypes.RPC tags { + "$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT "$Tags.COMPONENT" "rmi-client" "span.origin.type" Greeter.canonicalName errorTags(RuntimeException, String) @@ -132,12 +136,13 @@ class RmiTest extends AgentTestRunner { } trace(0, 1) { span(0) { - resourceName "Server#exceptional" + resourceName "Server.exceptional" operationName "rmi.request" errored true spanType DDSpanTypes.RPC tags { + "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER "span.origin.type" server.class.canonicalName "$Tags.COMPONENT" "rmi-server" errorTags(RuntimeException, String) @@ -169,11 +174,12 @@ class RmiTest extends AgentTestRunner { trace(1, 2) { basicSpan(it, 0, "parent") span(1) { - resourceName "Greeter#hello" + resourceName "Greeter.hello" operationName "rmi.invoke" spanType DDSpanTypes.RPC childOf span(0) tags { + "$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT "$Tags.COMPONENT" "rmi-client" "span.origin.type" Greeter.canonicalName defaultTags() @@ -184,11 +190,12 @@ class RmiTest extends AgentTestRunner { trace(0, 1) { span(0) { childOf parentSpan - resourceName "ServerLegacy#hello" + resourceName "ServerLegacy.hello" operationName "rmi.request" spanType DDSpanTypes.RPC tags { "$Tags.COMPONENT" "rmi-server" + "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER "span.origin.type" server.class.canonicalName defaultTags(true) }