/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2010-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) 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 for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.systemreport.system; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.util.TreeMap; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteWatchdog; import org.apache.commons.io.IOUtils; import org.opennms.core.utils.LogUtils; import org.opennms.systemreport.AbstractSystemReportPlugin; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; public class ThreadReportPlugin extends AbstractSystemReportPlugin { public String getName() { return "Threads"; } public String getDescription() { return "Java thread dump (full output only)"; } public int getPriority() { return 10; } public TreeMap<String, Resource> getEntries() { final TreeMap<String,Resource> map = new TreeMap<String,Resource>(); LogUtils.tracef(this, "starting thread dump"); triggerThreadDump(); LogUtils.tracef(this, "thread dump finished"); final String outputLog = System.getProperty("opennms.home") + File.separator + "logs" + File.separator + "daemon" + File.separator + "output.log"; LogUtils.debugf(this, "reading file " + outputLog); final File outputLogFile = new File(outputLog); FileReader fr = null; BufferedReader bfr = null; FileWriter fw = null; File threadDumpFile = null; String threadDump = null; if (outputLogFile.exists()) { try { threadDumpFile = File.createTempFile("ThreadReportPlugin", null); threadDumpFile.deleteOnExit(); fr = new FileReader(outputLogFile); bfr = new BufferedReader(fr); fw = new FileWriter(threadDumpFile); String line; StringBuffer sb = null; boolean endOnCarriageReturn = false; while ((line = bfr.readLine()) != null) { if (line.startsWith("Full thread dump")) { LogUtils.debugf(this, "found full thread dump"); sb = new StringBuffer(); sb.append(line).append("\n"); } else if (sb != null) { if (endOnCarriageReturn && line.length() == 0) { endOnCarriageReturn = false; threadDump = sb.toString(); sb = null; } else if (line.startsWith("Heap")) { endOnCarriageReturn = true; sb.append(line).append("\n"); } else { sb.append(line).append("\n"); } } } if (threadDump == null) { LogUtils.debugf(this, "No thread dump was found."); } else { fw.append(threadDump); map.put("ThreadDump.txt", new FileSystemResource(threadDumpFile)); } } catch (final Exception e) { LogUtils.debugf(this, e, "Unable to read from '%s'", outputLog); } finally { IOUtils.closeQuietly(fw); IOUtils.closeQuietly(bfr); IOUtils.closeQuietly(fr); } } else { LogUtils.warnf(this, "could not find output.log in '%s'", outputLog); } return map; } private void triggerThreadDump() { String kill = findBinary("kill"); if (kill != null) { for (final Integer pid : getOpenNMSProcesses()) { LogUtils.debugf(this, "pid = " + pid); CommandLine command = CommandLine.parse(kill + " -3 " + pid.toString()); try { LogUtils.tracef(this, "running '%s'", command.toString()); DefaultExecutor executor = new DefaultExecutor(); executor.setWatchdog(new ExecuteWatchdog(5000)); int exitValue = executor.execute(command); LogUtils.tracef(this, "finished '%s'", command.toString()); if (exitValue != 0) { LogUtils.warnf(this, "'%s' exited non-zero: %d", command.toString(), exitValue); } } catch (final Exception e) { LogUtils.warnf(this, e, "Unable to run kill -3 on '%s': you might need to run system-report as root.", pid.toString()); } } } } }