Skip to content

Commit 68fd45d

Browse files
Merge branch 'master' into daniel.mohedano/refactor-execution-policies
2 parents 1f7c3ab + 969d21d commit 68fd45d

33 files changed

Lines changed: 955 additions & 121 deletions

File tree

.github/workflows/analyze-changes.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
${{ runner.os }}-gradle-
3131
3232
- name: Initialize CodeQL
33-
uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
33+
uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
3434
with:
3535
languages: 'java'
3636
build-mode: 'manual'
@@ -49,7 +49,7 @@ jobs:
4949
--build-cache --parallel --stacktrace --no-daemon --max-workers=4
5050
5151
- name: Perform CodeQL Analysis and upload results to GitHub Security tab
52-
uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
52+
uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
5353

5454
trivy:
5555
name: Analyze changes with Trivy
@@ -101,7 +101,7 @@ jobs:
101101
ls -laR "./workspace/.trivy"
102102
103103
- name: Run Trivy security scanner
104-
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284 # v0.34.0
104+
uses: aquasecurity/trivy-action@e368e328979b113139d6f9068e03accaed98a518 # v0.34.1
105105
with:
106106
scan-type: rootfs
107107
scan-ref: './workspace/.trivy/'
@@ -114,7 +114,7 @@ jobs:
114114
TRIVY_JAVA_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-java-db,public.ecr.aws/aquasecurity/trivy-java-db
115115

116116
- name: Upload Trivy scan results to GitHub Security tab
117-
uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
117+
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
118118
if: always()
119119
with:
120120
sarif_file: 'trivy-results.sarif'

.gitlab/find-gh-base-ref.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ if [[ $CI_COMMIT_BRANCH =~ ^(master|release/.*)$ ]]; then
1414
exit 1
1515
fi
1616

17+
# See .test_job declaration
18+
if [[ $CI_COMMIT_BRANCH =~ ^(mq-working-branch-|gh-readonly-queue/) ]]; then
19+
echo "CI_COMMIT_BRANCH is a merge queue branch, skipping base ref detection" >&2
20+
exit 1
21+
fi
22+
1723
CURRENT_HEAD_SHA="$(git rev-parse HEAD)"
1824
if [[ -z "${CURRENT_HEAD_SHA:-}" ]]; then
1925
echo "Failed to determine current HEAD SHA" >&2

buildSrc/src/main/kotlin/datadog/gradle/plugin/dump/DumpHangedTestPlugin.kt

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import java.util.concurrent.ScheduledExecutorService
2020
import java.util.concurrent.ScheduledFuture
2121
import java.util.concurrent.TimeUnit
2222
import javax.inject.Inject
23+
import kotlin.jvm.optionals.getOrElse
2324

2425
/**
2526
* Plugin to collect thread and heap dumps for hanged tests.
@@ -120,43 +121,27 @@ class DumpHangedTestPlugin : Plugin<Project> {
120121

121122
dumpsDir.mkdirs()
122123

123-
fun file(name: String, ext: String = "log") =
124-
File(dumpsDir, "$name-${System.currentTimeMillis()}.$ext")
124+
ProcessHandle.current().children()
125+
.filter { it.info().commandLine().getOrElse { "" }.contains("Gradle Test Executor") }
126+
.forEach { process ->
127+
collectDump(dumpsDir, process)
125128

126-
// Collect all JVMs pids.
127-
val allJavaProcessesFile = file("all-java-processes")
128-
runCmd(Redirect.to(allJavaProcessesFile), "jcmd", "-l")
129-
130-
// On IBM JDK thread dump can be collected by signaling the matching `Gradle Test Executor` process with `kill -3`.
131-
// It will be writen into `/tmp/javacore.YYYYMMDD.HHMMSS.PID.SEQ.txt
132-
if (isIbm8(allJavaProcessesFile)) {
133-
val allProcessesFile = file("all-processes")
134-
runCmd(Redirect.to(allProcessesFile), "ps", "-ef")
135-
extractPidsIbm8(allProcessesFile).forEach { ibm8Pid ->
136-
runCmd(Redirect.INHERIT, "kill", "-3", ibm8Pid)
137-
}
138-
} else {
139-
val pids = extractPids(allJavaProcessesFile)
140-
141-
pids.forEach { pid ->
142-
// Collect heap dump by pid.
143-
val heapDumpPath = file("${pid}-heap-dump", "hprof").absolutePath
144-
runCmd(Redirect.INHERIT, "jcmd", pid, "GC.heap_dump", heapDumpPath)
145-
146-
// Collect thread dump by pid.
147-
val threadDumpFile = file("${pid}-thread-dump")
148-
runCmd(Redirect.to(threadDumpFile), "jcmd", pid, "Thread.print", "-l")
129+
process.children().forEach { child ->
130+
collectDump(dumpsDir, child)
131+
}
149132
}
150133

151-
// Just in case collect all thread dumps by using special PID `0`.
152-
val allThreadsFile = file("all-thread-dumps")
153-
runCmd(Redirect.to(allThreadsFile), "jcmd", "0", "Thread.print", "-l")
154-
}
134+
// Just in case collect all thread dumps by using special PID `0`.
135+
val allThreadsFile = file(dumpsDir, "all-thread-dumps")
136+
runCmd(Redirect.to(allThreadsFile), "jcmd", "0", "Thread.print", "-l")
155137
} catch (e: Throwable) {
156138
t.logger.warn("Taking dumps failed with error: ${e.message ?: e.javaClass.name}, for ${t.path}")
157139
}
158140
}
159141

142+
private fun file(baseDir: File, name: String, ext: String = "log") =
143+
File(baseDir, "$name-${System.currentTimeMillis()}.$ext")
144+
160145
private fun cleanup(t: Task) {
161146
val future = t.extra
162147
.takeIf { it.has(DUMP_FUTURE_KEY) }
@@ -183,23 +168,24 @@ class DumpHangedTestPlugin : Plugin<Project> {
183168
}
184169
}
185170

186-
private fun isIbm8(file: File): Boolean =
187-
file.readLines().any { it.contains("-PtestJvm=ibm8") }
188-
189-
private fun extractPids(file: File): List<String> =
190-
file.readLines()
191-
.filter { it.contains("Gradle Test Executor") }
192-
.map { it.substringBefore(' ') }
193-
194-
private fun extractPidsIbm8(file: File): List<String> =
195-
file.readLines()
196-
.filter { it.contains("Gradle Test Executor") }
197-
.filter { it.contains("ibm", ignoreCase = true) }
198-
.mapNotNull(::extractPid)
199-
200-
private val whitespaceRegex = Regex("\\s+")
171+
private fun collectDump(
172+
baseDir: File,
173+
process: ProcessHandle
174+
) {
175+
val pid = process.pid().toString()
201176

202-
// ps -ef format produce output like: UID PID PPID ...
203-
private fun extractPid(line: String): String? =
204-
line.trimStart().split(whitespaceRegex, limit = 3).getOrNull(1)
177+
if (process.info().command().getOrElse { "" }.contains("/ibm8")) {
178+
// On IBM JDK thread dump can be collected by signaling process with `kill -3`.
179+
// It will be writen into `/tmp/javacore.YYYYMMDD.HHMMSS.PID.SEQ.txt
180+
runCmd(Redirect.INHERIT, "kill", "-3", pid)
181+
} else {
182+
// Collect heap dump by pid.
183+
val heapDumpPath = file(baseDir, "$pid-heap-dump", "hprof").absolutePath
184+
runCmd(Redirect.INHERIT, "jcmd", pid, "GC.heap_dump", heapDumpPath)
185+
186+
// Collect thread dump by pid.
187+
val threadDumpFile = file(baseDir, "$pid-thread-dump", "log")
188+
runCmd(Redirect.to(threadDumpFile), "jcmd", pid, "Thread.print", "-l")
189+
}
190+
}
205191
}
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
package datadog.trace.bootstrap.instrumentation.decorator;
22

33
import datadog.trace.api.DDTags;
4+
import datadog.trace.api.TagMap;
45
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
56
import datadog.trace.bootstrap.instrumentation.api.Tags;
67

78
public abstract class ServerDecorator extends BaseDecorator {
9+
private static final TagMap.Entry SPAN_KIND_ENTRY =
10+
TagMap.Entry.create(Tags.SPAN_KIND, Tags.SPAN_KIND_SERVER);
11+
private static final TagMap.Entry LANG_ENTRY =
12+
TagMap.Entry.create(DDTags.LANGUAGE_TAG_KEY, DDTags.LANGUAGE_TAG_VALUE);
813

914
@Override
1015
public AgentSpan afterStart(final AgentSpan span) {
11-
span.setTag(Tags.SPAN_KIND, Tags.SPAN_KIND_SERVER);
12-
span.setTag(DDTags.LANGUAGE_TAG_KEY, DDTags.LANGUAGE_TAG_VALUE);
16+
span.setTag(SPAN_KIND_ENTRY);
17+
span.setTag(LANG_ENTRY);
18+
1319
return super.afterStart(span);
1420
}
1521
}

dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/BaseDecoratorTest.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ class BaseDecoratorTest extends DDSpecification {
3030
1 * spanContext.setIntegrationName("test-component")
3131
_ * span.setTag(_)
3232
_ * span.setTag(_, _) // Want to allow other calls from child implementations.
33+
_ * span.setTag(_)
3334
_ * span.setMeasured(true)
3435
_ * span.setMetric(_)
3536
_ * span.setMetric(_, _)
37+
_ * span.setMetric(_)
3638
_ * span.setServiceName(_, _)
3739
_ * span.setOperationName(_)
3840
_ * span.setSamplingPriority(_)

dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/ServerDecoratorTest.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ class ServerDecoratorTest extends BaseDecoratorTest {
2222
decorator.afterStart(span)
2323

2424
then:
25-
1 * span.setTag(LANGUAGE_TAG_KEY, LANGUAGE_TAG_VALUE)
25+
1 * span.setTag(TagMap.Entry.create(LANGUAGE_TAG_KEY, LANGUAGE_TAG_VALUE))
2626
1 * span.setTag(TagMap.Entry.create(COMPONENT, "test-component"))
2727
1 * span.context() >> spanContext
2828
1 * spanContext.setIntegrationName("test-component")
29-
1 * span.setTag(SPAN_KIND, "server")
29+
1 * span.setTag(TagMap.Entry.create(SPAN_KIND, "server"))
3030
1 * span.setSpanType(decorator.spanType())
3131
if (decorator.traceAnalyticsEnabled) {
3232
1 * span.setMetric(TagMap.Entry.create(ANALYTICS_SAMPLE_RATE, 1.0))

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/JarScanner.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.datadog.debugger.symbol;
22

3+
import java.net.URI;
34
import java.net.URISyntaxException;
45
import java.net.URL;
56
import java.nio.file.Path;
@@ -65,6 +66,13 @@ public static String trimPrefixes(String classFilePath) {
6566
private static Path getPathFromPrefixedFileName(String locationStr, String prefix, int endIdx) {
6667
String fileName = locationStr.substring(prefix.length(), endIdx);
6768
LOGGER.debug("jar filename={}", fileName);
68-
return Paths.get(fileName);
69+
try {
70+
// Reconstruct a file URI and use Paths.get(URI) to correctly handle
71+
// platform-specific paths, including Windows drive letters (e.g. /C:/...)
72+
return Paths.get(new URI("file:" + fileName));
73+
} catch (URISyntaxException e) {
74+
LOGGER.debug("Failed to parse as URI: {}, falling back to direct path", fileName, e);
75+
return Paths.get(fileName);
76+
}
6977
}
7078
}

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/JarScannerTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
import java.net.URISyntaxException;
99
import java.net.URL;
1010
import java.net.URLClassLoader;
11+
import java.nio.file.Path;
1112
import java.security.CodeSource;
1213
import java.security.ProtectionDomain;
1314
import java.security.cert.Certificate;
1415
import org.junit.jupiter.api.Test;
16+
import org.junit.jupiter.api.condition.EnabledOnOs;
17+
import org.junit.jupiter.api.condition.OS;
1518

1619
class JarScannerTest {
1720
@Test
@@ -50,4 +53,28 @@ public void extractJarPathFromNestedJar() throws URISyntaxException {
5053
assertEquals(
5154
jarFileUrl.getFile(), JarScanner.extractJarPath(protectionDomain, null).toString());
5255
}
56+
57+
@Test
58+
@EnabledOnOs(OS.WINDOWS)
59+
public void extractJarPathFromFileOnWindows() throws URISyntaxException {
60+
URL mockLocation = mock(URL.class);
61+
when(mockLocation.toString()).thenReturn("file:/C:/apps/server/classes/");
62+
CodeSource codeSource = new CodeSource(mockLocation, (Certificate[]) null);
63+
ProtectionDomain protectionDomain = new ProtectionDomain(codeSource, null);
64+
Path result = JarScanner.extractJarPath(protectionDomain, SymDBReport.NO_OP);
65+
assertNotNull(result);
66+
assertTrue(result.toString().contains("server"));
67+
}
68+
69+
@Test
70+
@EnabledOnOs(OS.WINDOWS)
71+
public void extractJarPathFromJarOnWindows() throws URISyntaxException {
72+
URL mockLocation = mock(URL.class);
73+
when(mockLocation.toString()).thenReturn("jar:file:/C:/libs/app.jar!/com/example/");
74+
CodeSource codeSource = new CodeSource(mockLocation, (Certificate[]) null);
75+
ProtectionDomain protectionDomain = new ProtectionDomain(codeSource, null);
76+
Path result = JarScanner.extractJarPath(protectionDomain, SymDBReport.NO_OP);
77+
assertNotNull(result);
78+
assertTrue(result.toString().contains("app.jar"));
79+
}
5380
}

dd-java-agent/agent-profiling/build.gradle

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ excludedClassesCoverage += [
1313
'com.datadog.profiling.agent.ProfilingAgent',
1414
'com.datadog.profiling.agent.ProfilingAgent.ShutdownHook',
1515
'com.datadog.profiling.agent.ProfilingAgent.DataDumper',
16-
'com.datadog.profiling.agent.ProfilerFlare'
16+
'com.datadog.profiling.agent.ProfilerFlare',
17+
'com.datadog.profiling.agent.ScrubRecordingDataListener',
18+
'com.datadog.profiling.agent.ScrubRecordingDataListener.ScrubbedRecordingData'
1719
]
1820

1921
dependencies {
@@ -23,6 +25,7 @@ dependencies {
2325
api project(':dd-java-agent:agent-profiling:profiling-ddprof')
2426
api project(':dd-java-agent:agent-profiling:profiling-uploader')
2527
api project(':dd-java-agent:agent-profiling:profiling-controller')
28+
implementation project(':dd-java-agent:agent-profiling:profiling-scrubber')
2629
api project(':dd-java-agent:agent-profiling:profiling-controller-jfr')
2730
api project(':dd-java-agent:agent-profiling:profiling-controller-jfr:implementation')
2831
api project(':dd-java-agent:agent-profiling:profiling-controller-ddprof')
@@ -42,6 +45,11 @@ configurations {
4245

4346
tasks.named("shadowJar", ShadowJar) {
4447
dependencies deps.excludeShared
48+
49+
// Exclude multi-release versioned classes from jafar-parser.
50+
// These are duplicates of base classes for newer Java APIs and confuse
51+
// the GraalVM native-image builder when the profiling jar is embedded in the agent.
52+
exclude 'META-INF/versions/**'
4553
}
4654

4755
tasks.named("jar", Jar) {

dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerRecordingData.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.nio.file.Path;
88
import java.time.Instant;
99
import javax.annotation.Nonnull;
10+
import javax.annotation.Nullable;
1011

1112
final class DatadogProfilerRecordingData extends RecordingData {
1213
private final Path recordingFile;
@@ -36,4 +37,10 @@ public void release() {
3637
public String getName() {
3738
return "ddprof";
3839
}
40+
41+
@Nullable
42+
@Override
43+
public Path getPath() {
44+
return recordingFile;
45+
}
3946
}

0 commit comments

Comments
 (0)