/**
* jvmtop - java monitoring for the command-line
*
* Copyright (C) 2013 by Patric Rufflar. 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 program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package com.jvmtop;
import java.io.BufferedOutputStream;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.management.ManagementFactory;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import com.jvmtop.view.ConsoleView;
import com.jvmtop.view.VMDetailView;
import com.jvmtop.view.VMOverviewView;
import com.jvmtop.view.VMProfileView;
/**
* JvmTop entry point class.
*
* - parses program arguments
* - selects console view
* - prints header
* - main "iteration loop"
*
* TODO: refactor to split these tasks
*
* @author paru
*
*/
public class JvmTop
{
public static final String VERSION = "0.8.0 alpha";
private Double delay_ = 1.0;
private Boolean supportsSystemAverage_;
private java.lang.management.OperatingSystemMXBean localOSBean_;
private final static String CLEAR_TERMINAL_ANSI_CMD = new String(
new byte[] {
(byte) 0x1b, (byte) 0x5b, (byte) 0x32, (byte) 0x4a, (byte) 0x1b,
(byte) 0x5b, (byte) 0x48 });
private int maxIterations_ = -1;
private static Logger logger;
private static OptionParser createOptionParser()
{
OptionParser parser = new OptionParser();
parser.acceptsAll(Arrays.asList(new String[] { "help", "?", "h" }),
"shows this help").forHelp();
parser
.accepts("once",
"jvmtop will exit after first output iteration [deprecated, use -n 1 instead]");
parser
.acceptsAll(Arrays.asList(new String[] { "n", "iteration" }),
"jvmtop will exit after n output iterations").withRequiredArg()
.ofType(Integer.class);
parser
.acceptsAll(Arrays.asList(new String[] { "d", "delay" }),
"delay between each output iteration").withRequiredArg()
.ofType(Double.class);
parser.accepts("profile", "start CPU profiling at the specified jvm");
parser.accepts("sysinfo", "outputs diagnostic information");
parser.accepts("verbose", "verbose mode");
parser.accepts("threadlimit",
"sets the number of displayed threads in detail mode")
.withRequiredArg().ofType(Integer.class);
parser
.accepts("disable-threadlimit", "displays all threads in detail mode");
parser
.acceptsAll(Arrays.asList(new String[] { "p", "pid" }),
"PID to connect to").withRequiredArg().ofType(Integer.class);
parser
.acceptsAll(Arrays.asList(new String[] { "w", "width" }),
"Width in columns for the console display").withRequiredArg().ofType(Integer.class);
parser
.accepts("threadnamewidth",
"sets displayed thread name length in detail mode (defaults to 30)")
.withRequiredArg().ofType(Integer.class);
return parser;
}
public static void main(String[] args) throws Exception
{
Locale.setDefault(Locale.US);
logger = Logger.getLogger("jvmtop");
OptionParser parser = createOptionParser();
OptionSet a = parser.parse(args);
if (a.has("help"))
{
System.out.println("jvmtop - java monitoring for the command-line");
System.out.println("Usage: jvmtop.sh [options...] [PID]");
System.out.println("");
parser.printHelpOn(System.out);
System.exit(0);
}
boolean sysInfoOption = a.has("sysinfo");
Integer pid = null;
Integer width = null;
double delay = 1.0;
boolean profileMode = a.has("profile");
Integer iterations = a.has("once") ? 1 : -1;
Integer threadlimit = null;
boolean threadLimitEnabled = true;
Integer threadNameWidth = null;
if (a.hasArgument("delay"))
{
delay = (Double) (a.valueOf("delay"));
if (delay < 0.1d)
{
throw new IllegalArgumentException("Delay cannot be set below 0.1");
}
}
if (a.hasArgument("n"))
{
iterations = (Integer) a.valueOf("n");
}
//to support PID as non option argument
if (a.nonOptionArguments().size() > 0)
{
pid = Integer.valueOf((String) a.nonOptionArguments().get(0));
}
if (a.hasArgument("pid"))
{
pid = (Integer) a.valueOf("pid");
}
if (a.hasArgument("width"))
{
width = (Integer) a.valueOf("width");
}
if (a.hasArgument("threadlimit"))
{
threadlimit = (Integer) a.valueOf("threadlimit");
}
if (a.has("disable-threadlimit"))
{
threadLimitEnabled = false;
}
if (a.has("verbose"))
{
fineLogging();
logger.setLevel(Level.ALL);
logger.fine("Verbosity mode.");
}
if (a.hasArgument("threadnamewidth"))
{
threadNameWidth = (Integer) a.valueOf("threadnamewidth");
}
if (sysInfoOption)
{
outputSystemProps();
}
else
{
JvmTop jvmTop = new JvmTop();
jvmTop.setDelay(delay);
jvmTop.setMaxIterations(iterations);
if (pid == null)
{
jvmTop.run(new VMOverviewView(width));
}
else
{
if (profileMode)
{
jvmTop.run(new VMProfileView(pid, width));
}
else
{
VMDetailView vmDetailView = new VMDetailView(pid, width);
vmDetailView.setDisplayedThreadLimit(threadLimitEnabled);
if (threadlimit != null)
{
vmDetailView.setNumberOfDisplayedThreads(threadlimit);
}
if (threadNameWidth != null)
{
vmDetailView.setThreadNameDisplayWidth(threadNameWidth);
}
jvmTop.run(vmDetailView);
}
}
}
}
public int getMaxIterations()
{
return maxIterations_;
}
public void setMaxIterations(int iterations)
{
maxIterations_ = iterations;
}
private static void fineLogging()
{
//get the top Logger:
Logger topLogger = java.util.logging.Logger.getLogger("");
// Handler for console (reuse it if it already exists)
Handler consoleHandler = null;
//see if there is already a console handler
for (Handler handler : topLogger.getHandlers())
{
if (handler instanceof ConsoleHandler)
{
//found the console handler
consoleHandler = handler;
break;
}
}
if (consoleHandler == null)
{
//there was no console handler found, create a new one
consoleHandler = new ConsoleHandler();
topLogger.addHandler(consoleHandler);
}
//set the console handler to fine:
consoleHandler.setLevel(java.util.logging.Level.FINEST);
}
private static void outputSystemProps()
{
for (Object key : System.getProperties().keySet())
{
System.out.println(key + "=" + System.getProperty(key + ""));
}
}
protected void run(ConsoleView view) throws Exception
{
try
{
System.setOut(new PrintStream(new BufferedOutputStream(
new FileOutputStream(FileDescriptor.out)), false));
int iterations = 0;
while (!view.shouldExit())
{
if (maxIterations_ > 1 || maxIterations_ == -1)
{
clearTerminal();
}
printTopBar();
view.printView();
System.out.flush();
iterations++;
if (iterations >= maxIterations_ && maxIterations_ > 0)
{
break;
}
view.sleep((int) (delay_ * 1000));
}
}
catch (NoClassDefFoundError e)
{
e.printStackTrace(System.err);
System.err.println("");
System.err.println("ERROR: Some JDK classes cannot be found.");
System.err
.println(" Please check if the JAVA_HOME environment variable has been set to a JDK path.");
System.err.println("");
}
}
/**
*
*/
private void clearTerminal()
{
if (System.getProperty("os.name").contains("Windows"))
{
//hack
System.out
.printf("%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n");
}
else if (System.getProperty("jvmtop.altClear") != null)
{
System.out.print('\f');
}
else
{
System.out.print(CLEAR_TERMINAL_ANSI_CMD);
}
}
public JvmTop()
{
localOSBean_ = ManagementFactory.getOperatingSystemMXBean();
}
/**
* @throws NoSuchMethodException
* @throws SecurityException
*
*/
private void printTopBar()
{
System.out.printf(" JvmTop %s - %8tT, %6s, %2d cpus, %15.15s", VERSION,
new Date(), localOSBean_.getArch(),
localOSBean_.getAvailableProcessors(), localOSBean_.getName() + " "
+ localOSBean_.getVersion());
if (supportSystemLoadAverage() && localOSBean_.getSystemLoadAverage() != -1)
{
System.out.printf(", load avg %3.2f%n",
localOSBean_.getSystemLoadAverage());
}
else
{
System.out.println();
}
System.out.println(" https://github.com/patric-r/jvmtop");
System.out.println();
}
private boolean supportSystemLoadAverage()
{
if (supportsSystemAverage_ == null)
{
try
{
supportsSystemAverage_ = (localOSBean_.getClass().getMethod(
"getSystemLoadAverage") != null);
}
catch (Throwable e)
{
supportsSystemAverage_ = false;
}
}
return supportsSystemAverage_;
}
public Double getDelay()
{
return delay_;
}
public void setDelay(Double delay)
{
delay_ = delay;
}
}