Created
November 25, 2012 20:48
-
-
Save jarek-przygodzki/4145271 to your computer and use it in GitHub Desktop.
JVM thread dump in Groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env groovy | |
import java.lang.management.* | |
import javax.management.* | |
import javax.management.remote.* | |
import java.text.* | |
def vmInfo(prop) { | |
def vmName = prop.getProperty('java.vm.name') | |
def vmVer = prop.getProperty('java.vm.version') | |
def vmInfo = prop.getProperty('java.vm.info') | |
return "Full thread dump $vmName $vmVer $vmInfo" | |
} | |
def getProperties(runtimeMxBean) { | |
def systemProperties = new Properties() | |
systemProperties.putAll(runtimeMxBean.getSystemProperties()) | |
return systemProperties | |
} | |
def jstack(serviceUrl, out) { | |
jmxUrl = new JMXServiceURL(serviceUrl) | |
JMXConnector jmxc = JMXConnectorFactory.connect(jmxUrl, null) | |
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection() | |
ThreadMXBean threadMXBean = ManagementFactory.newPlatformMXBeanProxy(mbsc, | |
ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class) | |
RuntimeMXBean runtimeMxBean = ManagementFactory.newPlatformMXBeanProxy(mbsc, | |
ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class) | |
ThreadInfo[] threads = threadMXBean.dumpAllThreads(true, true) | |
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") | |
out.println df.format(new Date()) | |
out.print vmInfo(getProperties(runtimeMxBean)) | |
out.println ':' | |
threads.each { t -> | |
printThreadInfo(t, out) | |
} | |
} | |
def printThreadInfo(ThreadInfo thread, out) { | |
monitors = thread.lockedMonitors | |
out.println() | |
out.println "\"$thread.threadName\" tid=$thread.threadId" | |
out.println "\tjava.lang.Thread.State: $thread.threadState" | |
thread.stackTrace.eachWithIndex { st, index -> | |
lock = thread.lockInfo | |
lockOwner = thread.lockOwnerName | |
out.println "\t\tat $st" | |
if (index == 0) { | |
if ("java.lang.Object".equals(st.getClassName()) && "wait".equals(st.getMethodName())) { | |
if (lock != null) { | |
out.print "\t\t- waiting on " | |
printLock(lock, out) | |
out.println() | |
} | |
} else if (lock != null) { | |
if (lockOwner == null) { | |
out.print "\t\t- parking to wait for " | |
printLock(lock, out) | |
out.println() | |
} else { | |
out.print "\t\t- waiting to lock " | |
printLock(lock, out) | |
out.println " owned by \"$lockOwner\" t@$thread.lockOwnerId" | |
} | |
} | |
} | |
printMonitors(monitors, index, out) | |
} | |
synchronizers = thread.lockedSynchronizers | |
out.println() | |
printSynchronizers(synchronizers, out) | |
} | |
def printLock(lockInfo, out) { | |
id = Integer.toHexString(lockInfo.getIdentityHashCode()) | |
className = lockInfo.getClassName() | |
out.print "<0x$id> (a $className)" | |
} | |
def printMonitors(monitors, index, out) { | |
if(monitors) { | |
monitors.each { mi -> | |
if (mi.getLockedStackDepth() == index) { | |
out.print "\t\t- locked " | |
printLock(mi, out) | |
out.println() | |
} | |
} | |
} | |
} | |
def printSynchronizers(synchronizers, out) { | |
out.println "\tLocked ownable synchronizers:" | |
if (synchronizers == null || synchronizers.length == 0) { | |
out.println "\t- None" | |
} else { | |
synchronizers.each { li -> | |
out.print "\t- locked " | |
printLock(li, out); | |
out.println() | |
} | |
} | |
} | |
def cli = new CliBuilder(usage: 'jstack -u <jmx url>', | |
header: 'JVM thread dump in Groovy') | |
cli.with { | |
h longOpt: 'help' , args: 0, 'Show usage information and quit' | |
u longOpt: 'jmxurl', args: 1, argName: 'jmx url', 'JMX service URL' | |
o longOpt: 'output', args: 1, argName: 'output file', 'Output file' | |
} | |
def opts = cli.parse(args) | |
if(!opts) { | |
// because the parse failed, the usage will be shown automatically | |
return | |
} | |
if (opts.h || !opts.u) { | |
cli.usage() | |
return | |
} | |
if(opts.o) { | |
def sw = new StringWriter() | |
def pw = new PrintWriter(sw) | |
jstack(opts.u, pw) | |
pw.close() | |
new File(opts.o).withWriter { w -> | |
w << sw.toString() | |
} | |
} else { | |
jstack(opts.u, System.out) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment