Copied from HERE with some code modification.
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.management.ManagementFactory;
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
public class StackTraceUtils {
private static final char PID_SEPERATOR = '@';
private static String pathToJStack = "jstack";
private static String acquirePid()
{
String mxName = ManagementFactory.getRuntimeMXBean().getName();
int index = mxName.indexOf(PID_SEPERATOR);
String result;
if (index != -1) {
result = mxName.substring(0, index);
} else {
throw new IllegalStateException("Could not acquire pid using " + mxName);
}
return result;
}
public static String executeJstack()
{
ProcessInterface pi = new ProcessInterface();
int exitCode;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
exitCode = pi.run(new String[] { pathToJStack, "-l", acquirePid(),}, byteArrayOutputStream);
} catch (Exception e) {
throw new IllegalStateException("Error invoking jstack", e);
}
if (exitCode != 0) {
throw new IllegalStateException("Bad jstack exit code " + exitCode);
}
try {
String str = new String(byteArrayOutputStream.toByteArray(), "UTF-8");
return str;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
final String s = executeJstack();
System.out.println("s = " + s);
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class ProcessInterface
{
private final Map<String, String> addModifyEnv;
private final Set<String> removeEnv;
static class StreamGobbler extends Thread
{
private static int gobblerNumber = 0;
private final InputStream is;
private final OutputStream os;
private static synchronized int getNextGobblerNumber()
{
return gobblerNumber++;
}
public StreamGobbler(InputStream is, OutputStream os)
{
super("StreamGobblerThread-" + getNextGobblerNumber());
this.is = is;
this.os = os;
}
@Override
public void run()
{
try
{
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null)
{
bw.write(line);
bw.newLine();
}
bw.flush();
osw.flush();
}
catch (IOException ioe)
{
throw new IllegalStateException(ioe);
}
}
}
public ProcessInterface()
{
this.addModifyEnv = new HashMap<String, String>();
this.removeEnv = new HashSet<String>();
}
public void removeEnv(String name)
{
if (addModifyEnv.containsKey(name))
{
addModifyEnv.remove(name);
}
removeEnv.add(name);
}
public void addEnv(String name, String value)
{
if (removeEnv.contains(name))
{
removeEnv.remove(name);
}
addModifyEnv.put(name, value);
}
public int run(String[] command) throws InterruptedException, IOException
{
return run(command, null, null, null);
}
public int run(String[] command, File workingDir) throws InterruptedException, IOException
{
return run(command, null, null, workingDir);
}
public int run(String[] command, OutputStream os) throws InterruptedException, IOException
{
return run(command, os, os, null);
}
public int run(String[] command, OutputStream os, File workingDir) throws InterruptedException, IOException
{
return run(command, os, os, workingDir);
}
public int run(String[] command, OutputStream std, OutputStream err, File workingDir)
throws InterruptedException, IOException
{
StringBuilder sb = new StringBuilder();
for (String s : command)
{
sb.append(s);
sb.append(" ");
}
ProcessBuilder builder = new ProcessBuilder();
if (workingDir != null)
{
builder.directory(workingDir);
}
Map<String, String> env = builder.environment();
for (String name : removeEnv)
{
env.remove(name);
}
for (Entry<String, String> entry : addModifyEnv.entrySet())
{
env.put(entry.getKey(), entry.getValue());
}
builder.command(command);
Process process = builder.start();
OutputStream outStream = ((std == null) ? System.out : std);
OutputStream errStream = ((err == null) ? System.err : err);
StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), outStream);
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), errStream);
outputGobbler.start();
errorGobbler.start();
int exitVal = process.waitFor();
return exitVal;
}
}
This can be very helpful, for example in a code block you suspect there is a deadlock, for Example timeout from connection pool , you can log the stacktrace so you can come back later and run a ThreadDump analysis tool on it. Add it to your code before the Operations guy restart your problematic server and report an issue in your name !