/* * This file is part of TDA - Thread Dump Analysis Tool. * * TDA is free software; you can redistribute it and/or modify * it under the terms of the Lesser GNU General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * TDA 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 * Lesser GNU General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with TDA; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * $Id: BeaJDKParser.java,v 1.12 2010-01-03 14:23:09 irockel Exp $ */ package com.pironet.tda.parser.impl; import java.io.BufferedReader; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.MutableTreeNode; import com.pironet.tda.MonitorMap; import com.pironet.tda.TDA; import com.pironet.tda.TableCategory; import com.pironet.tda.ThreadDumpInfo; import com.pironet.tda.TreeCategory; import com.pironet.tda.parser.AbstractDumpParser; import com.pironet.tda.utils.DateMatcher; import com.pironet.tda.utils.IconFactory; /** * Parses Bea/JRockit Thread Dumps * * TODO add line info * * @author irockel */ public class BeaJDKParser extends AbstractDumpParser { private MutableTreeNode nextDump = null; private Map threadStore = null; private int counter = 1; // Number of the thread dump private int lineCounter = 0; // private boolean foundClassHistograms = false; // private boolean withCurrentTimeStamp = false; /** * constructs a new instance of a bea jdk parser * @param dumpFileStream the dump file stream to read. * @param threadStore the thread store to store the thread informations in. */ public BeaJDKParser(BufferedReader bis, Map threadStore, int lineCounter, DateMatcher dm) { super(bis, dm); this.threadStore = threadStore; this.lineCounter = lineCounter; } /** * returns true if at least one more dump available, already loads it * (this will be returned on next call of parseNext) */ public boolean hasMoreDumps() { // throw new UnsupportedOperationException("Not supported yet."); nextDump = parseNext(); return(nextDump != null); } /** * parse the next thread dump from the stream passed with the constructor. * @returns null if no more thread dumps were found. */ public MutableTreeNode parseNext() { if (nextDump != null) { MutableTreeNode tmpDump = nextDump; nextDump = null; return(tmpDump); } boolean retry = false; do { DefaultMutableTreeNode threadDump = null; ThreadDumpInfo overallTDI = null; DefaultMutableTreeNode catMonitors = null; DefaultMutableTreeNode catMonitorsLocks = null; DefaultMutableTreeNode catThreads = null; DefaultMutableTreeNode catLocking = null; DefaultMutableTreeNode catSleeping = null; DefaultMutableTreeNode catWaiting = null; try { Map threads = new HashMap(); overallTDI = new ThreadDumpInfo("Dump No. " + counter++, 0); threadDump = new DefaultMutableTreeNode(overallTDI); catThreads = new DefaultMutableTreeNode(new TableCategory("Threads", IconFactory.THREADS)); threadDump.add(catThreads); catWaiting = new DefaultMutableTreeNode(new TableCategory("Threads waiting for Monitors", IconFactory.THREADS_WAITING)); catSleeping = new DefaultMutableTreeNode(new TableCategory("Threads sleeping on Monitors", IconFactory.THREADS_SLEEPING)); catLocking = new DefaultMutableTreeNode(new TableCategory("Threads locking Monitors", IconFactory.THREADS_LOCKING)); // create category for monitors with disabled filtering. catMonitors = new DefaultMutableTreeNode(new TreeCategory("Monitors", IconFactory.MONITORS, false)); catMonitorsLocks = new DefaultMutableTreeNode(new TreeCategory("Monitors without locking thread", IconFactory.MONITORS_NOLOCKS, false)); String title = null; StringBuffer content = null; StringBuffer lContent = null; StringBuffer sContent = null; StringBuffer wContent = null; int threadCount = 0; int waiting = 0; int locking = 0; int sleeping = 0; boolean locked = true; // true means we haven't hit the beggining of a thread dump yet boolean finished = false; MonitorMap mmap = new MonitorMap(); Stack monitorStack = new Stack(); long startTime = 0; int singleLineCounter = 0; Matcher matched = getDm().getLastMatch(); while (getBis().ready() && !finished) { String line = getBis().readLine(); lineCounter++; singleLineCounter++; if (locked) { // Are we outside of a thread dump ? if (line.indexOf("===== FULL THREAD DUMP ===============") >= 0) { locked = false; } } else { // Alright we're already inside a dump if (line.indexOf("-- end of trace")>= 0){ System.out.print("x"); } if (line.startsWith("\"")) { // Did we hit a new thread ? String stringContent = content != null ? content.toString() : null; if (title != null) { // Let's store the previous thread threads.put(title, content.toString()); content.append("</pre></pre>"); addToCategory(catThreads, title, null, stringContent, singleLineCounter, true); threadCount++; } if (wContent != null) { wContent.append("</b><hr>"); addToCategory(catWaiting, title, null, stringContent, singleLineCounter, true); wContent = null; waiting++; } if (sContent != null) { sContent.append("</b><hr>"); addToCategory(catSleeping, title, null, stringContent, singleLineCounter, true); sContent = null; sleeping++; } if (lContent != null) { lContent.append("</b><hr>"); addToCategory(catLocking, title, null, stringContent, singleLineCounter, true); lContent = null; locking++; } singleLineCounter = 0; while (!monitorStack.empty()) { mmap.parseAndAddThread((String) monitorStack.pop(), title, content.toString()); } title = line; content = new StringBuffer("<body bgcolor=\"ffffff\"><pre><font size=" + TDA.getFontSizeModifier(-1) + ">"); content.append(line); content.append("\n"); } else if (line.indexOf("at ") >= 0) { // enganado por [fat lock] content.append(line); content.append("\n"); } else if (line.indexOf("-- Waiting for notification") >= 0) { String newLine = linkifyMonitor(line); content.append(newLine); if (sContent == null) { sContent = new StringBuffer("<body bgcolor=\"ffffff\"><font size=" + TDA.getFontSizeModifier(-1) + "><b>"); } sContent.append(newLine); monitorStack.push(line); sContent.append("\n"); content.append("\n"); } } } } catch (Exception e) { System.out.println(e.toString()); } } while (retry); // Keep parsing until we get a full thread dump, or the file ends return(null); // throw new UnsupportedOperationException("Not supported yet."); } private String linkifyMonitor(String line) { if(line != null && line.indexOf('@') >= 0) { String begin = line.substring(0, line.indexOf('@')); String monitor = line.substring(line.indexOf('@'), line.indexOf('[') + 1); String end = line.substring(line.indexOf('>') + 1); monitor = monitor.replaceAll("@", "<a href=\"monitor://" + monitor + "\"><"); monitor = monitor.substring(0, monitor.length() - 1) + "></a>"; return(begin + monitor + end); } else { return(line); } } public boolean isFoundClassHistograms() { // bea parser doesn't support class histograms return false; } public void parseLoggcFile(InputStream loggcFileStream, DefaultMutableTreeNode root) { throw new UnsupportedOperationException("Not supported yet."); } @Override public void setDumpHistogramCounter(int value) { throw new UnsupportedOperationException("Not supported yet."); } /** * check if the passed logline contains the beginning of a Bea jdk thread * dump. * @param logLine the line of the logfile to test * @return true, if the start of a bea thread dump is detected. */ public static boolean checkForSupportedThreadDump(String logLine) { return (logLine.trim().indexOf("===== FULL THREAD DUMP ===============") >= 0); } @Override protected String[] getThreadTokens(String name) { String patternMask = "^.*\"([^\"]+)\".*id=([^ ]+).*tid=([^ ]+).*"+ "prio=([^ ]+) ([^,]+,? ?[^,]+?,? ?[^,]+?,? ?[^,]+?)(, daemon)?$"; Pattern p = Pattern.compile(patternMask); Matcher m = p.matcher(name); System.out.println(m.matches()); for (int iLoop =1; iLoop < m.groupCount(); iLoop++){ System.out.println(iLoop+": "+m.group(iLoop)); } String[] tokens = new String[7]; tokens[0] = m.group(1); // name tokens[2] = m.group(4); // prio tokens[3] = m.group(3); // tid tokens[4] = m.group(2); // nid tokens[5] = m.group(5); // State return (tokens); } }