Skip to content

Commit c2e0084

Browse files
Merge branch 'landerson/dd-dogstatsd-port' into landerson/fix-crashtrackingsmoke
2 parents 3df5bbf + e4b8c9e commit c2e0084

File tree

16 files changed

+255
-4
lines changed

16 files changed

+255
-4
lines changed

communication/src/main/java/datadog/communication/monitor/DDAgentStatsDClientManager.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package datadog.communication.monitor;
22

3-
import static datadog.trace.api.ConfigDefaults.DEFAULT_DOGSTATSD_PORT;
43
import static datadog.trace.bootstrap.instrumentation.api.WriterConstants.LOGGING_WRITER_TYPE;
54

65
import datadog.trace.api.Config;
@@ -22,7 +21,7 @@ public static StatsDClientManager statsDClientManager() {
2221
return INSTANCE;
2322
}
2423

25-
private static final AtomicInteger defaultStatsDPort = new AtomicInteger(DEFAULT_DOGSTATSD_PORT);
24+
private static final AtomicInteger defaultStatsDPort = new AtomicInteger(Config.get().getDogsStatsDPort());
2625

2726
public static void setDefaultStatsDPort(final int newPort) {
2827
if (newPort > 0 && defaultStatsDPort.getAndSet(newPort) != newPort) {

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static datadog.trace.api.ConfigDefaults.DEFAULT_STARTUP_LOGS_ENABLED;
44
import static datadog.trace.api.Platform.isJavaVersionAtLeast;
55
import static datadog.trace.api.Platform.isOracleJDK8;
6+
import static datadog.trace.api.telemetry.LogCollector.SEND_TELEMETRY;
67
import static datadog.trace.bootstrap.Library.WILDFLY;
78
import static datadog.trace.bootstrap.Library.detectLibraries;
89
import static datadog.trace.util.AgentThreadFactory.AgentThread.JMX_STARTUP;
@@ -44,6 +45,7 @@
4445
import datadog.trace.util.AgentTaskScheduler;
4546
import datadog.trace.util.AgentThreadFactory.AgentThread;
4647
import datadog.trace.util.throwable.FatalAgentMisconfigurationError;
48+
import de.thetaphi.forbiddenapis.SuppressForbidden;
4749
import java.lang.instrument.Instrumentation;
4850
import java.lang.reflect.InvocationTargetException;
4951
import java.lang.reflect.Method;
@@ -291,6 +293,8 @@ public static void start(
291293
codeOriginEnabled = isFeatureEnabled(AgentFeature.CODE_ORIGIN);
292294
agentlessLogSubmissionEnabled = isFeatureEnabled(AgentFeature.AGENTLESS_LOG_SUBMISSION);
293295

296+
patchJPSAccess(inst);
297+
294298
if (profilingEnabled) {
295299
if (!isOracleJDK8()) {
296300
// Profiling agent startup code is written in a way to allow `startProfilingAgent` be called
@@ -420,6 +424,23 @@ private static void injectAgentArgsConfig(String agentArgs) {
420424
}
421425
}
422426

427+
@SuppressForbidden
428+
public static void patchJPSAccess(Instrumentation inst) {
429+
if (Platform.isJavaVersionAtLeast(9)) {
430+
// Unclear if supported for J9, may need to revisit
431+
try {
432+
Class.forName("datadog.trace.util.JPMSJPSAccess")
433+
.getMethod("patchModuleAccess", Instrumentation.class)
434+
.invoke(null, inst);
435+
} catch (Exception e) {
436+
log.debug(
437+
SEND_TELEMETRY,
438+
"Failed to patch module access for jvmstat and Java version "
439+
+ Platform.getRuntimeVersion());
440+
}
441+
}
442+
}
443+
423444
public static void shutdown(final boolean sync) {
424445
StaticEventLogger.end("Agent");
425446
StaticEventLogger.stop();

dd-java-agent/agent-bootstrap/src/main/java11/datadog/trace/bootstrap/instrumentation/jfr/exceptions/ExceptionProfiling.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package datadog.trace.bootstrap.instrumentation.jfr.exceptions;
22

33
import datadog.trace.api.Config;
4+
import datadog.trace.bootstrap.CallDepthThreadLocalMap;
45

56
/**
67
* JVM-wide singleton exception profiling service. Uses {@linkplain Config} class to configure
@@ -13,6 +14,24 @@ private static final class Holder {
1314
static final ExceptionProfiling INSTANCE = new ExceptionProfiling(Config.get());
1415
}
1516

17+
/**
18+
* Support for excluding certain exception types because they are used for control flow or leak
19+
* detection.
20+
*/
21+
public static final class Exclusion {
22+
public static void enter() {
23+
CallDepthThreadLocalMap.incrementCallDepth(Exclusion.class);
24+
}
25+
26+
public static void exit() {
27+
CallDepthThreadLocalMap.decrementCallDepth(Exclusion.class);
28+
}
29+
30+
public static boolean isEffective() {
31+
return CallDepthThreadLocalMap.getCallDepth(Exclusion.class) > 0;
32+
}
33+
}
34+
1635
/**
1736
* Get a pre-configured shared instance.
1837
*

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ apply from: "$rootDir/gradle/java.gradle"
1111
apply plugin: "idea"
1212

1313
dependencies {
14+
testImplementation 'de.thetaphi:forbiddenapis:3.8'
1415
testImplementation libs.bundles.junit5
1516
testImplementation libs.bundles.jmc
1617
testImplementation libs.commons.math
@@ -29,6 +30,11 @@ forbiddenApisMain_java11 {
2930
failOnMissingClasses = false
3031
}
3132

33+
test {
34+
useJUnit()
35+
useJUnitPlatform()
36+
}
37+
3238
idea {
3339
module {
3440
jdkName = '11'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package datadog.exceptions.instrumentation;
2+
3+
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
4+
5+
import com.google.auto.service.AutoService;
6+
import datadog.trace.agent.tooling.Instrumenter;
7+
import datadog.trace.agent.tooling.InstrumenterModule;
8+
import datadog.trace.api.Platform;
9+
10+
/**
11+
* Provides instrumentation to exclude exception types known to be used for control flow or
12+
* 'connection leak' detection.
13+
*/
14+
@AutoService(InstrumenterModule.class)
15+
public final class KnownExcludesInstrumentation extends InstrumenterModule.Profiling
16+
implements Instrumenter.ForBootstrap, Instrumenter.ForKnownTypes, Instrumenter.HasMethodAdvice {
17+
18+
public KnownExcludesInstrumentation() {
19+
// this instrumentation is controlled together with 'throwables' instrumentation
20+
super("throwables");
21+
}
22+
23+
@Override
24+
public boolean isEnabled() {
25+
return Platform.hasJfr() && super.isEnabled();
26+
}
27+
28+
@Override
29+
public void methodAdvice(MethodTransformer transformer) {
30+
transformer.applyAdvice(isConstructor(), packageName + ".ExclusionAdvice");
31+
}
32+
33+
@Override
34+
public String[] knownMatchingTypes() {
35+
return new String[] {"com.zaxxer.hikari.pool.ProxyLeakTask"};
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package datadog.exceptions.instrumentation;
2+
3+
import datadog.trace.bootstrap.instrumentation.jfr.exceptions.ExceptionProfiling;
4+
import net.bytebuddy.asm.Advice;
5+
6+
public class ExclusionAdvice {
7+
@Advice.OnMethodEnter(suppress = Throwable.class)
8+
public static void onEnter() {
9+
ExceptionProfiling.Exclusion.enter();
10+
}
11+
12+
@Advice.OnMethodExit(suppress = Throwable.class)
13+
public static void onExit(@Advice.This final Object t) {
14+
ExceptionProfiling.Exclusion.exit();
15+
}
16+
}

dd-java-agent/instrumentation/exception-profiling/src/main/java11/datadog/exceptions/instrumentation/ThrowableInstanceAdvice.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
public class ThrowableInstanceAdvice {
1313
@Advice.OnMethodExit(suppress = Throwable.class)
1414
public static void onExit(@Advice.This final Object t) {
15+
if (ExceptionProfiling.Exclusion.isEffective()) {
16+
return;
17+
}
1518
/*
1619
* This instrumentation handler is sensitive to any throwables thrown from its body -
1720
* it will go into infinite loop of trying to handle the new throwable instance and generating
@@ -40,7 +43,7 @@ public static void onExit(@Advice.This final Object t) {
4043
}
4144
/*
4245
* JFR will assign the stacktrace depending on the place where the event is committed.
43-
* Therefore we need to commit the event here, right in the 'Exception' constructor
46+
* Therefore, we need to commit the event here, right in the 'Exception' constructor
4447
*/
4548
final ExceptionSampleEvent event = ExceptionProfiling.getInstance().process((Throwable) t);
4649
if (event != null && event.shouldCommit()) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import com.zaxxer.hikari.pool.ProxyLeakTask
2+
import datadog.trace.agent.test.AgentTestRunner
3+
import datadog.trace.bootstrap.instrumentation.jfr.InstrumentationBasedProfiling
4+
import jdk.jfr.Recording
5+
import org.openjdk.jmc.common.item.Attribute
6+
import org.openjdk.jmc.common.item.IAttribute
7+
import org.openjdk.jmc.common.item.ItemFilters
8+
import org.openjdk.jmc.common.unit.UnitLookup
9+
import org.openjdk.jmc.flightrecorder.JfrLoaderToolkit
10+
import spock.lang.Shared
11+
12+
import java.nio.file.Files
13+
14+
class KnownExcludesForkedTest extends AgentTestRunner {
15+
private static final IAttribute<String> TYPE =
16+
Attribute.attr("type", "type", "Exception type", UnitLookup.PLAIN_TEXT)
17+
18+
@Shared
19+
Recording recording
20+
21+
@Override
22+
protected void configurePreAgent() {
23+
super.configurePreAgent()
24+
injectSysConfig("profiling.enabled", "true")
25+
injectSysConfig("profiling.start-force-first", "true")
26+
}
27+
28+
def setupSpec() {
29+
recording = new Recording()
30+
recording.enable("datadog.ExceptionCount")
31+
recording.start()
32+
InstrumentationBasedProfiling.enableInstrumentationBasedProfiling()
33+
}
34+
35+
def "obey excluded"() {
36+
when:
37+
println("Generating exceptions ...")
38+
for (int i = 0; i < 50; i++) {
39+
new ProxyLeakTask()
40+
new NullPointerException()
41+
}
42+
println("Exceptions generated")
43+
44+
def tempPath = Files.createTempDirectory("test-recording")
45+
def recFile = tempPath.resolve(KnownExcludesForkedTest.name.replace('.', '_') + ".jfr")
46+
recFile.toFile().deleteOnExit()
47+
recording.dump(recFile)
48+
recording.stop()
49+
50+
def events = JfrLoaderToolkit.loadEvents(recFile.toFile()).apply(ItemFilters.type("datadog.ExceptionCount"))
51+
52+
then:
53+
events.apply(ItemFilters.equals(TYPE, NullPointerException.canonicalName)).hasItems()
54+
!events.apply(ItemFilters.equals(TYPE, ProxyLeakTask.canonicalName)).hasItems()
55+
}
56+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.zaxxer.hikari.pool;
2+
3+
public class ProxyLeakTask extends Exception {
4+
private static final long serialVersionUID = 1L;
5+
6+
public ProxyLeakTask() {
7+
super("Proxy leak detected");
8+
}
9+
10+
public ProxyLeakTask(String message) {
11+
super(message);
12+
}
13+
14+
public ProxyLeakTask(String message, Throwable cause) {
15+
super(message, cause);
16+
}
17+
18+
public ProxyLeakTask(Throwable cause) {
19+
super(cause);
20+
}
21+
}

internal-api/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ excludedClassesCoverage += [
175175
"datadog.trace.util.ComparableVersion.LongItem",
176176
"datadog.trace.util.ComparableVersion.StringItem",
177177
"datadog.trace.util.ConcurrentEnumMap",
178+
"datadog.trace.util.JPSUtils",
178179
"datadog.trace.util.MethodHandles",
179180
"datadog.trace.util.PidHelper",
180181
"datadog.trace.util.PidHelper.Fallback",

0 commit comments

Comments
 (0)