Skip to content

Commit 28af69d

Browse files
authored
Merge branch 'master' into jb/ddprof_1.25.0
2 parents 05b20e4 + 74633af commit 28af69d

File tree

31 files changed

+736
-81
lines changed

31 files changed

+736
-81
lines changed

.circleci/config.continue.yml.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ instrumentation_modules: &instrumentation_modules "dd-java-agent/instrumentation
3636
debugger_modules: &debugger_modules "dd-java-agent/agent-debugger|dd-java-agent/agent-bootstrap|dd-java-agent/agent-builder|internal-api|communication|dd-trace-core"
3737
profiling_modules: &profiling_modules "dd-java-agent/agent-profiling"
3838

39-
default_system_tests_commit: &default_system_tests_commit 761b9e7a82ffb136c4653a4d1623d120d67b005b
39+
default_system_tests_commit: &default_system_tests_commit 08276e905c5c81055412ea4c318856d879cf15e5
4040

4141
parameters:
4242
nightly:

dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/TempLocationManager.java

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
import java.nio.file.Path;
1717
import java.nio.file.Paths;
1818
import java.nio.file.attribute.BasicFileAttributes;
19+
import java.nio.file.attribute.PosixFilePermission;
1920
import java.nio.file.attribute.PosixFilePermissions;
2021
import java.time.Instant;
2122
import java.time.temporal.ChronoUnit;
2223
import java.util.Set;
2324
import java.util.concurrent.CountDownLatch;
2425
import java.util.concurrent.TimeUnit;
26+
import java.util.concurrent.atomic.AtomicReference;
2527
import java.util.regex.Pattern;
2628
import java.util.stream.Stream;
2729
import org.slf4j.Logger;
@@ -219,6 +221,7 @@ boolean await(long timeout, TimeUnit unit) throws Throwable {
219221
}
220222
}
221223

224+
private final boolean isPosixFs;
222225
private final Path baseTempDir;
223226
private final Path tempDir;
224227
private final long cutoffSeconds;
@@ -262,6 +265,9 @@ private TempLocationManager() {
262265
ConfigProvider configProvider, boolean runStartupCleanup, CleanupHook testHook) {
263266
cleanupTestHook = testHook;
264267

268+
Set<String> supportedViews = FileSystems.getDefault().supportedFileAttributeViews();
269+
isPosixFs = supportedViews.contains("posix");
270+
265271
// In order to avoid racy attempts to clean up files which are currently being processed in a
266272
// JVM which is being shut down (the JVMs far in the shutdown routine may not be reported by
267273
// 'jps' but still can be eg. processing JFR chunks) we will not clean up any files not older
@@ -317,6 +323,8 @@ private TempLocationManager() {
317323
},
318324
"Temp Location Manager Cleanup");
319325
Runtime.getRuntime().addShutdownHook(selfCleanup);
326+
327+
createTempDir(tempDir);
320328
}
321329

322330
// @VisibleForTesting
@@ -362,21 +370,7 @@ public Path getTempDir(Path subPath, boolean create) {
362370
Path rslt =
363371
subPath != null && !subPath.toString().isEmpty() ? tempDir.resolve(subPath) : tempDir;
364372
if (create && !Files.exists(rslt)) {
365-
try {
366-
Set<String> supportedViews = FileSystems.getDefault().supportedFileAttributeViews();
367-
if (supportedViews.contains("posix")) {
368-
Files.createDirectories(
369-
rslt,
370-
PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------")));
371-
} else {
372-
// non-posix, eg. Windows - let's rely on the created folders being world-writable
373-
Files.createDirectories(rslt);
374-
}
375-
376-
} catch (Exception e) {
377-
log.warn(SEND_TELEMETRY, "Failed to create temp directory: {}", tempDir, e);
378-
throw new IllegalStateException("Failed to create temp directory: " + tempDir, e);
379-
}
373+
createTempDir(rslt);
380374
}
381375
return rslt;
382376
}
@@ -454,4 +448,79 @@ boolean waitForCleanup(long timeout, TimeUnit unit) {
454448
void createDirStructure() throws IOException {
455449
Files.createDirectories(baseTempDir);
456450
}
451+
452+
private void createTempDir(Path tempDir) {
453+
String msg = "Failed to create temp directory: " + tempDir;
454+
try {
455+
if (isPosixFs) {
456+
Files.createDirectories(
457+
tempDir,
458+
PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------")));
459+
} else {
460+
Files.createDirectories(tempDir);
461+
}
462+
} catch (IOException e) {
463+
log.error("Failed to create temp directory {}", tempDir, e);
464+
// if on a posix fs, let's check the expected permissions
465+
// we will find the first offender not having the expected permissions and fail the check
466+
if (isPosixFs) {
467+
// take the first subfolder below the base temp dir
468+
Path root = baseTempDir.resolve(baseTempDir.relativize(tempDir).getRoot());
469+
try {
470+
AtomicReference<Path> failed = new AtomicReference<>();
471+
Files.walkFileTree(
472+
root,
473+
new FileVisitor<Path>() {
474+
@Override
475+
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
476+
throws IOException {
477+
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(dir);
478+
if (!perms.contains(PosixFilePermission.OWNER_READ)
479+
|| !perms.contains(PosixFilePermission.OWNER_WRITE)
480+
|| !perms.contains(PosixFilePermission.OWNER_EXECUTE)) {
481+
failed.set(dir);
482+
return FileVisitResult.TERMINATE;
483+
}
484+
return FileVisitResult.CONTINUE;
485+
}
486+
487+
@Override
488+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
489+
throws IOException {
490+
return FileVisitResult.SKIP_SIBLINGS;
491+
}
492+
493+
@Override
494+
public FileVisitResult visitFileFailed(Path file, IOException exc)
495+
throws IOException {
496+
return FileVisitResult.TERMINATE;
497+
}
498+
499+
@Override
500+
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
501+
throws IOException {
502+
return FileVisitResult.CONTINUE;
503+
}
504+
});
505+
Path failedDir = failed.get();
506+
507+
if (failedDir != null) {
508+
msg +=
509+
" (offender: "
510+
+ failedDir
511+
+ ", permissions: "
512+
+ PosixFilePermissions.toString(Files.getPosixFilePermissions(failedDir))
513+
+ ")";
514+
log.warn(SEND_TELEMETRY, msg, e);
515+
}
516+
} catch (IOException ignored) {
517+
// should not happen, but let's ignore it anyway
518+
}
519+
throw new IllegalStateException(msg, e);
520+
} else {
521+
log.warn(SEND_TELEMETRY, msg, e);
522+
throw new IllegalStateException(msg, e);
523+
}
524+
}
525+
}
457526
}

dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/CompositeController.java

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.datadog.profiling.agent;
22

3+
import static datadog.trace.api.telemetry.LogCollector.SEND_TELEMETRY;
4+
35
import com.datadog.profiling.controller.Controller;
46
import com.datadog.profiling.controller.ControllerContext;
57
import com.datadog.profiling.controller.OngoingRecording;
@@ -140,26 +142,33 @@ public static Controller build(ConfigProvider provider, ControllerContext contex
140142
List<Controller> controllers = new ArrayList<>();
141143
boolean isOracleJDK8 = Platform.isOracleJDK8();
142144
boolean isDatadogProfilerEnabled = Config.get().isDatadogProfilerEnabled();
143-
if (provider.getBoolean(ProfilingConfig.PROFILING_DEBUG_JFR_DISABLED, false)) {
144-
log.warn("JFR is disabled by configuration");
145+
boolean isJfrEnabled =
146+
!provider.getBoolean(ProfilingConfig.PROFILING_DEBUG_JFR_DISABLED, false);
147+
if (!isJfrEnabled) {
148+
log.warn(SEND_TELEMETRY, "JFR is disabled by configuration");
145149
} else {
146150
if (isOracleJDK8 && !isDatadogProfilerEnabled) {
147151
try {
148152
Class.forName("com.oracle.jrockit.jfr.Producer");
149153
controllers.add(OracleJdkController.instance(provider));
150-
} catch (Throwable ignored) {
151-
log.debug("Failed to load oracle profiler", ignored);
154+
} catch (Throwable t) {
155+
log.debug(SEND_TELEMETRY, "Failed to load oracle profiler: " + t.getMessage(), t);
152156
}
153157
}
154158
if (!isOracleJDK8) {
155159
try {
156160
if (Platform.hasJfr()) {
157161
controllers.add(OpenJdkController.instance(provider));
158162
} else {
159-
log.debug("JFR is not available on this platform");
163+
log.debug(
164+
SEND_TELEMETRY,
165+
"JFR is not available on this platform: "
166+
+ OperatingSystem.current()
167+
+ ", "
168+
+ Arch.current());
160169
}
161-
} catch (Throwable ignored) {
162-
log.debug("Failed to load openjdk profiler", ignored);
170+
} catch (Throwable t) {
171+
log.debug(SEND_TELEMETRY, "Failed to load openjdk profiler: " + t.getMessage(), t);
163172
}
164173
}
165174
}
@@ -175,16 +184,20 @@ public static Controller build(ConfigProvider provider, ControllerContext contex
175184
context.setDatadogProfilerUnavailableReason(rootCause.getMessage());
176185
OperatingSystem os = OperatingSystem.current();
177186
if (os != OperatingSystem.linux) {
178-
log.debug("Datadog profiler only supported on Linux", rootCause);
179-
} else if (log.isDebugEnabled()) {
180-
log.warn(
181-
"failed to instantiate Datadog profiler on {} {}", os, Arch.current(), rootCause);
182-
} else {
187+
log.debug(SEND_TELEMETRY, "Datadog profiler only supported on Linux", rootCause);
188+
} else if (!log.isDebugEnabled()) {
183189
log.warn(
184190
"failed to instantiate Datadog profiler on {} {} because: {}",
185191
os,
186192
Arch.current(),
187193
rootCause.getMessage());
194+
} else {
195+
log.debug(
196+
SEND_TELEMETRY,
197+
"failed to instantiate Datadog profiler on {} {}",
198+
os,
199+
Arch.current(),
200+
rootCause);
188201
}
189202
}
190203
} else {
@@ -202,14 +215,18 @@ public static Controller build(ConfigProvider provider, ControllerContext contex
202215
}
203216
controllers.forEach(controller -> controller.configure(context));
204217
if (controllers.isEmpty()) {
205-
throw new UnsupportedEnvironmentException(getFixProposalMessage());
218+
throw new UnsupportedEnvironmentException(
219+
getFixProposalMessage(isDatadogProfilerEnabled, isJfrEnabled));
206220
} else if (controllers.size() == 1) {
207221
return controllers.get(0);
208222
}
209223
return new CompositeController(controllers);
210224
}
211225

212-
private static String getFixProposalMessage() {
226+
private static String getFixProposalMessage(boolean datadogProfilerEnabled, boolean jfrEnabled) {
227+
if (!datadogProfilerEnabled && !jfrEnabled) {
228+
return "Profiling is disabled by configuration. Please, make sure that your configuration is correct.";
229+
}
213230
final String javaVendor = System.getProperty("java.vendor");
214231
final String javaVersion = System.getProperty("java.version");
215232
final String javaRuntimeName = System.getProperty("java.runtime.name");

dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilingAgent.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public static synchronized void run(
109109
return;
110110
}
111111
if (!config.isProfilingEnabled()) {
112-
log.debug("Profiling: disabled");
112+
log.debug(SEND_TELEMETRY, "Profiling: disabled");
113113
return;
114114
}
115115
if (config.getApiKey() != null && !API_KEY_REGEX.test(config.getApiKey())) {
@@ -167,7 +167,8 @@ public static synchronized void run(
167167
}
168168
} catch (final UnsupportedEnvironmentException e) {
169169
log.warn(e.getMessage());
170-
log.debug(SEND_TELEMETRY, "Unsupported environment for Datadog profiler", e);
170+
// no need to send telemetry for this aggregate message
171+
// a detailed telemetry message has been sent from the attempts to enable the controllers
171172
} catch (final ConfigurationException e) {
172173
log.warn("Failed to initialize profiling agent! {}", e.getMessage());
173174
log.debug(SEND_TELEMETRY, "Failed to initialize profiling agent!", e);

dd-java-agent/agent-tooling/src/main/resources/datadog/trace/agent/tooling/bytebuddy/matcher/proxy_ignored_class_name.trie

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,11 @@
2727
1 $$_Weld*
2828
1 $$_jvst*
2929
1 $$SpringCGLIB$$*
30+
# Jackson afterburner
31+
1 $Access4JacksonDeserializer*
32+
1 $Access4JacksonSerializer*
33+
1 $Creator4JacksonDeserializer*
34+
# Hibernate
35+
1 $HibernateInstantiator$*
36+
1 $HibernateProxy$*
37+
1 $HibernateAccessOptimizer$*

dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[
7676
+ "datadog.trace.api.Platform:rerun,"
7777
+ "datadog.trace.api.Platform$Captured:build_time,"
7878
+ "datadog.trace.api.env.CapturedEnvironment:build_time,"
79+
+ "datadog.trace.api.env.CapturedEnvironment$ProcessInfo:build_time,"
7980
+ "datadog.trace.api.ConfigCollector:rerun,"
8081
+ "datadog.trace.api.ConfigDefaults:build_time,"
8182
+ "datadog.trace.api.ConfigOrigin:build_time,"

dd-java-agent/instrumentation/spring-boot/src/main/java/datadog/trace/instrumentation/springboot/SpringApplicationInstrumentation.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import datadog.trace.agent.tooling.Instrumenter;
88
import datadog.trace.agent.tooling.InstrumenterModule;
99
import datadog.trace.api.Config;
10+
import datadog.trace.api.ProcessTags;
1011
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
1112
import net.bytebuddy.asm.Advice;
1213
import org.springframework.core.env.ConfigurableEnvironment;
@@ -60,6 +61,18 @@ public static void afterEnvironmentPostProcessed(
6061
final String applicationName = environment.getProperty("spring.application.name");
6162
if (applicationName != null && !applicationName.isEmpty()) {
6263
AgentTracer.get().updatePreferredServiceName(applicationName);
64+
ProcessTags.addTag("springboot.application", applicationName);
65+
}
66+
if (Config.get().isExperimentalPropagateProcessTagsEnabled()) {
67+
final String[] profiles = environment.getActiveProfiles();
68+
if (profiles != null && profiles.length > 0) {
69+
ProcessTags.addTag("springboot.profile", profiles[0]);
70+
} else {
71+
final String[] defaultProfiles = environment.getDefaultProfiles();
72+
if (defaultProfiles != null && defaultProfiles.length > 0) {
73+
ProcessTags.addTag("springboot.profile", defaultProfiles[0]);
74+
}
75+
}
6376
}
6477
}
6578
}
@@ -77,6 +90,18 @@ public static void afterEnvironmentPostProcessed(
7790
final String applicationName = environment.getProperty("spring.application.name");
7891
if (applicationName != null && !applicationName.isEmpty()) {
7992
AgentTracer.get().updatePreferredServiceName(applicationName);
93+
ProcessTags.addTag("springboot.application", applicationName);
94+
}
95+
if (Config.get().isExperimentalPropagateProcessTagsEnabled()) {
96+
final String[] profiles = environment.getActiveProfiles();
97+
if (profiles != null && profiles.length > 0) {
98+
ProcessTags.addTag("springboot.profile", profiles[0]);
99+
} else {
100+
final String[] defaultProfiles = environment.getDefaultProfiles();
101+
if (defaultProfiles != null && defaultProfiles.length > 0) {
102+
ProcessTags.addTag("springboot.profile", defaultProfiles[0]);
103+
}
104+
}
80105
}
81106
}
82107
}

dd-java-agent/instrumentation/spring-boot/src/test/groovy/SpringBootApplicationTest.groovy

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1+
import datadog.trace.api.ProcessTags
2+
13
import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace
24

35
import datadog.trace.agent.test.AgentTestRunner
4-
import datadog.trace.api.Config
56
import org.springframework.beans.factory.InitializingBean
67
import org.springframework.boot.SpringApplication
78

9+
import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED
10+
811
class SpringBootApplicationTest extends AgentTestRunner {
912
@Override
1013
protected void configurePreAgent() {
1114
super.configurePreAgent()
15+
injectSysConfig(EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "true")
1216
}
17+
1318
static class BeanWhoTraces implements InitializingBean {
1419

1520
@Override
@@ -32,15 +37,19 @@ class SpringBootApplicationTest extends AgentTestRunner {
3237
}
3338
}
3439
})
40+
and:
41+
def processTags = ProcessTags.getTagsForSerialization()
42+
assert processTags.toString() =~ ".+,springboot.application:$expectedService,springboot.profile:$expectedProfile"
3543
context != null
3644
cleanup:
3745
context?.stop()
3846
where:
39-
expectedService | args
40-
"application-name-from-args" | new String[]{
41-
"--spring.application.name=application-name-from-args"
47+
expectedService | expectedProfile | args
48+
"application-name-from-args" | "prod" | new String[]{
49+
"--spring.application.name=application-name-from-args",
50+
"--spring.profiles.active=prod,common",
4251
}
43-
"application-name-from-properties" | new String[0] // will load from properties
52+
"application-name-from-properties" | "default" | new String[0] // will load from properties
4453
}
4554
}
4655

dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import datadog.trace.agent.tooling.bytebuddy.matcher.GlobalIgnores
2727
import datadog.trace.api.Config
2828
import datadog.trace.api.DDSpanId
2929
import datadog.trace.api.IdGenerationStrategy
30+
import datadog.trace.api.ProcessTags
3031
import datadog.trace.api.StatsDClient
3132
import datadog.trace.api.TraceConfig
3233
import datadog.trace.api.WellKnownTags
@@ -509,6 +510,7 @@ abstract class AgentTestRunner extends DDSpecification implements AgentBuilder.L
509510
ActiveSubsystems.APPSEC_ACTIVE = true
510511
}
511512
InstrumentationErrors.resetErrorCount()
513+
ProcessTags.reset()
512514
}
513515

514516
@Override

0 commit comments

Comments
 (0)