Skip to content
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

Implement code origin support for grpc server entry spans #7942

Merged
merged 4 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dd-java-agent/agent-bootstrap/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ dependencies {
api project(':internal-api')
api project(':internal-api:internal-api-9')
api project(':dd-java-agent:agent-logging')
api project(':dd-java-agent:agent-debugger:debugger-bootstrap')
api libs.slf4j
// ^ Generally a bad idea for libraries, but we're shadowing.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ public static LogProbe.Builder createProbeBuilder(

protected TestSnapshotListener installProbes(
Configuration configuration, ProbeDefinition... probes) {

config = mock(Config.class);
when(config.isDebuggerEnabled()).thenReturn(true);
when(config.isDebuggerClassFileDumpEnabled()).thenReturn(true);
Expand Down
2 changes: 2 additions & 0 deletions dd-java-agent/instrumentation/grpc-1.5/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ dependencies {
testImplementation group: 'io.grpc', name: 'grpc-protobuf', version: grpcVersion
testImplementation group: 'io.grpc', name: 'grpc-stub', version: grpcVersion
testImplementation group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'
testImplementation project(':dd-java-agent:agent-debugger')
testImplementation libs.bundles.mockito

latestDepTestImplementation sourceSets.test.output // include the protobuf generated classes
latestDepTestCompileOnly group: 'io.grpc', name: 'grpc-core', version: '1.+'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package datadog.trace.instrumentation.grpc.server;

import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.nameEndsWith;
import static datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo.entry;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;

import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.Instrumenter.ForTypeHierarchy;
import datadog.trace.agent.tooling.InstrumenterModule;
import datadog.trace.api.Platform;
import java.lang.reflect.Method;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

@AutoService(InstrumenterModule.class)
public class MethodHandlersInstrumentation extends InstrumenterModule.Tracing
implements ForTypeHierarchy {
private static final ElementMatcher<TypeDescription> METHOD_HANDLERS =
evanchooly marked this conversation as resolved.
Show resolved Hide resolved
nameEndsWith("$MethodHandlers");

public MethodHandlersInstrumentation() {
super("grpc", "grpc-server", "grpc-server-code-origin");
}

@Override
public String hierarchyMarkerType() {
return "io.grpc.MethodDescriptor";
}

@Override
public ElementMatcher<TypeDescription> hierarchyMatcher() {
return METHOD_HANDLERS;
}

@Override
public boolean isEnabled() {
return super.isEnabled() && !Platform.isGraalVM();
}

@Override
public void methodAdvice(MethodTransformer transformer) {
transformer.applyAdvice(
isConstructor().and(takesArguments(2)),
MethodHandlersInstrumentation.class.getName() + "$BuildAdvice");
}

public static class BuildAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(@Advice.Argument(0) Object serviceImpl) {
try {
Class<?> serviceClass = serviceImpl.getClass();
Class<?> superclass = serviceClass.getSuperclass();
if (superclass != null) {
for (Method method : superclass.getDeclaredMethods()) {
try {
entry(serviceClass.getDeclaredMethod(method.getName(), method.getParameterTypes()));
} catch (Throwable e) {
// service method not overridden on the impl. skipping instrumentation.
}
}
}
} catch (Throwable e) {
// this should be logged somehow
}
}
}
}
Loading
Loading