Skip to content

Commit

Permalink
Add a startup profiler for debugging (#2085)
Browse files Browse the repository at this point in the history
* Add StartupProfiler

* Fix errorprone

* Fix spotless

* Invoke before premain

Co-authored-by: Trask Stalnaker <[email protected]>

* Create dump in applicationinsights folder

* Show the full path of the dump

* Fix lgtm

* Allow sout

* Fix lgtm

* Supress systemout at the method level

* Fix style complain

* Address comments

* Fix spotless

* Address comments

* Return when exception occurs

* Remove comment

Co-authored-by: Trask Stalnaker <[email protected]>

* Use getBoolean for system property

Co-authored-by: Trask Stalnaker <[email protected]>
  • Loading branch information
heyams and trask authored Feb 7, 2022
1 parent 32709f0 commit 836e268
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public static void premain(String agentArgs, Instrumentation inst) {
if (alreadyLoaded) {
return;
}

if (Boolean.getBoolean("applicationinsights.debug.startupProfiling")) {
StartupProfiler.start();
}

OpenTelemetryAgent.premain(agentArgs, inst);
alreadyLoaded = true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* ApplicationInsights-Java
* Copyright (c) Microsoft Corporation
* All rights reserved.
*
* MIT License
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the ""Software""), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

package com.microsoft.applicationinsights.agent;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

final class StartupProfiler {

private static final String STACKTRACES = "stacktrace.txt";

@SuppressWarnings("SystemOut")
public static void start() {
String tempDirectory = System.getProperty("java.io.tmpdir");
File folder = new File(tempDirectory, "applicationinsights");
if (!folder.exists()) {
folder.mkdirs();
}

File dumpFile = new File(folder, STACKTRACES);
System.out.println("Writing startup profiler to '" + dumpFile.getPath() + "'");

PrintWriter printWriter = null;
try (PrintWriter out =
new PrintWriter(Files.newBufferedWriter(dumpFile.toPath(), Charset.defaultCharset()))) {
printWriter = new PrintWriter(out);
} catch (IOException e) {
if (printWriter != null) {
printWriter.close();
}
System.out.println("Error occurred when writing dump to " + dumpFile.getPath());
e.printStackTrace();
return;
}

start(printWriter);
}

private static void start(PrintWriter out) {
Executors.newSingleThreadScheduledExecutor()
.scheduleAtFixedRate(new ThreadDump(out), 50, 50, TimeUnit.MILLISECONDS);
}

private StartupProfiler() {}

private static class ThreadDump implements Runnable {

private final PrintWriter out;

private ThreadDump(PrintWriter out) {
this.out = out;
}

@Override
public void run() {
out.println("========================================");
RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
out.println(runtimeBean.getUptime());
out.println();
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos =
threadBean.getThreadInfo(
threadBean.getAllThreadIds(), threadBean.isObjectMonitorUsageSupported(), false);
long currentThreadId = Thread.currentThread().getId();
for (ThreadInfo threadInfo : threadInfos) {
if (threadInfo.getThreadId() != currentThreadId) {
write(threadInfo);
}
}
out.flush();
}

private void write(ThreadInfo threadInfo) {
out.println(threadInfo.getThreadName() + " #" + threadInfo.getThreadId());
out.println(" java.lang.Thread.State: " + threadInfo.getThreadState());
for (StackTraceElement ste : threadInfo.getStackTrace()) {
out.println(" " + ste);
}
out.println();
}
}
}

0 comments on commit 836e268

Please sign in to comment.