From 42a4122e397df86a4d333ef416412365730300fc Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Thu, 6 Feb 2025 13:01:30 +0100 Subject: [PATCH 1/2] Use Java home of the crashed process to launch crash uploader --- .../crashtracking/ScriptInitializer.java | 3 ++ .../com/datadog/crashtracking/notify_oome.bat | 3 +- .../com/datadog/crashtracking/notify_oome.sh | 5 ++- .../datadog/crashtracking/upload_crash.bat | 44 ++++++++++++++++++- .../com/datadog/crashtracking/upload_crash.sh | 23 +++++++++- .../crashtracking/ScriptInitializerTest.java | 4 ++ 6 files changed, 76 insertions(+), 6 deletions(-) diff --git a/dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/ScriptInitializer.java b/dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/ScriptInitializer.java index 7d845efea83..e07be4b7e3f 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/ScriptInitializer.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/ScriptInitializer.java @@ -90,6 +90,9 @@ static void writeConfig(Path scriptPath, String... entries) { bw.write(entries[i + 1]); bw.newLine(); } + bw.write("java_home=" + System.getProperty("java.home")); + bw.newLine(); + Runtime.getRuntime() .addShutdownHook( new Thread( diff --git a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.bat b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.bat index 00658a95e6f..af35afde11a 100644 --- a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.bat +++ b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.bat @@ -31,10 +31,11 @@ for /f "tokens=1,2 delims=: " %%a in (%configFile%.cfg) do ( :: Debug: Print the loaded values (Optional) echo Agent Jar: %agent% echo Tags: %tags% +echo JAVA_HOME: %java_home% echo PID: %PID% :: Execute the Java command with the loaded values -java -Ddd.dogstatsd.start-delay=0 -jar "%agent%" sendOomeEvent "%tags%" +%java_home%\bin\java -Ddd.dogstatsd.start-delay=0 -jar "%agent%" sendOomeEvent "%tags%" set RC=%ERRORLEVEL% del "%configFile%" :: Clean up the configuration file if %RC% EQU 0 ( diff --git a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.sh b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.sh index 85ee5ef08ca..fc9a252513f 100644 --- a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.sh +++ b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.sh @@ -27,7 +27,7 @@ while IFS="=" read -r key value; do done < "$configFile" # Exiting early if configuration is missing -if [ -z "${config_agent}" ] || [ -z "${config_tags}" ]; then +if [ -z "${config_agent}" ] || [ -z "${config_tags}" ] || [ -z "${config_java_home}" ]; then echo "Error: Missing configuration" exit 1 fi @@ -35,10 +35,11 @@ fi # Debug: Print the loaded values (Optional) echo "Agent Jar: ${config_agent}" echo "Tags: ${config_tags}" +echo "JAVA_HOME: ${config_java_home}" echo "PID: $PID" # Execute the Java command with the loaded values -java -Ddd.dogstatsd.start-delay=0 -jar "${config_agent}" sendOomeEvent "${config_tags}" +${config_java_home}/bin/java -Ddd.dogstatsd.start-delay=0 -jar "${config_agent}" sendOomeEvent "${config_tags}" RC=$? rm -f "${configFile}" # Remove the configuration file diff --git a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.bat b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.bat index 588430e683b..aec5e5bf9ed 100644 --- a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.bat +++ b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.bat @@ -1,9 +1,50 @@ @echo off setlocal enabledelayedexpansion +REM ======================================================== +REM Function: ensureJava +REM Usage: call :ensureJava path\to\hs_err_file.txt +REM If 'java' is not found in PATH, extract JAVA_HOME from the +REM hs_err file and update PATH accordingly. +REM ======================================================== +:ensureJava + REM Check if java is available + where java >nul 2>&1 + if %ERRORLEVEL%==0 ( + REM Java found; nothing to do. + goto :EOF + ) + + REM Java not found; try to extract JAVA_HOME from the hs_err file passed as parameter. + if "%~1"=="" ( + echo Error: No hs_err file provided. + exit /b 1 + ) + + REM Use findstr to locate the line with JAVA_HOME. + for /f "tokens=2 delims==" %%A in ('findstr "JAVA_HOME" "%~1"') do ( + set "JAVA_HOME=%%A" + ) + + REM Check if JAVA_HOME was found + if not defined JAVA_HOME ( + echo Error: Java executable not found. Cannot upload error file. + exit /b 1 + ) + + REM Optionally, remove any surrounding quotes or spaces: + set "JAVA_HOME=%JAVA_HOME:"=%" + for /f "tokens=* delims= " %%A in ("%JAVA_HOME%") do set "JAVA_HOME=%%A" + + REM Prepend JAVA_HOME\bin to PATH + set "PATH=%JAVA_HOME%\bin;%PATH%" + goto :EOF + + :: Check if PID is provided if "%1"=="" ( echo "Error: No PID provided. Running in legacy mode." + call :ensureJava "!JAVA_ERROR_FILE!" java -jar "!AGENT_JAR!" uploadCrash "!JAVA_ERROR_FILE!" if %ERRORLEVEL% EQU 0 ( echo "Uploaded error file \"!JAVA_ERROR_FILE!\"" @@ -38,10 +79,11 @@ for /f "tokens=1,2 delims=: " %%a in (%configFile%.cfg) do ( :: Debug: Print the loaded values (Optional) echo Agent Jar: %agent% echo Error Log: %hs_err% +echo JAVA_HOME: %java_home% echo PID: %PID% :: Execute the Java command with the loaded values -java -jar "%agent%" uploadCrash "%hs_err%" +%java_home%\bin\java -jar "%agent%" uploadCrash "%hs_err%" set RC=%ERRORLEVEL% del "%configFile%" :: Clean up the configuration file if %RC% EQU 0 ( diff --git a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.sh b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.sh index 7b417dcc1be..938fe5d1a44 100644 --- a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.sh +++ b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.sh @@ -2,9 +2,27 @@ set +e # Disable exit on error +function ensureJava() { + # Check if Java is available + if [ -z "$(which java)" ]; then + # Extract the JAVA_HOME from the provided hs_err file + JAVA_HOME=$(grep "JAVA_HOME" "$1") + if [ -n "$JAVA_HOME" ]; then + JAVA_HOME=$(cut -f2 -d '=' <<< "$JAVA_HOME") + export JAVA_HOME + export PATH=$JAVA_HOME/bin:$PATH + else + echo "Error: Java executable not found. Can not upload error file." + exit 1 + fi + fi +} + # Check if PID is provided if [ -z "$1" ]; then echo "Warn: No PID provided. Running in legacy mode." + ensureJava "!JAVA_ERROR_FILE!" + java -jar "!AGENT_JAR!" uploadCrash "!JAVA_ERROR_FILE!" if [ $? -eq 0 ]; then echo "Error file !JAVA_ERROR_FILE! was uploaded successfully" @@ -35,7 +53,7 @@ while IFS="=" read -r key value; do done < "$configFile" # Exiting early if configuration is missing -if [ -z "${config_agent}" ] || [ -z "${config_hs_err}" ]; then +if [ -z "${config_agent}" ] || [ -z "${config_hs_err}" ] || [ -z "${config_java_home}" ]; then echo "Error: Missing configuration" exit 1 fi @@ -43,10 +61,11 @@ fi # Debug: Print the loaded values (Optional) echo "Agent Jar: ${config_agent}" echo "Error Log: ${config_hs_err}" +echo "JAVA_HOME: ${config_java_home}" echo "PID: $PID" # Execute the Java command with the loaded values -java -jar "${config_agent}" uploadCrash "${config_hs_err}" +${config_java_home}/bin/java -jar "${config_agent}" uploadCrash "${config_hs_err}" RC=$? rm -f "${configFile}" # Remove the configuration file diff --git a/dd-java-agent/agent-crashtracking/src/test/java/com/datadog/crashtracking/ScriptInitializerTest.java b/dd-java-agent/agent-crashtracking/src/test/java/com/datadog/crashtracking/ScriptInitializerTest.java index d33b5ff2539..98a1c6974f4 100644 --- a/dd-java-agent/agent-crashtracking/src/test/java/com/datadog/crashtracking/ScriptInitializerTest.java +++ b/dd-java-agent/agent-crashtracking/src/test/java/com/datadog/crashtracking/ScriptInitializerTest.java @@ -65,6 +65,8 @@ void testCrashUploaderInitializationSuccess(String target, String pidArg) assertFalse(lines.isEmpty(), "File " + file + " is expected to be non-empty"); // sanity to check the crash log file was properly replaced in the script assertTrue(lines.stream().anyMatch(l -> l.contains(hsErrFile))); + // sanity to check the java home was properly captured + assertTrue(lines.stream().anyMatch(l -> l.contains("java_home"))); } @Test @@ -96,6 +98,8 @@ void testOomeNotifierInitializationSuccess(String target) throws IOException { assertFalse(lines.isEmpty(), "File " + file + " is expected to be non-empty"); // sanity to check the placeholder was properly replaced assertTrue(lines.stream().anyMatch(l -> !l.contains("!TAGS!"))); + // sanity to check the java home was properly captured + assertTrue(lines.stream().anyMatch(l -> l.contains("java_home"))); } @Test From 23bb3df9d857facdd4eed57f16bda203d2290dab Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Fri, 7 Feb 2025 10:40:33 +0100 Subject: [PATCH 2/2] Simplify JAVA_HOME handling --- .../CrashUploaderScriptInitializer.java | 1 + .../com/datadog/crashtracking/notify_oome.bat | 2 +- .../com/datadog/crashtracking/notify_oome.sh | 2 +- .../datadog/crashtracking/upload_crash.bat | 44 +------------------ .../com/datadog/crashtracking/upload_crash.sh | 21 +-------- .../crashtracking/ScriptInitializerTest.java | 4 ++ 6 files changed, 11 insertions(+), 63 deletions(-) diff --git a/dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/CrashUploaderScriptInitializer.java b/dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/CrashUploaderScriptInitializer.java index baf99051509..6579c151f74 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/CrashUploaderScriptInitializer.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/CrashUploaderScriptInitializer.java @@ -109,6 +109,7 @@ private static void writeCrashUploaderScript( private static String template(String line, String execClass, String crashFile) { line = Strings.replace(line, "!AGENT_JAR!", execClass); + line = Strings.replace(line, "!JAVA_HOME!", System.getProperty("java.home")); if (crashFile != null) { line = Strings.replace(line, "!JAVA_ERROR_FILE!", crashFile); } diff --git a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.bat b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.bat index af35afde11a..b0d8b5bdbb4 100644 --- a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.bat +++ b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.bat @@ -35,7 +35,7 @@ echo JAVA_HOME: %java_home% echo PID: %PID% :: Execute the Java command with the loaded values -%java_home%\bin\java -Ddd.dogstatsd.start-delay=0 -jar "%agent%" sendOomeEvent "%tags%" +"%java_home%\bin\java" -Ddd.dogstatsd.start-delay=0 -jar "%agent%" sendOomeEvent "%tags%" set RC=%ERRORLEVEL% del "%configFile%" :: Clean up the configuration file if %RC% EQU 0 ( diff --git a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.sh b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.sh index fc9a252513f..c2ee9ecf6df 100644 --- a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.sh +++ b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/notify_oome.sh @@ -39,7 +39,7 @@ echo "JAVA_HOME: ${config_java_home}" echo "PID: $PID" # Execute the Java command with the loaded values -${config_java_home}/bin/java -Ddd.dogstatsd.start-delay=0 -jar "${config_agent}" sendOomeEvent "${config_tags}" +"${config_java_home}/bin/java" -Ddd.dogstatsd.start-delay=0 -jar "${config_agent}" sendOomeEvent "${config_tags}" RC=$? rm -f "${configFile}" # Remove the configuration file diff --git a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.bat b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.bat index aec5e5bf9ed..340817c6461 100644 --- a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.bat +++ b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.bat @@ -1,51 +1,11 @@ @echo off setlocal enabledelayedexpansion -REM ======================================================== -REM Function: ensureJava -REM Usage: call :ensureJava path\to\hs_err_file.txt -REM If 'java' is not found in PATH, extract JAVA_HOME from the -REM hs_err file and update PATH accordingly. -REM ======================================================== -:ensureJava - REM Check if java is available - where java >nul 2>&1 - if %ERRORLEVEL%==0 ( - REM Java found; nothing to do. - goto :EOF - ) - - REM Java not found; try to extract JAVA_HOME from the hs_err file passed as parameter. - if "%~1"=="" ( - echo Error: No hs_err file provided. - exit /b 1 - ) - - REM Use findstr to locate the line with JAVA_HOME. - for /f "tokens=2 delims==" %%A in ('findstr "JAVA_HOME" "%~1"') do ( - set "JAVA_HOME=%%A" - ) - - REM Check if JAVA_HOME was found - if not defined JAVA_HOME ( - echo Error: Java executable not found. Cannot upload error file. - exit /b 1 - ) - - REM Optionally, remove any surrounding quotes or spaces: - set "JAVA_HOME=%JAVA_HOME:"=%" - for /f "tokens=* delims= " %%A in ("%JAVA_HOME%") do set "JAVA_HOME=%%A" - - REM Prepend JAVA_HOME\bin to PATH - set "PATH=%JAVA_HOME%\bin;%PATH%" - goto :EOF - - :: Check if PID is provided if "%1"=="" ( echo "Error: No PID provided. Running in legacy mode." call :ensureJava "!JAVA_ERROR_FILE!" - java -jar "!AGENT_JAR!" uploadCrash "!JAVA_ERROR_FILE!" + "!JAVA_HOME!\bin\java" -jar "!AGENT_JAR!" uploadCrash "!JAVA_ERROR_FILE!" if %ERRORLEVEL% EQU 0 ( echo "Uploaded error file \"!JAVA_ERROR_FILE!\"" ) else ( @@ -83,7 +43,7 @@ echo JAVA_HOME: %java_home% echo PID: %PID% :: Execute the Java command with the loaded values -%java_home%\bin\java -jar "%agent%" uploadCrash "%hs_err%" +"%java_home%\bin\java" -jar "%agent%" uploadCrash "%hs_err%" set RC=%ERRORLEVEL% del "%configFile%" :: Clean up the configuration file if %RC% EQU 0 ( diff --git a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.sh b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.sh index 938fe5d1a44..e2d0f378797 100644 --- a/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.sh +++ b/dd-java-agent/agent-crashtracking/src/main/resources/com/datadog/crashtracking/upload_crash.sh @@ -2,28 +2,11 @@ set +e # Disable exit on error -function ensureJava() { - # Check if Java is available - if [ -z "$(which java)" ]; then - # Extract the JAVA_HOME from the provided hs_err file - JAVA_HOME=$(grep "JAVA_HOME" "$1") - if [ -n "$JAVA_HOME" ]; then - JAVA_HOME=$(cut -f2 -d '=' <<< "$JAVA_HOME") - export JAVA_HOME - export PATH=$JAVA_HOME/bin:$PATH - else - echo "Error: Java executable not found. Can not upload error file." - exit 1 - fi - fi -} - # Check if PID is provided if [ -z "$1" ]; then echo "Warn: No PID provided. Running in legacy mode." - ensureJava "!JAVA_ERROR_FILE!" - java -jar "!AGENT_JAR!" uploadCrash "!JAVA_ERROR_FILE!" + "!JAVA_HOME!/bin/java" -jar "!AGENT_JAR!" uploadCrash "!JAVA_ERROR_FILE!" if [ $? -eq 0 ]; then echo "Error file !JAVA_ERROR_FILE! was uploaded successfully" else @@ -65,7 +48,7 @@ echo "JAVA_HOME: ${config_java_home}" echo "PID: $PID" # Execute the Java command with the loaded values -${config_java_home}/bin/java -jar "${config_agent}" uploadCrash "${config_hs_err}" +"${config_java_home}/bin/java" -jar "${config_agent}" uploadCrash "${config_hs_err}" RC=$? rm -f "${configFile}" # Remove the configuration file diff --git a/dd-java-agent/agent-crashtracking/src/test/java/com/datadog/crashtracking/ScriptInitializerTest.java b/dd-java-agent/agent-crashtracking/src/test/java/com/datadog/crashtracking/ScriptInitializerTest.java index 98a1c6974f4..0c7ffabe7c7 100644 --- a/dd-java-agent/agent-crashtracking/src/test/java/com/datadog/crashtracking/ScriptInitializerTest.java +++ b/dd-java-agent/agent-crashtracking/src/test/java/com/datadog/crashtracking/ScriptInitializerTest.java @@ -11,6 +11,7 @@ import java.nio.file.attribute.PosixFilePermissions; import java.util.Comparator; import java.util.List; +import java.util.regex.Pattern; import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -63,6 +64,9 @@ void testCrashUploaderInitializationSuccess(String target, String pidArg) assertTrue(Files.exists(file), "File " + file + " should have been created"); List lines = Files.readAllLines(file); assertFalse(lines.isEmpty(), "File " + file + " is expected to be non-empty"); + // sanity check to see if no placeholders are left + Pattern placeholder = Pattern.compile("![A-Z_]+!"); + assertFalse(lines.stream().anyMatch(l -> placeholder.matcher(l).find())); // sanity to check the crash log file was properly replaced in the script assertTrue(lines.stream().anyMatch(l -> l.contains(hsErrFile))); // sanity to check the java home was properly captured