[rmi] Split context propagation to server and client instrumentation

+ Separate extra code from advices
 + cleanup helper definitions
This commit is contained in:
Pawel Chojnacki 2019-12-20 12:29:48 +01:00
parent c3308042d3
commit 3f21f6419d
14 changed files with 274 additions and 210 deletions

View File

@ -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.activateSpan;
import static datadog.trace.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.instrumentation.api.AgentTracer.activeSpan;
import static datadog.trace.instrumentation.api.AgentTracer.startSpan; 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.api.DDTags;
import datadog.trace.instrumentation.api.AgentScope; import datadog.trace.instrumentation.api.AgentScope;
@ -11,7 +11,7 @@ import datadog.trace.instrumentation.api.AgentSpan;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
public class ClientAdvice { public class RmiClientAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static AgentScope onEnter(@Advice.Argument(value = 1) final Method method) { public static AgentScope onEnter(@Advice.Argument(value = 1) final Method method) {
if (activeSpan() == null) { if (activeSpan() == null) {
@ -19,9 +19,7 @@ public class ClientAdvice {
} }
final AgentSpan span = final AgentSpan span =
startSpan("rmi.invoke") startSpan("rmi.invoke")
.setTag( .setTag(DDTags.RESOURCE_NAME, DECORATE.spanNameForMethod(method))
DDTags.RESOURCE_NAME,
method.getDeclaringClass().getSimpleName() + "#" + method.getName())
.setTag("span.origin.type", method.getDeclaringClass().getCanonicalName()); .setTag("span.origin.type", method.getDeclaringClass().getCanonicalName());
DECORATE.afterStart(span); DECORATE.afterStart(span);

View File

@ -1,10 +1,10 @@
package datadog.trace.instrumentation.rmi.client; package datadog.trace.instrumentation.rmi.client;
import datadog.trace.agent.decorator.BaseDecorator; import datadog.trace.agent.decorator.ClientDecorator;
import datadog.trace.api.DDSpanTypes; import datadog.trace.api.DDSpanTypes;
public class ClientDecorator extends BaseDecorator { public class RmiClientDecorator extends ClientDecorator {
public static final ClientDecorator DECORATE = new ClientDecorator(); public static final RmiClientDecorator DECORATE = new RmiClientDecorator();
@Override @Override
protected String[] instrumentationNames() { protected String[] instrumentationNames() {
@ -20,4 +20,9 @@ public class ClientDecorator extends BaseDecorator {
protected String component() { protected String component() {
return "rmi-client"; return "rmi-client";
} }
@Override
protected String service() {
return "rmi";
}
} }

View File

@ -31,8 +31,8 @@ public final class RmiClientInstrumentation extends Instrumenter.Default {
public String[] helperClassNames() { public String[] helperClassNames() {
return new String[] { return new String[] {
"datadog.trace.agent.decorator.BaseDecorator", "datadog.trace.agent.decorator.BaseDecorator",
packageName + ".ClientDecorator", "datadog.trace.agent.decorator.ClientDecorator",
packageName + ".ClientAdvice" packageName + ".RmiClientDecorator"
}; };
} }
@ -43,6 +43,6 @@ public final class RmiClientInstrumentation extends Instrumenter.Default {
.and(named("invoke")) .and(named("invoke"))
.and(takesArgument(0, named("java.rmi.Remote"))) .and(takesArgument(0, named("java.rmi.Remote")))
.and(takesArgument(1, named("java.lang.reflect.Method"))), .and(takesArgument(1, named("java.lang.reflect.Method"))),
packageName + ".ClientAdvice"); packageName + ".RmiClientAdvice");
} }
} }

View File

@ -1,78 +1,38 @@
package datadog.trace.instrumentation.rmi.context; 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.api.AgentTracer.propagate;
import static datadog.trace.instrumentation.rmi.context.ContextPayload.SETTER; import static datadog.trace.instrumentation.rmi.context.ContextPayload.SETTER;
import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.ContextStore;
import datadog.trace.bootstrap.InstrumentationContext;
import datadog.trace.instrumentation.api.AgentSpan; import datadog.trace.instrumentation.api.AgentSpan;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.rmi.NoSuchObjectException; import java.rmi.NoSuchObjectException;
import java.rmi.server.ObjID; import java.rmi.server.ObjID;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.asm.Advice;
import sun.rmi.transport.Connection; import sun.rmi.transport.Connection;
import sun.rmi.transport.StreamRemoteCall; import sun.rmi.transport.StreamRemoteCall;
import sun.rmi.transport.TransportConstants; import sun.rmi.transport.TransportConstants;
/**
* Main entry point for transferring context between RMI service.
*
* <p>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
*
* <p>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
*
* <p>As well as optional baggage items
*
* <p>On the other side of the communication a special Dispatcher is created when a message with
* DD_CONTEXT_CALL_ID is received.
*
* <p>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 @Slf4j
public class StreamRemoteCallConstructorAdvice { public class ContextPropagator {
public static final ObjID ACTIVATOR_ID = new ObjID(ObjID.ACTIVATOR_ID); private static final ObjID ACTIVATOR_ID = new ObjID(ObjID.ACTIVATOR_ID);
public static final ObjID DGC_ID = new ObjID(ObjID.DGC_ID); private static final ObjID DGC_ID = new ObjID(ObjID.DGC_ID);
public static final ObjID REGISTRY_ID = new ObjID(ObjID.REGISTRY_ID); private 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 ObjID DD_CONTEXT_CALL_ID = new ObjID("Datadog.v1.context_call".hashCode());
public static final int CONTEXT_CHECK_CALL_OP_ID = -1; private static final int CONTEXT_CHECK_CALL_OP_ID = -1;
public static final int CONTEXT_PASS_OPERATION_ID = -2; 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<Connection, Boolean> contextStore =
InstrumentationContext.get(Connection.class, Boolean.class);
attemptToPropagateContext(contextStore, c);
}
public static boolean isRMIInternalObject(final ObjID id) { public static boolean isRMIInternalObject(final ObjID id) {
return ACTIVATOR_ID.equals(id) || DGC_ID.equals(id) || REGISTRY_ID.equals(id); return ACTIVATOR_ID.equals(id) || DGC_ID.equals(id) || REGISTRY_ID.equals(id);
} }
public static void attemptToPropagateContext( public static final ContextPropagator PROPAGATOR = new ContextPropagator();
final ContextStore<Connection, Boolean> contextStore, final Connection c) {
final AgentSpan span = activeSpan();
if (span == null) {
return;
}
public void attemptToPropagateContext(
final ContextStore<Connection, Boolean> contextStore,
final Connection c,
final AgentSpan span) {
if (checkIfContextCanBePassed(contextStore, c)) { if (checkIfContextCanBePassed(contextStore, c)) {
final ContextPayload payload = new ContextPayload(); final ContextPayload payload = new ContextPayload();
propagate().inject(span, payload, SETTER); propagate().inject(span, payload, SETTER);
@ -82,7 +42,7 @@ public class StreamRemoteCallConstructorAdvice {
} }
} }
private static boolean checkIfContextCanBePassed( private boolean checkIfContextCanBePassed(
final ContextStore<Connection, Boolean> contextStore, final Connection c) { final ContextStore<Connection, Boolean> contextStore, final Connection c) {
final Boolean storedResult = contextStore.get(c); final Boolean storedResult = contextStore.get(c);
if (storedResult != null) { if (storedResult != null) {
@ -94,7 +54,7 @@ public class StreamRemoteCallConstructorAdvice {
return result; return result;
} }
private static boolean syntheticCall( private boolean syntheticCall(
final Connection c, final ContextPayload payload, final int operationId) { final Connection c, final ContextPayload payload, final int operationId) {
final StreamRemoteCall shareContextCall = new StreamRemoteCall(c); final StreamRemoteCall shareContextCall = new StreamRemoteCall(c);
try { try {

View File

@ -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<? super TypeDescription> 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<String, String> contextStore() {
final HashMap<String, String> 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<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
final Map<ElementMatcher<? super MethodDescription>, 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);
}
}

View File

@ -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<? super TypeDescription> typeMatcher() {
return not(isInterface()).and(safeHasSuperType(named("sun.rmi.transport.StreamRemoteCall")));
}
@Override
public Map<String, String> 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<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isConstructor()
.and(takesArgument(0, named("sun.rmi.transport.Connection")))
.and(takesArgument(1, named("java.rmi.server.ObjID"))),
packageName + ".StreamRemoteCallConstructorAdvice");
}
}

View File

@ -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.
*
* <p>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
*
* <p>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
*
* <p>As well as optional baggage items
*
* <p>On the other side of the communication a special Dispatcher is created when a message with
* DD_CONTEXT_CALL_ID is received.
*
* <p>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<Connection, Boolean> contextStore =
InstrumentationContext.get(Connection.class, Boolean.class);
PROPAGATOR.attemptToPropagateContext(contextStore, c, activeSpan);
}
}

View File

@ -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.api.AgentTracer.propagate;
import static datadog.trace.instrumentation.rmi.context.ContextPayload.GETTER; import static datadog.trace.instrumentation.rmi.context.ContextPayload.GETTER;
import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.ContextStore;
import datadog.trace.instrumentation.api.AgentSpan; 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.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.rmi.Remote; import java.rmi.Remote;
@ -25,7 +27,7 @@ public class ContextDispatcher implements Dispatcher {
final int operationId = in.readInt(); final int operationId = in.readInt();
in.readLong(); // skip 8 bytes 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); final ContextPayload payload = ContextPayload.read(in);
if (payload != null) { if (payload != null) {
final AgentSpan.Context context = propagate().extract(payload, GETTER); final AgentSpan.Context context = propagate().extract(payload, GETTER);

View File

@ -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.ContextStore;
import datadog.trace.bootstrap.InstrumentationContext; import datadog.trace.bootstrap.InstrumentationContext;
import datadog.trace.instrumentation.api.AgentSpan; import datadog.trace.instrumentation.api.AgentSpan;
import java.rmi.Remote; import java.rmi.Remote;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import sun.rmi.transport.Target; import sun.rmi.transport.Target;
@Slf4j
public class ObjectTableAdvice { public class ObjectTableAdvice {
public static final DummyRemote DUMMY_REMOTE = new DummyRemote();
@Advice.OnMethodExit(suppress = Throwable.class) @Advice.OnMethodExit(suppress = Throwable.class)
public static void methodExit( public static void methodExit(
@ -31,12 +28,14 @@ public class ObjectTableAdvice {
result = result =
new Target( new Target(
DUMMY_REMOTE, NoopRemote.NOOP_REMOTE,
new ContextDispatcher(callableContextStore), new ContextDispatcher(callableContextStore),
DUMMY_REMOTE, NoopRemote.NOOP_REMOTE,
DD_CONTEXT_CALL_ID, DD_CONTEXT_CALL_ID,
false); false);
} }
public static class DummyRemote implements Remote {} public static class NoopRemote implements Remote {
public static final NoopRemote NOOP_REMOTE = new NoopRemote();
}
} }

View File

@ -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<? super TypeDescription> typeMatcher() {
return not(isInterface()).and(safeHasSuperType(named("sun.rmi.transport.ObjectTable")));
}
@Override
public Map<String, String> 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<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod()
.and(isStatic())
.and(named("getTarget"))
.and((takesArgument(0, named("sun.rmi.transport.ObjectEndpoint")))),
packageName + ".ObjectTableAdvice");
}
}

View File

@ -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<Thread, AgentSpan.Context> 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";
}
}

View File

@ -2,8 +2,7 @@ package datadog.trace.instrumentation.rmi.server;
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType;
import static datadog.trace.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.instrumentation.api.AgentTracer.activateSpan;
import static datadog.trace.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.instrumentation.rmi.server.RmiServerDecorator.DECORATE;
import static datadog.trace.instrumentation.rmi.server.ServerDecorator.DECORATE;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isMethod;
@ -19,7 +18,7 @@ import datadog.trace.bootstrap.ContextStore;
import datadog.trace.bootstrap.InstrumentationContext; import datadog.trace.bootstrap.InstrumentationContext;
import datadog.trace.instrumentation.api.AgentScope; import datadog.trace.instrumentation.api.AgentScope;
import datadog.trace.instrumentation.api.AgentSpan; import datadog.trace.instrumentation.api.AgentSpan;
import datadog.trace.instrumentation.api.AgentTracer; import java.lang.reflect.Method;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
@ -42,9 +41,9 @@ public final class RmiServerInstrumentation extends Instrumenter.Default {
@Override @Override
public String[] helperClassNames() { public String[] helperClassNames() {
return new String[] { return new String[] {
packageName + ".ServerDecorator", "datadog.trace.agent.decorator.ServerDecorator",
packageName + ".RmiServerInstrumentation$ServerAdvice", "datadog.trace.agent.decorator.BaseDecorator",
"datadog.trace.agent.decorator.BaseDecorator" packageName + ".RmiServerDecorator"
}; };
} }
@ -63,33 +62,20 @@ public final class RmiServerInstrumentation extends Instrumenter.Default {
public static class ServerAdvice { public static class ServerAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class, inline = true) @Advice.OnMethodEnter(suppress = Throwable.class, inline = true)
public static AgentScope onEnter( public static AgentScope onEnter(
@Advice.This final Object thiz, @Advice.Origin(value = "#m") final String method) { @Advice.This final Object thiz, @Advice.Origin final Method method) {
final ContextStore<Thread, AgentSpan.Context> callableContextStore = final ContextStore<Thread, AgentSpan.Context> threadContextStore =
InstrumentationContext.get(Thread.class, AgentSpan.Context.class); InstrumentationContext.get(Thread.class, AgentSpan.Context.class);
final AgentSpan span = final AgentSpan span =
startSpan(callableContextStore) DECORATE
.setTag(DDTags.RESOURCE_NAME, thiz.getClass().getSimpleName() + "#" + method) .startSpanWithContext(threadContextStore)
.setTag(DDTags.RESOURCE_NAME, DECORATE.spanNameForMethod(method))
.setTag("span.origin.type", thiz.getClass().getCanonicalName()); .setTag("span.origin.type", thiz.getClass().getCanonicalName());
DECORATE.afterStart(span); DECORATE.afterStart(span);
return activateSpan(span, true); return activateSpan(span, true);
} }
public static AgentSpan startSpan(
final ContextStore<Thread, AgentSpan.Context> 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) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan( public static void stopSpan(
@Advice.Enter final AgentScope scope, @Advice.Thrown final Throwable throwable) { @Advice.Enter final AgentScope scope, @Advice.Thrown final Throwable throwable) {

View File

@ -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";
}
}

View File

@ -39,12 +39,13 @@ class RmiTest extends AgentTestRunner {
trace(1, 2) { trace(1, 2) {
basicSpan(it, 0, "parent") basicSpan(it, 0, "parent")
span(1) { span(1) {
resourceName "Greeter#hello" resourceName "Greeter.hello"
operationName "rmi.invoke" operationName "rmi.invoke"
childOf span(0) childOf span(0)
spanType DDSpanTypes.RPC spanType DDSpanTypes.RPC
tags { tags {
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
"$Tags.COMPONENT" "rmi-client" "$Tags.COMPONENT" "rmi-client"
"span.origin.type" Greeter.canonicalName "span.origin.type" Greeter.canonicalName
defaultTags() defaultTags()
@ -53,21 +54,23 @@ class RmiTest extends AgentTestRunner {
} }
trace(0, 2) { trace(0, 2) {
span(0) { span(0) {
resourceName "Server#hello" resourceName "Server.hello"
operationName "rmi.request" operationName "rmi.request"
spanType DDSpanTypes.RPC spanType DDSpanTypes.RPC
tags { tags {
"span.origin.type" server.class.canonicalName "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER
"$Tags.COMPONENT" "rmi-server" "$Tags.COMPONENT" "rmi-server"
"span.origin.type" server.class.canonicalName
defaultTags(true) defaultTags(true)
} }
} }
span(1) { span(1) {
resourceName "Server#someMethod" resourceName "Server.someMethod"
operationName "rmi.request" operationName "rmi.request"
spanType DDSpanTypes.RPC spanType DDSpanTypes.RPC
tags { tags {
"$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER
"$Tags.COMPONENT" "rmi-server" "$Tags.COMPONENT" "rmi-server"
"span.origin.type" server.class.canonicalName "span.origin.type" server.class.canonicalName
defaultTags() defaultTags()
@ -116,13 +119,14 @@ class RmiTest extends AgentTestRunner {
trace(1, 2) { trace(1, 2) {
basicSpan(it, 0, "parent", null, thrownException) basicSpan(it, 0, "parent", null, thrownException)
span(1) { span(1) {
resourceName "Greeter#exceptional" resourceName "Greeter.exceptional"
operationName "rmi.invoke" operationName "rmi.invoke"
childOf span(0) childOf span(0)
errored true errored true
spanType DDSpanTypes.RPC spanType DDSpanTypes.RPC
tags { tags {
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
"$Tags.COMPONENT" "rmi-client" "$Tags.COMPONENT" "rmi-client"
"span.origin.type" Greeter.canonicalName "span.origin.type" Greeter.canonicalName
errorTags(RuntimeException, String) errorTags(RuntimeException, String)
@ -132,12 +136,13 @@ class RmiTest extends AgentTestRunner {
} }
trace(0, 1) { trace(0, 1) {
span(0) { span(0) {
resourceName "Server#exceptional" resourceName "Server.exceptional"
operationName "rmi.request" operationName "rmi.request"
errored true errored true
spanType DDSpanTypes.RPC spanType DDSpanTypes.RPC
tags { tags {
"$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER
"span.origin.type" server.class.canonicalName "span.origin.type" server.class.canonicalName
"$Tags.COMPONENT" "rmi-server" "$Tags.COMPONENT" "rmi-server"
errorTags(RuntimeException, String) errorTags(RuntimeException, String)
@ -169,11 +174,12 @@ class RmiTest extends AgentTestRunner {
trace(1, 2) { trace(1, 2) {
basicSpan(it, 0, "parent") basicSpan(it, 0, "parent")
span(1) { span(1) {
resourceName "Greeter#hello" resourceName "Greeter.hello"
operationName "rmi.invoke" operationName "rmi.invoke"
spanType DDSpanTypes.RPC spanType DDSpanTypes.RPC
childOf span(0) childOf span(0)
tags { tags {
"$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT
"$Tags.COMPONENT" "rmi-client" "$Tags.COMPONENT" "rmi-client"
"span.origin.type" Greeter.canonicalName "span.origin.type" Greeter.canonicalName
defaultTags() defaultTags()
@ -184,11 +190,12 @@ class RmiTest extends AgentTestRunner {
trace(0, 1) { trace(0, 1) {
span(0) { span(0) {
childOf parentSpan childOf parentSpan
resourceName "ServerLegacy#hello" resourceName "ServerLegacy.hello"
operationName "rmi.request" operationName "rmi.request"
spanType DDSpanTypes.RPC spanType DDSpanTypes.RPC
tags { tags {
"$Tags.COMPONENT" "rmi-server" "$Tags.COMPONENT" "rmi-server"
"$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER
"span.origin.type" server.class.canonicalName "span.origin.type" server.class.canonicalName
defaultTags(true) defaultTags(true)
} }