Skip to content

Commit 5b58772

Browse files
authored
Add Micronaut 4 support for code origin for spans (#8039)
Make Code Origin for spans feature independent from dynamic instrumentation so it could be enabled while DI is not Add in Status Logger the code origin feature status
1 parent 686f51a commit 5b58772

File tree

10 files changed

+111
-35
lines changed

10 files changed

+111
-35
lines changed

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ private enum AgentFeature {
105105
DEBUGGER(propertyNameToSystemPropertyName(DebuggerConfig.DEBUGGER_ENABLED), false),
106106
EXCEPTION_DEBUGGING(
107107
propertyNameToSystemPropertyName(DebuggerConfig.EXCEPTION_REPLAY_ENABLED), false),
108+
SPAN_ORIGIN(
109+
propertyNameToSystemPropertyName(TraceInstrumentationConfig.CODE_ORIGIN_FOR_SPANS_ENABLED),
110+
false),
108111
DATA_JOBS(propertyNameToSystemPropertyName(GeneralConfig.DATA_JOBS_ENABLED), false),
109112
AGENTLESS_LOG_SUBMISSION(
110113
propertyNameToSystemPropertyName(GeneralConfig.AGENTLESS_LOG_SUBMISSION_ENABLED), false);
@@ -152,6 +155,7 @@ public boolean isEnabledByDefault() {
152155
private static boolean telemetryEnabled = true;
153156
private static boolean debuggerEnabled = false;
154157
private static boolean exceptionDebuggingEnabled = false;
158+
private static boolean spanOriginEnabled = false;
155159
private static boolean agentlessLogSubmissionEnabled = false;
156160

157161
/**
@@ -263,6 +267,7 @@ public static void start(
263267
telemetryEnabled = isFeatureEnabled(AgentFeature.TELEMETRY);
264268
debuggerEnabled = isFeatureEnabled(AgentFeature.DEBUGGER);
265269
exceptionDebuggingEnabled = isFeatureEnabled(AgentFeature.EXCEPTION_DEBUGGING);
270+
spanOriginEnabled = isFeatureEnabled(AgentFeature.SPAN_ORIGIN);
266271
agentlessLogSubmissionEnabled = isFeatureEnabled(AgentFeature.AGENTLESS_LOG_SUBMISSION);
267272

268273
if (profilingEnabled) {
@@ -1073,7 +1078,7 @@ private static void shutdownProfilingAgent(final boolean sync) {
10731078
}
10741079

10751080
private static void maybeStartDebugger(Instrumentation inst, Class<?> scoClass, Object sco) {
1076-
if (!debuggerEnabled && !exceptionDebuggingEnabled) {
1081+
if (!debuggerEnabled && !exceptionDebuggingEnabled && !spanOriginEnabled) {
10771082
return;
10781083
}
10791084
if (!remoteConfigEnabled) {

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public static synchronized void run(
100100
DebuggerContext.initExceptionDebugger(defaultExceptionDebugger);
101101
}
102102
if (config.isDebuggerCodeOriginEnabled()) {
103+
LOGGER.info("Starting Code Origin for spans");
103104
DebuggerContext.initCodeOrigin(new DefaultCodeOriginRecorder(config, configurationUpdater));
104105
}
105106
if (config.isDebuggerInstrumentTheWorld()) {

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/codeorigin/DefaultCodeOriginRecorder.java

+18-32
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class DefaultCodeOriginRecorder implements CodeOriginRecorder {
3030

3131
private final ConfigurationUpdater configurationUpdater;
3232

33-
private final Map<String, CodeOriginProbe> fingerprints = new HashMap<>();
33+
private final Map<String, CodeOriginProbe> probesByFingerprint = new HashMap<>();
3434

3535
private final Map<String, CodeOriginProbe> probes = new ConcurrentHashMap<>();
3636

@@ -45,36 +45,28 @@ public DefaultCodeOriginRecorder(Config config, ConfigurationUpdater configurati
4545
public String captureCodeOrigin(boolean entry) {
4646
StackTraceElement element = findPlaceInStack();
4747
String fingerprint = Fingerprinter.fingerprint(element);
48-
CodeOriginProbe probe;
49-
50-
if (isAlreadyInstrumented(fingerprint)) {
51-
probe = fingerprints.get(fingerprint);
52-
} else {
53-
probe =
54-
createProbe(
55-
fingerprint,
56-
entry,
57-
Where.of(
58-
element.getClassName(),
59-
element.getMethodName(),
60-
null,
61-
String.valueOf(element.getLineNumber())));
48+
CodeOriginProbe probe = probesByFingerprint.get(fingerprint);
49+
if (probe == null) {
50+
Where where =
51+
Where.of(
52+
element.getClassName(),
53+
element.getMethodName(),
54+
null,
55+
String.valueOf(element.getLineNumber()));
56+
probe = createProbe(fingerprint, entry, where);
57+
LOG.debug("Creating probe for location {}", where);
6258
}
63-
6459
return probe.getId();
6560
}
6661

6762
@Override
6863
public String captureCodeOrigin(Method method, boolean entry) {
69-
CodeOriginProbe probe;
70-
71-
String fingerPrint = method.toString();
72-
if (isAlreadyInstrumented(fingerPrint)) {
73-
probe = fingerprints.get(fingerPrint);
74-
} else {
75-
probe = createProbe(fingerPrint, entry, Where.of(method));
64+
String fingerprint = method.toString();
65+
CodeOriginProbe probe = probesByFingerprint.get(fingerprint);
66+
if (probe == null) {
67+
probe = createProbe(fingerprint, entry, Where.of(method));
68+
LOG.debug("Creating probe for method {}", fingerprint);
7669
}
77-
7870
return probe.getId();
7971
}
8072

@@ -106,22 +98,16 @@ private StackTraceElement findPlaceInStack() {
10698
.orElse(null));
10799
}
108100

109-
public boolean isAlreadyInstrumented(String fingerprint) {
110-
return fingerprints.containsKey(fingerprint);
111-
}
112-
113101
void addFingerprint(String fingerprint, CodeOriginProbe probe) {
114-
fingerprints.putIfAbsent(fingerprint, probe);
102+
probesByFingerprint.putIfAbsent(fingerprint, probe);
115103
}
116104

117-
public String installProbe(CodeOriginProbe probe) {
105+
public void installProbe(CodeOriginProbe probe) {
118106
CodeOriginProbe installed = probes.putIfAbsent(probe.getId(), probe);
119107
if (installed == null) {
120108
AgentTaskScheduler.INSTANCE.execute(
121109
() -> configurationUpdater.accept(CODE_ORIGIN, getProbes()));
122-
return probe.getId();
123110
}
124-
return installed.getId();
125111
}
126112

127113
public CodeOriginProbe getProbe(String probeId) {

dd-java-agent/instrumentation/micronaut/build.gradle

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@
44

55
apply from: "$rootDir/gradle/java.gradle"
66

7+
muzzle {
8+
pass {
9+
name = "micronaut-common"
10+
group = "io.micronaut"
11+
module = "micronaut-http-server-netty"
12+
versions = "[2,)"
13+
}
14+
}
15+
716
dependencies {
817
compileOnly group: 'io.micronaut', name: 'micronaut-http-server-netty', version: '2.0.0'
18+
implementation project(':dd-java-agent:instrumentation:span-origin')
919
}

dd-java-agent/instrumentation/micronaut/http-server-netty-4.0/build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ addTestSuiteForDir('latestDepTest', 'test')
3030

3131
dependencies {
3232
main_java17CompileOnly group: 'io.micronaut', name: 'micronaut-http-server-netty', version: '4.0.0'
33+
implementation project(':dd-java-agent:instrumentation:micronaut')
3334

3435
// Added to ensure cross compatibility:
3536
testImplementation project(':dd-java-agent:instrumentation:micronaut:http-server-netty-2.0')
3637
testImplementation project(':dd-java-agent:instrumentation:micronaut:http-server-netty-3.0')
3738
testImplementation project(':dd-java-agent:instrumentation:netty-4.1')
39+
testImplementation project(':dd-java-agent:agent-debugger')
3840
testImplementation group: 'io.micronaut', name: 'micronaut-http-server-netty', version: '4.0.0', {
3941
exclude group: 'org.slf4j', module: 'slf4j-api'
4042
exclude group: 'ch.qos.logback', module: 'logback-classic'

dd-java-agent/instrumentation/micronaut/http-server-netty-4.0/src/test/groovy/MicronautTest.groovy

+32
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,49 @@ import datadog.trace.agent.test.asserts.TraceAssert
22
import datadog.trace.agent.test.base.HttpServer
33
import datadog.trace.agent.test.base.HttpServerTest
44
import datadog.trace.api.DDSpanTypes
5+
import datadog.trace.bootstrap.debugger.DebuggerContext
56
import datadog.trace.bootstrap.instrumentation.api.Tags
67
import datadog.trace.instrumentation.micronaut.v4_0.MicronautDecorator
78
import datadog.trace.instrumentation.netty41.server.NettyHttpServerDecorator
89
import test.MicronautServer
910

11+
import java.lang.reflect.Method
12+
1013
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR
1114
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
1215
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_FOUND
1316
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.PATH_PARAM
1417
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_ENCODED_BOTH
1518
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS
19+
import static datadog.trace.api.config.TraceInstrumentationConfig.CODE_ORIGIN_FOR_SPANS_ENABLED
1620

1721
class MicronautTest extends HttpServerTest<Object> {
1822

23+
def codeOriginRecorder
24+
25+
@Override
26+
protected void configurePreAgent() {
27+
super.configurePreAgent()
28+
injectSysConfig(CODE_ORIGIN_FOR_SPANS_ENABLED, "true")
29+
codeOriginRecorder = new DebuggerContext.CodeOriginRecorder() {
30+
def invoked = false
31+
@Override
32+
String captureCodeOrigin(boolean entry) {
33+
invoked = true
34+
return "done"
35+
}
36+
37+
@Override
38+
String captureCodeOrigin(Method method, boolean entry) {
39+
invoked = true
40+
return "done"
41+
}
42+
}
43+
DebuggerContext.initCodeOrigin(codeOriginRecorder)
44+
}
45+
46+
47+
1948
@Override
2049
HttpServer server() {
2150
return new MicronautServer()
@@ -67,6 +96,9 @@ class MicronautTest extends HttpServerTest<Object> {
6796

6897
@Override
6998
void handlerSpan(TraceAssert trace, ServerEndpoint endpoint = SUCCESS) {
99+
if (endpoint != NOT_FOUND) {
100+
assert codeOriginRecorder.invoked
101+
}
70102
trace.span {
71103
serviceName expectedServiceName()
72104
operationName "micronaut-controller"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package datadog.trace.instrumentation.micronaut;
2+
3+
import com.google.auto.service.AutoService;
4+
import datadog.trace.agent.tooling.InstrumenterModule;
5+
import datadog.trace.instrumentation.codeorigin.CodeOriginInstrumentation;
6+
import java.util.Arrays;
7+
import java.util.HashSet;
8+
import java.util.Set;
9+
10+
@AutoService(InstrumenterModule.class)
11+
public class MicronautCodeOriginInstrumentation extends CodeOriginInstrumentation {
12+
13+
public static final String IO_MICRONAUT_HTTP_ANNOTATION = "io.micronaut.http.annotation.";
14+
15+
public MicronautCodeOriginInstrumentation() {
16+
super("micronaut", "micronaut-span-origin");
17+
}
18+
19+
@Override
20+
public String muzzleDirective() {
21+
return "micronaut-common";
22+
}
23+
24+
@Override
25+
protected Set<String> getAnnotations() {
26+
return new HashSet<>(
27+
Arrays.asList(
28+
IO_MICRONAUT_HTTP_ANNOTATION + "Get",
29+
IO_MICRONAUT_HTTP_ANNOTATION + "Post",
30+
IO_MICRONAUT_HTTP_ANNOTATION + "Put",
31+
IO_MICRONAUT_HTTP_ANNOTATION + "Delete",
32+
IO_MICRONAUT_HTTP_ANNOTATION + "Patch",
33+
IO_MICRONAUT_HTTP_ANNOTATION + "Head",
34+
IO_MICRONAUT_HTTP_ANNOTATION + "Options"));
35+
}
36+
}

dd-java-agent/instrumentation/span-origin/src/main/java/datadog/trace/instrumentation/codeorigin/CodeOriginInstrumentation.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ public abstract class CodeOriginInstrumentation extends Tracing implements ForTy
1717
private final OneOf<NamedElement> matcher;
1818

1919
@SuppressForbidden
20-
public CodeOriginInstrumentation(String instrumentationName) {
21-
super(instrumentationName);
20+
public CodeOriginInstrumentation(String instrumentationName, String... additionalNames) {
21+
super(instrumentationName, additionalNames);
2222
this.matcher = NameMatchers.namedOneOf(getAnnotations());
2323
}
2424

dd-trace-core/src/main/java/datadog/trace/core/StatusLogger.java

+2
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ public void toJson(JsonWriter writer, Config config) throws IOException {
114114
writer.value(config.isDebuggerEnabled());
115115
writer.name("debugger_exception_enabled");
116116
writer.value(config.isDebuggerExceptionEnabled());
117+
writer.name("debugger_span_origin_enabled");
118+
writer.value(config.isDebuggerCodeOriginEnabled());
117119
writer.name("appsec_enabled");
118120
writer.value(config.getAppSecActivation().toString());
119121
writer.name("appsec_rules_file_path");

internal-api/src/main/java/datadog/trace/api/Config.java

+2
Original file line numberDiff line numberDiff line change
@@ -4326,6 +4326,8 @@ public String toString() {
43264326
+ debuggerSymbolIncludes
43274327
+ ", debuggerExceptionEnabled="
43284328
+ debuggerExceptionEnabled
4329+
+ ", debuggerCodeOriginEnabled="
4330+
+ debuggerCodeOriginEnabled
43294331
+ ", awsPropagationEnabled="
43304332
+ awsPropagationEnabled
43314333
+ ", sqsPropagationEnabled="

0 commit comments

Comments
 (0)