Skip to content

Commit 8d1b4d4

Browse files
Merge branch 'master' into ci/update-gradle-dependencies-instrumentation-20260320
2 parents 277b903 + 468d566 commit 8d1b4d4

5 files changed

Lines changed: 62 additions & 2 deletions

File tree

dd-java-agent/instrumentation/java/java-lang/java-lang-1.8/src/main/java/datadog/trace/instrumentation/java/lang/ProcessImplStartAdvice.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
package datadog.trace.instrumentation.java.lang;
22

3+
import datadog.trace.api.Config;
34
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
45
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
56
import datadog.trace.bootstrap.instrumentation.api.java.lang.ProcessImplInstrumentationHelpers;
7+
import java.util.Map;
68
import net.bytebuddy.asm.Advice;
79

810
class ProcessImplStartAdvice {
911
@Advice.OnMethodEnter(suppress = Throwable.class)
10-
public static AgentSpan beforeStart(@Advice.Argument(0) final String[] command) {
12+
public static AgentSpan beforeStart(
13+
@Advice.Argument(0) final String[] command,
14+
@Advice.Argument(1) final Map<String, String> environment) {
15+
String rootSessionId = Config.get().getRootSessionId();
16+
if (rootSessionId != null && environment != null) {
17+
environment.put("_DD_ROOT_JAVA_SESSION_ID", rootSessionId);
18+
}
19+
1120
if (!ProcessImplInstrumentationHelpers.ONLINE) {
1221
return null;
1322
}

dd-java-agent/instrumentation/java/java-lang/java-lang-1.8/src/test/groovy/datadog/trace/instrumentation/java/lang/ProcessImplInstrumentationSpecification.groovy

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package datadog.trace.instrumentation.java.lang
33
import datadog.trace.agent.test.InstrumentationSpecification
44
import datadog.trace.agent.test.asserts.SpanAssert
55
import datadog.trace.agent.test.utils.TraceUtils
6+
import datadog.trace.api.Config
67
import datadog.trace.bootstrap.ActiveSubsystems
78

89
import java.util.concurrent.TimeUnit
@@ -331,4 +332,18 @@ class ProcessImplInstrumentationSpecification extends InstrumentationSpecificati
331332
['/does/not/exist/cmd', '--pass', 'abc', '--token=def'] | '["/does/not/exist/cmd","--pass","?","--token=?"]'
332333
['/does/not/exist/md5', '-s', 'pony'] | '["/does/not/exist/md5","?","?"]'
333334
}
335+
336+
void 'child process inherits root session ID'() {
337+
when:
338+
def command = ['/bin/sh', '-c', 'echo $_DD_ROOT_JAVA_SESSION_ID']
339+
def builder = new ProcessBuilder(command)
340+
builder.environment()
341+
Process p = builder.start()
342+
def output = p.inputStream.text.trim()
343+
def terminated = p.waitFor(5, TimeUnit.SECONDS)
344+
345+
then:
346+
terminated
347+
output == Config.get().getRootSessionId()
348+
}
334349
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,12 @@ public class Config {
792792
*/
793793
static class RuntimeIdHolder {
794794
static final String runtimeId = RandomUtils.randomUUID().toString();
795+
static final String rootSessionId = initRootSessionId();
796+
797+
private static String initRootSessionId() {
798+
String inherited = ConfigHelper.env("_DD_ROOT_JAVA_SESSION_ID");
799+
return inherited != null ? inherited : runtimeId;
800+
}
795801
}
796802

797803
static class HostNameHolder {
@@ -3123,6 +3129,10 @@ public String getRuntimeId() {
31233129
return runtimeIdEnabled ? RuntimeIdHolder.runtimeId : "";
31243130
}
31253131

3132+
public String getRootSessionId() {
3133+
return runtimeIdEnabled ? RuntimeIdHolder.rootSessionId : "";
3134+
}
3135+
31263136
public Long getProcessId() {
31273137
return PidHelper.getPidAsLong();
31283138
}
@@ -5863,6 +5873,9 @@ public String toString() {
58635873
+ ", runtimeId='"
58645874
+ getRuntimeId()
58655875
+ '\''
5876+
+ ", rootSessionId='"
5877+
+ getRootSessionId()
5878+
+ '\''
58665879
+ ", runtimeVersion='"
58675880
+ runtimeVersion
58685881
+ ", apiKey="

telemetry/src/main/java/datadog/telemetry/TelemetryRequest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ public Request.Builder httpRequest() {
8080
builder.addHeader("DD-Telemetry-Debug-Enabled", "true");
8181
}
8282

83+
Config config = Config.get();
84+
String sessionId = config.getRuntimeId();
85+
if (sessionId != null && !sessionId.isEmpty()) {
86+
builder.addHeader("DD-Session-ID", sessionId);
87+
}
88+
String rootSessionId = config.getRootSessionId();
89+
if (rootSessionId != null && !rootSessionId.equals(sessionId)) {
90+
builder.addHeader("DD-Root-Session-ID", rootSessionId);
91+
}
92+
8393
return builder;
8494
}
8595

telemetry/src/test/groovy/datadog/telemetry/TestTelemetryRouter.groovy

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import datadog.telemetry.api.DistributionSeries
77
import datadog.telemetry.api.LogMessage
88
import datadog.telemetry.api.Metric
99
import datadog.telemetry.api.RequestType
10+
import datadog.trace.api.Config
1011
import datadog.trace.api.ConfigSetting
1112
import datadog.trace.api.telemetry.Endpoint
1213
import datadog.trace.api.telemetry.ProductChange
@@ -84,7 +85,8 @@ class TestTelemetryRouter extends TelemetryRouter {
8485
'DD-Client-Library-Language',
8586
'DD-Client-Library-Version',
8687
'DD-Telemetry-API-Version',
87-
'DD-Telemetry-Request-Type'
88+
'DD-Telemetry-Request-Type',
89+
'DD-Session-ID'
8890
])
8991
assert this.request.header('Content-Type') == 'application/json; charset=utf-8'
9092
assert this.request.header('Content-Length').toInteger() > 0
@@ -94,6 +96,17 @@ class TestTelemetryRouter extends TelemetryRouter {
9496
assert this.request.header('DD-Telemetry-Request-Type') == requestType.toString()
9597
def entityId = this.request.header('Datadog-Entity-ID')
9698
assert entityId == null || entityId.startsWith("in-") || entityId.startsWith("cin-")
99+
def sessionId = this.request.header('DD-Session-ID')
100+
assert sessionId =~ /[\da-f]{8}-([\da-f]{4}-){3}[\da-f]{12}/
101+
assert sessionId == Config.get().getRuntimeId()
102+
// DD-Root-Session-ID should only be present when inherited from a parent process
103+
// (i.e., when rootSessionId != runtimeId). In normal test context, they're equal.
104+
def rootSessionId = this.request.header('DD-Root-Session-ID')
105+
if (Config.get().getRootSessionId() == Config.get().getRuntimeId()) {
106+
assert rootSessionId == null
107+
} else {
108+
assert rootSessionId == Config.get().getRootSessionId()
109+
}
97110
return this
98111
}
99112

0 commit comments

Comments
 (0)