|  | 
| 4 | 4 | import static java.util.Comparator.reverseOrder; | 
| 5 | 5 | import static java.util.Locale.ROOT; | 
| 6 | 6 | 
 | 
| 7 |  | -import com.sun.management.HotSpotDiagnosticMXBean; | 
|  | 7 | +import com.datadoghq.profiler.JVMAccess; | 
| 8 | 8 | import datadog.trace.api.Platform; | 
|  | 9 | +import datadog.trace.api.config.ProfilingConfig; | 
|  | 10 | +import datadog.trace.bootstrap.config.provider.ConfigProvider; | 
| 9 | 11 | import datadog.trace.util.PidHelper; | 
| 10 | 12 | import java.io.BufferedWriter; | 
| 11 | 13 | import java.io.IOException; | 
| 12 | 14 | import java.io.InputStream; | 
| 13 |  | -import java.lang.management.ManagementFactory; | 
| 14 | 15 | import java.net.URL; | 
| 15 | 16 | import java.nio.file.Files; | 
| 16 | 17 | import java.nio.file.Path; | 
|  | 
| 20 | 21 | import org.slf4j.Logger; | 
| 21 | 22 | import org.slf4j.LoggerFactory; | 
| 22 | 23 | 
 | 
| 23 |  | -public final class ScriptInitializer { | 
| 24 |  | -  static final Logger LOG = LoggerFactory.getLogger(ScriptInitializer.class); | 
|  | 24 | +public final class Initializer { | 
|  | 25 | +  static final Logger LOG = LoggerFactory.getLogger(Initializer.class); | 
| 25 | 26 |   static final String PID_PREFIX = "_pid"; | 
| 26 | 27 |   static final String RWXRWXRWX = "rwxrwxrwx"; | 
| 27 | 28 |   static final String R_XR_XR_X = "r-xr-xr-x"; | 
| 28 | 29 | 
 | 
| 29 | 30 |   public static void initialize() { | 
| 30 |  | -    // this is HotSpot specific implementation (eg. will not work for IBM J9) | 
| 31 |  | -    HotSpotDiagnosticMXBean diagBean = | 
| 32 |  | -        ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); | 
|  | 31 | +    ConfigProvider cfgProvider = ConfigProvider.getInstance(); | 
|  | 32 | +    String scratchDir = cfgProvider.getString(ProfilingConfig.PROFILING_DATADOG_PROFILER_SCRATCH); | 
| 33 | 33 | 
 | 
| 34 |  | -    initializeCrashUploader(diagBean); | 
| 35 |  | -    initializeOOMENotifier(diagBean); | 
|  | 34 | +    JVMAccess jvmAccess = | 
|  | 35 | +        new JVMAccess( | 
|  | 36 | +            null, | 
|  | 37 | +            scratchDir, | 
|  | 38 | +            throwable -> { | 
|  | 39 | +              logInitializationError( | 
|  | 40 | +                  "Unexpected exception while initializing JVMAccess", throwable); | 
|  | 41 | +            }); | 
|  | 42 | + | 
|  | 43 | +    JVMAccess.Flags flags = jvmAccess.flags(); | 
|  | 44 | + | 
|  | 45 | +    initializeCrashUploader(flags); | 
|  | 46 | +    initializeOOMENotifier(flags); | 
| 36 | 47 |   } | 
| 37 | 48 | 
 | 
| 38 | 49 |   static InputStream getCrashUploaderTemplate() { | 
| @@ -130,28 +141,75 @@ private static String getBaseName(Path path) { | 
| 130 | 141 |    * `dd_crash_uploader.bat` and the script does not exist it will be created and prefilled with | 
| 131 | 142 |    * code ensuring the error log upload will be triggered on JVM crash. | 
| 132 | 143 |    */ | 
| 133 |  | -  private static void initializeCrashUploader(HotSpotDiagnosticMXBean diagBean) { | 
|  | 144 | +  private static void initializeCrashUploader(JVMAccess.Flags flags) { | 
| 134 | 145 |     try { | 
| 135 |  | -      String onErrorVal = diagBean.getVMOption("OnError").getValue(); | 
| 136 |  | -      String onErrorFile = diagBean.getVMOption("ErrorFile").getValue(); | 
| 137 |  | -      CrashUploaderScriptInitializer.initialize(onErrorVal, onErrorFile); | 
|  | 146 | +      String onErrorVal = flags.getStringFlag("OnError"); | 
|  | 147 | +      String onErrorFile = flags.getStringFlag("ErrorFile"); | 
|  | 148 | + | 
|  | 149 | +      String uploadScript = getScript("dd_crash_uploader"); | 
|  | 150 | +      if (onErrorVal == null || onErrorVal.isEmpty()) { | 
|  | 151 | +        onErrorVal = uploadScript; | 
|  | 152 | +      } else if (!onErrorVal.contains("dd_crash_uploader")) { | 
|  | 153 | +        // we can chain scripts so let's preserve the original value in addition to our crash | 
|  | 154 | +        // uploader | 
|  | 155 | +        onErrorVal = uploadScript + "; " + onErrorVal; | 
|  | 156 | +      } | 
|  | 157 | + | 
|  | 158 | +      // set the JVM flag | 
|  | 159 | +      flags.setStringFlag("OnError", onErrorVal); | 
|  | 160 | +      if (LOG.isDebugEnabled()) { | 
|  | 161 | +        String currentVal = flags.getStringFlag("OnError"); | 
|  | 162 | +        if (!currentVal.equals(uploadScript)) { | 
|  | 163 | +          LOG.debug("Unable to set OnError flag to {}. Crash-tracking may not work.", currentVal); | 
|  | 164 | +        } | 
|  | 165 | +      } | 
|  | 166 | + | 
|  | 167 | +      CrashUploaderScriptInitializer.initialize(uploadScript, onErrorFile); | 
| 138 | 168 |     } catch (Throwable t) { | 
| 139 | 169 |       logInitializationError( | 
| 140 | 170 |           "Unexpected exception while creating custom crash upload script. Crash tracking will not work properly.", | 
| 141 | 171 |           t); | 
| 142 | 172 |     } | 
| 143 | 173 |   } | 
| 144 | 174 | 
 | 
| 145 |  | -  private static void initializeOOMENotifier(HotSpotDiagnosticMXBean diagBean) { | 
|  | 175 | +  private static void initializeOOMENotifier(JVMAccess.Flags flags) { | 
| 146 | 176 |     try { | 
| 147 |  | -      String onOutOfMemoryVal = diagBean.getVMOption("OnOutOfMemoryError").getValue(); | 
| 148 |  | -      OOMENotifierScriptInitializer.initialize(onOutOfMemoryVal); | 
|  | 177 | +      String onOutOfMemoryVal = flags.getStringFlag("OnOutOfMemoryError"); | 
|  | 178 | +      String notifierScript = getScript("dd_oome_notifier"); | 
|  | 179 | + | 
|  | 180 | +      if (onOutOfMemoryVal == null || onOutOfMemoryVal.isEmpty()) { | 
|  | 181 | +        onOutOfMemoryVal = notifierScript; | 
|  | 182 | +      } else if (!onOutOfMemoryVal.contains("dd_oome_notifier")) { | 
|  | 183 | +        // we can chain scripts so let's preserve the original value in addition to our oome tracker | 
|  | 184 | +        onOutOfMemoryVal = notifierScript + "; " + onOutOfMemoryVal; | 
|  | 185 | +      } | 
|  | 186 | + | 
|  | 187 | +      // set the JVM flag | 
|  | 188 | +      flags.setStringFlag("OnOutOfMemoryError", onOutOfMemoryVal); | 
|  | 189 | +      if (LOG.isDebugEnabled()) { | 
|  | 190 | +        String currentVal = flags.getStringFlag("OnOutOfMemoryError"); | 
|  | 191 | +        if (!currentVal.equals(onOutOfMemoryVal)) { | 
|  | 192 | +          LOG.debug( | 
|  | 193 | +              "Unable to set OnOutOfMemoryError flag to {}. OOME tracking may not work.", | 
|  | 194 | +              currentVal); | 
|  | 195 | +        } | 
|  | 196 | +      } | 
|  | 197 | + | 
|  | 198 | +      OOMENotifierScriptInitializer.initialize(notifierScript); | 
| 149 | 199 |     } catch (Throwable t) { | 
| 150 | 200 |       logInitializationError( | 
| 151 | 201 |           "Unexpected exception while initializing OOME notifier. OOMEs will not be tracked.", t); | 
| 152 | 202 |     } | 
| 153 | 203 |   } | 
| 154 | 204 | 
 | 
|  | 205 | +  private static String getScript(String scriptName) { | 
|  | 206 | +    return System.getProperty("java.io.tmpdir") + "/" + getScriptFileName(scriptName) + " %p"; | 
|  | 207 | +  } | 
|  | 208 | + | 
|  | 209 | +  private static String getScriptFileName(String scriptName) { | 
|  | 210 | +    return scriptName + "." + (Platform.isWindows() ? "bat" : "sh"); | 
|  | 211 | +  } | 
|  | 212 | + | 
| 155 | 213 |   private static void logInitializationError(String msg, Throwable t) { | 
| 156 | 214 |     if (LOG.isDebugEnabled()) { | 
| 157 | 215 |       LOG.warn("{}", msg, t); | 
|  | 
0 commit comments