Skip to content

Automatically register crashtracking via native extensions #8851

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 26 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cfeb32e
Set up crash-tracking JVM flags automatically (for Hotspot)
jbachorik Apr 25, 2025
685acda
Reorganize imports and exports within Gradle to avoid shadowing in th…
MattAlp Apr 30, 2025
d0656dc
Address startup delay regression
MattAlp May 21, 2025
285dc50
Update gradle/libs.versions.toml
MattAlp May 20, 2025
c6a81a6
Update dd-java-agent/agent-profiling/profiling-ddprof/build.gradle
MattAlp May 20, 2025
c54ac77
Update dd-java-agent/agent-crashtracking/build.gradle
MattAlp May 20, 2025
bd01490
Use TLM for crashtracking temp files
MattAlp May 21, 2025
27ea385
Use TLM for crashtracking temp files
MattAlp May 21, 2025
89fceb4
Limit dependency scope
MattAlp May 22, 2025
a8f1f37
Update dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/boot…
MattAlp May 22, 2025
4b6ee54
Fix spotless post-merge
MattAlp May 22, 2025
2fb51dd
Add experimental mutex between native library load callsites
MattAlp May 22, 2025
0815229
Temporary - increase binary size limit to 34mb
MattAlp May 22, 2025
4c2eb83
We need the profiler throwable message to show in CI
MattAlp May 23, 2025
82757f9
Mystery null profiling startup CI log
MattAlp May 23, 2025
039b5fb
Appears to be an invocation issue in CI
MattAlp May 23, 2025
7fb9306
Appears to be an invocation issue in CI
MattAlp May 23, 2025
eae4de8
Appears to be an invocation issue in CI
MattAlp May 23, 2025
f3fc9d7
Crashtracking no longer depends on profiling modules for TLM
MattAlp May 23, 2025
b0fa667
Final touches following thorough compatibility checks
MattAlp May 24, 2025
ea9d36f
Rework the crashtracking
jbachorik May 27, 2025
dc9034f
Spotless
jbachorik May 27, 2025
2b4f917
Fix ddprof dep
jbachorik May 27, 2025
58ae723
Add more telemetry
jbachorik May 28, 2025
2e374d4
Adjust jacoco verification
jbachorik May 28, 2025
dc725c3
Remove usage of forbidden APIs
jbachorik May 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dd-java-agent/agent-bootstrap/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dependencies {
api project(':dd-java-agent:agent-logging')
api project(':dd-java-agent:agent-debugger:debugger-bootstrap')
api project(':components:json')

api libs.slf4j
// ^ Generally a bad idea for libraries, but we're shadowing.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import datadog.trace.api.appsec.AppSecEventTracker;
import datadog.trace.api.config.AppSecConfig;
import datadog.trace.api.config.CiVisibilityConfig;
import datadog.trace.api.config.CrashTrackingConfig;
import datadog.trace.api.config.CwsConfig;
import datadog.trace.api.config.DebuggerConfig;
import datadog.trace.api.config.GeneralConfig;
Expand Down Expand Up @@ -54,6 +55,7 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -95,6 +97,9 @@ private enum AgentFeature {
TRACING(TraceInstrumentationConfig.TRACE_ENABLED, true),
JMXFETCH(JmxFetchConfig.JMX_FETCH_ENABLED, true),
STARTUP_LOGS(GeneralConfig.STARTUP_LOGS_ENABLED, DEFAULT_STARTUP_LOGS_ENABLED),
CRASH_TRACKING(
CrashTrackingConfig.CRASH_TRACKING_ENABLED,
CrashTrackingConfig.CRASH_TRACKING_ENABLED_DEFAULT),
PROFILING(ProfilingConfig.PROFILING_ENABLED, false),
APPSEC(AppSecConfig.APPSEC_ENABLED, false),
IAST(IastConfig.IAST_ENABLED, false),
Expand Down Expand Up @@ -146,9 +151,11 @@ public boolean isEnabledByDefault() {
private static ClassLoader AGENT_CLASSLOADER = null;

private static volatile Runnable PROFILER_INIT_AFTER_JMX = null;
private static volatile Runnable CRASHTRACKER_INIT_AFTER_JMX = null;

private static boolean jmxFetchEnabled = true;
private static boolean profilingEnabled = false;
private static boolean crashTrackingEnabled = false;
private static boolean appSecEnabled;
private static boolean appSecFullyDisabled;
private static boolean remoteConfigEnabled = true;
Expand Down Expand Up @@ -276,6 +283,7 @@ public static void start(

jmxFetchEnabled = isFeatureEnabled(AgentFeature.JMXFETCH);
profilingEnabled = isFeatureEnabled(AgentFeature.PROFILING);
crashTrackingEnabled = isFeatureEnabled(AgentFeature.CRASH_TRACKING);
usmEnabled = isFeatureEnabled(AgentFeature.USM);
appSecEnabled = isFeatureEnabled(AgentFeature.APPSEC);
appSecFullyDisabled = isFullyDisabled(AgentFeature.APPSEC);
Expand All @@ -293,6 +301,18 @@ public static void start(

patchJPSAccess(inst);

// We need to run the crashtracking initialization after all the config has been resolved
if (crashTrackingEnabled) {
if (Platform.isJavaVersionAtLeast(9)) {
// it is safe to initialize crashtracking 'in-line'
initializeCrashTracking();
} else {
// for Java 8 we are relying on JMX to give us the process PID
// we need to delay the crash tracking initialization until JMX is available
CRASHTRACKER_INIT_AFTER_JMX = Agent::initializeCrashTracking;
}
}

if (profilingEnabled) {
if (!isOracleJDK8()) {
// Profiling agent startup code is written in a way to allow `startProfilingAgent` be called
Expand All @@ -305,13 +325,7 @@ public static void start(
// Profiling can not run early on Oracle JDK 8 because it will cause JFR initialization
// deadlock.
// Oracle JDK 8 JFR controller requires JMX so register an 'after-jmx-initialized' callback.
PROFILER_INIT_AFTER_JMX =
new Runnable() {
@Override
public void run() {
startProfilingAgent(false, inst);
}
};
PROFILER_INIT_AFTER_JMX = () -> startProfilingAgent(false, inst);
}
}

Expand Down Expand Up @@ -757,25 +771,33 @@ private static synchronized void startJmx() {
if (jmxStarting.getAndSet(true)) {
return; // another thread is already in startJmx
}
// error tracking initialization relies on JMX being available
initializeErrorTracking();
if (jmxFetchEnabled) {
startJmxFetch();
}
initializeJmxSystemAccessProvider(AGENT_CLASSLOADER);
if (crashTrackingEnabled && CRASHTRACKER_INIT_AFTER_JMX != null) {
try {
CRASHTRACKER_INIT_AFTER_JMX.run();
} finally {
CRASHTRACKER_INIT_AFTER_JMX = null;
}
}
if (profilingEnabled) {
registerDeadlockDetectionEvent();
registerSmapEntryEvent();
if (PROFILER_INIT_AFTER_JMX != null) {
if (getJmxStartDelay() == 0) {
log.debug("Waiting for profiler initialization");
AgentTaskScheduler.INSTANCE.scheduleWithJitter(
PROFILER_INIT_AFTER_JMX, 500, TimeUnit.MILLISECONDS);
} else {
log.debug("Initializing profiler");
PROFILER_INIT_AFTER_JMX.run();
try {
if (getJmxStartDelay() == 0) {
log.debug("Waiting for profiler initialization");
AgentTaskScheduler.INSTANCE.scheduleWithJitter(
PROFILER_INIT_AFTER_JMX, 500, TimeUnit.MILLISECONDS);
} else {
log.debug("Initializing profiler");
PROFILER_INIT_AFTER_JMX.run();
}
} finally {
PROFILER_INIT_AFTER_JMX = null;
}
PROFILER_INIT_AFTER_JMX = null;
}
}
}
Expand Down Expand Up @@ -1017,16 +1039,38 @@ private static void stopTelemetry() {
}
}

private static void initializeErrorTracking() {
private static void initializeCrashTracking() {
initializeCrashTracking(true);
}

private static void initializeCrashTracking(boolean delayed) {
if (Platform.isJ9()) {
// TODO currently crash tracking is supported only for HotSpot based JVMs
return;
}
log.debug("Initializing crashtracking");
try {
Class<?> clz = AGENT_CLASSLOADER.loadClass("com.datadog.crashtracking.ScriptInitializer");
clz.getMethod("initialize").invoke(null);
Class<?> clz = AGENT_CLASSLOADER.loadClass("datadog.crashtracking.Initializer");
// first try to use the JVMAccess using the native library
boolean rslt = (boolean) clz.getMethod("initialize", boolean.class).invoke(null, false);
if (!rslt) {
if (delayed) {
// already delayed initialization, so no need to reschedule it again
// just call initialize and force JMX
rslt = (boolean) clz.getMethod("initialize", boolean.class).invoke(null, true);
} else {
// delayed initialization, so we need to reschedule it and mark as delayed
CRASHTRACKER_INIT_AFTER_JMX = Agent::initializeCrashTracking;
}
}
if (rslt) {
log.debug("Crashtracking initialized");
} else {
log.debug(
SEND_TELEMETRY, "Crashtracking failed to initialize. No additional details available.");
}
} catch (Throwable t) {
log.debug("Unable to initialize crash uploader", t);
log.debug(SEND_TELEMETRY, "Unable to initialize crashtracking", t);
}
}

Expand Down Expand Up @@ -1125,8 +1169,11 @@ public void withTracer(TracerAPI tracer) {
}
});
}
} catch (final Throwable ex) {
log.error("Throwable thrown while starting profiling agent", ex);
} catch (final Throwable t) {
log.error(
SEND_TELEMETRY,
"Throwable thrown while starting profiling agent "
+ Arrays.toString(t.getCause().getStackTrace()));
} finally {
Thread.currentThread().setContextClassLoader(contextLoader);
}
Expand Down
1 change: 1 addition & 0 deletions dd-java-agent/agent-crashtracking/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies {
implementation project(':internal-api')
implementation project(':utils:container-utils')
implementation project(':utils:version-utils')
implementation project(path: ':dd-java-agent:ddprof-lib', configuration: 'shadow')

implementation libs.okhttp
implementation libs.moshi
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.datadog.crashtracking;
package datadog.crashtracking;

import com.datadog.crashtracking.dto.CrashLog;
import com.datadog.crashtracking.parsers.HotspotCrashLogParser;
import datadog.crashtracking.dto.CrashLog;
import datadog.crashtracking.parsers.HotspotCrashLogParser;

public final class CrashLogParser {
public static CrashLog fromHotspotCrashLog(String logText) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.datadog.crashtracking;
package datadog.crashtracking;

import static datadog.trace.api.config.CrashTrackingConfig.CRASH_TRACKING_PROXY_HOST;
import static datadog.trace.api.config.CrashTrackingConfig.CRASH_TRACKING_PROXY_PASSWORD;
Expand All @@ -7,11 +7,11 @@
import static datadog.trace.api.config.CrashTrackingConfig.CRASH_TRACKING_UPLOAD_TIMEOUT;
import static datadog.trace.api.config.CrashTrackingConfig.CRASH_TRACKING_UPLOAD_TIMEOUT_DEFAULT;

import com.datadog.crashtracking.dto.CrashLog;
import com.squareup.moshi.JsonWriter;
import datadog.common.container.ContainerInfo;
import datadog.common.version.VersionInfo;
import datadog.communication.http.OkHttpUtils;
import datadog.crashtracking.dto.CrashLog;
import datadog.trace.api.Config;
import datadog.trace.api.DDTags;
import datadog.trace.bootstrap.config.provider.ConfigProvider;
Expand Down
Loading
Loading