/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package utils; import java.util.Map; import java.util.Scanner; import java.util.regex.MatchResult; /** * * jstack default format 2008-03-05 18:36:26 Full thread dump Java HotSpot(TM) * Client VM (11.0-b11 mixed mode): * * "Thread-16" #10 daemon prio=3 os_prio=0 tid=0x0814d800 nid=0x1d runnable * [0xf394d000..0xf394d9f0] java.lang.Thread.State: RUNNABLE at * java.net.SocketInputStream.socketRead0(Native Method) at * java.net.SocketInputStream.read(SocketInputStream.java:129) at * java.net.SocketInputStream.read(SocketInputStream.java:182) at * java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2249) * at * java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2542) * at * java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2552) * at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1297) at * java.io.ObjectInputStream.readObject(ObjectInputStream.java:351) at * tmtools.share.debuggee.DebuggeeProtocolHandler.run(DebuggeeProtocolHandler.java:32) * * Locked ownable synchronizers: - None .... * * Note that os_prio field is optional and will be printed only if JVM was able * to get native thread priority. */ public class DefaultFormat implements Format { protected String threadInfoPattern() { return "^\"(.*)\"\\s(#\\d+\\s|)(daemon\\s|)prio=(.+)\\s(os_prio=(.+)\\s|)tid=(.+)\\snid=(.+)\\s(" + Consts.UNKNOWN + "|runnable|waiting\\son\\scondition|in\\sObject\\.wait\\(\\)|waiting\\sfor\\smonitor\\sentry)((.*))$"; } protected String methodInfoPattern() { return "^\\s+at\\s(.+)\\((.*?)(\\:|\\))((.*?))\\)?$"; } protected String extendedStatusPattern() { return "\\s+java\\.lang\\.Thread\\.State\\:\\s((.+))$"; } protected String jniGlobalRefInfoPattern() { return "^JNI\\sglobal\\sreferences:\\s((.+))$"; } // Sample string that matches the pattern: // waiting on <0x000000008f64e6d0> (a java.lang.Object) protected String monitorInfoPattern() { return "^\\s+\\-\\s(locked|waiting\\son|waiting\\sto\\slock)\\s\\<(.*)\\>\\s\\(((.*))\\)$"; } // Sample string that matches the pattern: // waiting on <no object reference available> protected String monitorInfoNoObjectRefPattern() { return "^\\s+\\-\\s(locked|waiting\\son|waiting\\sto\\slock)\\s\\<(.*)\\>$"; } protected String vmVersionInfoPattern() { return "Full\\sthread\\sdump\\s.*"; } protected String ownableSynchronizersPattern() { return "^\\s+\\-\\s(\\<.*\\>\\s\\(((.*))\\)|None)$"; } public JStack parse(String stack) { JStack result = new JStack(); Scanner scanner = new Scanner(stack); // parsing thread stacks ThreadStack currentThreadStack = null; MethodInfo currentMethodInfo = null; try { while (scanner.hasNextLine()) { String line = scanner.nextLine(); if (line.matches(threadInfoPattern())) { currentThreadStack = parseThreadInfo(line); result.addThreadStack(currentThreadStack.getThreadName(), currentThreadStack); } else if (line.matches(methodInfoPattern())) { currentMethodInfo = parseMethodInfo(line); currentThreadStack.addMethod(currentMethodInfo); } else if (line.matches(monitorInfoPattern())) { MonitorInfo mi = parseMonitorInfo(line, monitorInfoPattern()); currentMethodInfo.getLocks().add(mi); } else if (line.matches(monitorInfoNoObjectRefPattern())) { MonitorInfo mi = parseMonitorInfo(line, monitorInfoNoObjectRefPattern()); currentMethodInfo.getLocks().add(mi); } else if (line.matches(extendedStatusPattern())) { currentThreadStack.setExtendedStatus(parseExtendedStatus(line)); } else if (line.matches(vmVersionInfoPattern())) { result.setVmVersion(line); } else if (line.matches(ownableSynchronizersPattern())) { currentThreadStack.getLockOSList().add(parseLockInfo(line)); } else if (line.matches(jniGlobalRefInfoPattern())) { result.setJniGlobalReferences(parseJNIGlobalRefs(line)); } else if (line.length() != 0) { System.err.println("[Warning] Unknown string: " + line); } } scanner.close(); } catch (NullPointerException e) { e.printStackTrace(); throw new RuntimeException("Unexpected format in jstack output"); } return result; } private MonitorInfo parseMonitorInfo(String line, String pattern) { Scanner s = new Scanner(line); s.findInLine(pattern); MonitorInfo mi = new MonitorInfo(); MatchResult res = s.match(); mi.setType(res.group(1)); mi.setMonitorAddress(res.group(2)); if (res.groupCount() > 2) { mi.setMonitorClass(res.group(3)); } return mi; } protected String parseExtendedStatus(String line) { Scanner s = new Scanner(line); s.findInLine(extendedStatusPattern()); String result = s.match().group(1); s.close(); return result; } protected String parseJNIGlobalRefs(String line) { Scanner s = new Scanner(line); s.findInLine(jniGlobalRefInfoPattern()); String result = s.match().group(1); s.close(); return result; } protected ThreadStack parseThreadInfo(String threadInfo) { Scanner s = new Scanner(threadInfo); ThreadStack result = new ThreadStack(); // parsing thread info s.findInLine(threadInfoPattern()); MatchResult res = s.match(); result.setThreadName(res.group(1)); result.setType(res.group(3)); result.setPriority(res.group(4)); result.setTid(res.group(7)); result.setNid(res.group(8)); result.setStatus(res.group(9)); s.close(); return result; } protected MethodInfo parseMethodInfo(String line) { MethodInfo result = new MethodInfo(); Scanner s = new Scanner(line); s.findInLine(methodInfoPattern()); MatchResult rexp = s.match(); if (rexp.group(4) != null && rexp.group(4).length() > 0) { // line " at tmtools.jstack.share.utils.Utils.sleep(Utils.java:29)" result.setName(rexp.group(1)); result.setCompilationUnit(rexp.group(2)); result.setLine(rexp.group(4)); } else { // line " at java.lang.Thread.sleep(Native Method)" result.setName(rexp.group(1)); } s.close(); return result; } public String dumpStackTraces() { StringBuffer result = new StringBuffer(); Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces(); // adding data and vm version result.append(Consts.UNKNOWN + "\n"); result.append(Consts.UNKNOWN + "\n\n"); for (Thread t : stacks.keySet()) { result.append("\"" + t.getName() + "\""); result.append(Consts.SEPARATOR); // status if (t.isDaemon()) { result.append("daemon"); result.append(Consts.SEPARATOR); } // priority result.append("prio=" + t.getPriority()); result.append(Consts.SEPARATOR); // tid result.append("tid=" + Consts.UNKNOWN); result.append(Consts.SEPARATOR); // nid result.append("nid=" + Consts.UNKNOWN); result.append(Consts.SEPARATOR); // status result.append(Consts.UNKNOWN); result.append(Consts.SEPARATOR); result.append("\n"); // extended status result.append(" java.lang.Thread.State: " + String.valueOf(Thread.currentThread().getState())); result.append(Consts.SEPARATOR); result.append("\n"); for (StackTraceElement st : stacks.get(t)) { result.append(" at " + st.toString() + "\n"); } result.append("\n"); } result.append(Consts.JNI_GLOBAL_REF + Consts.UNKNOWN + "\n"); return result.toString(); } protected LockInfo parseLockInfo(String line) { LockInfo res = new LockInfo(); Scanner s = new Scanner(line); s.findInLine(ownableSynchronizersPattern()); MatchResult matchRes = s.match(); String lock = matchRes.group(1).equals("None") ? matchRes.group(1) : matchRes.group(2); res.setLock(lock); return res; } }