8154985: Add the ability to use main class as lookup (as jcmd) to jinfo, jmap, jstack
Reviewed-by: sla, dsamersoff
This commit is contained in:
parent
ae4d032d41
commit
d0b67fecb3
jdk/src/jdk.jcmd/share/classes/sun/tools
common
jcmd
jinfo
jmap
jstack
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 sun.tools.common;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
import com.sun.tools.attach.VirtualMachineDescriptor;
|
||||
|
||||
import sun.jvmstat.monitor.MonitorException;
|
||||
import sun.jvmstat.monitor.MonitoredHost;
|
||||
import sun.jvmstat.monitor.MonitoredVm;
|
||||
import sun.jvmstat.monitor.MonitoredVmUtil;
|
||||
import sun.jvmstat.monitor.VmIdentifier;
|
||||
|
||||
/**
|
||||
* Class for finding process matching a process argument,
|
||||
* excluding tool it self and returning a list containing
|
||||
* the process identifiers.
|
||||
*/
|
||||
public class ProcessArgumentMatcher {
|
||||
private String excludeCls;
|
||||
private String matchClass = null;
|
||||
private String singlePid = null;
|
||||
private boolean matchAll = false;
|
||||
|
||||
public ProcessArgumentMatcher(String pidArg, Class<?> excludeClass) {
|
||||
excludeCls = excludeClass.getName();
|
||||
if (pidArg == null || pidArg.isEmpty()) {
|
||||
throw new IllegalArgumentException("Pid string is invalid");
|
||||
}
|
||||
if (pidArg.charAt(0) == '-') {
|
||||
throw new IllegalArgumentException("Unrecognized " + pidArg);
|
||||
}
|
||||
try {
|
||||
long pid = Long.parseLong(pidArg);
|
||||
if (pid == 0) {
|
||||
matchAll = true;
|
||||
} else {
|
||||
singlePid = String.valueOf(pid);
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
matchClass = pidArg;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean check(VirtualMachineDescriptor vmd) {
|
||||
String mainClass = null;
|
||||
try {
|
||||
VmIdentifier vmId = new VmIdentifier(vmd.id());
|
||||
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
|
||||
MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1);
|
||||
mainClass = MonitoredVmUtil.mainClass(monitoredVm, true);
|
||||
monitoredHost.detach(monitoredVm);
|
||||
} catch (NullPointerException npe) {
|
||||
// There is a potential race, where a running java app is being
|
||||
// queried, unfortunately the java app has shutdown after this
|
||||
// method is started but before getMonitoredVM is called.
|
||||
// If this is the case, then the /tmp/hsperfdata_xxx/pid file
|
||||
// will have disappeared and we will get a NullPointerException.
|
||||
// Handle this gracefully....
|
||||
return false;
|
||||
} catch (MonitorException | URISyntaxException e) {
|
||||
if (e.getMessage() != null) {
|
||||
System.err.println(e.getMessage());
|
||||
} else {
|
||||
Throwable cause = e.getCause();
|
||||
if ((cause != null) && (cause.getMessage() != null)) {
|
||||
System.err.println(cause.getMessage());
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mainClass.equals(excludeCls)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (matchAll || mainClass.indexOf(matchClass) != -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Collection<String> getPids() {
|
||||
Collection<String> pids = new ArrayList<>();
|
||||
if (singlePid != null) {
|
||||
pids.add(singlePid);
|
||||
return pids;
|
||||
}
|
||||
List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
|
||||
for (VirtualMachineDescriptor vmd : vmds) {
|
||||
if (check(vmd)) {
|
||||
pids.add(vmd.id());
|
||||
}
|
||||
}
|
||||
return pids;
|
||||
}
|
||||
}
|
@ -33,16 +33,14 @@ class Arguments {
|
||||
private boolean listProcesses = false;
|
||||
private boolean listCounters = false;
|
||||
private boolean showUsage = false;
|
||||
private int pid = -1;
|
||||
private String command = null;
|
||||
private String processSubstring;
|
||||
private String processString = null;
|
||||
|
||||
public boolean isListProcesses() { return listProcesses; }
|
||||
public boolean isListCounters() { return listCounters; }
|
||||
public boolean isShowUsage() { return showUsage; }
|
||||
public int getPid() { return pid; }
|
||||
public String getCommand() { return command; }
|
||||
public String getProcessSubstring() { return processSubstring; }
|
||||
public String getProcessString() { return processString; }
|
||||
|
||||
public Arguments(String[] args) {
|
||||
if (args.length == 0 || args[0].equals("-l")) {
|
||||
@ -55,15 +53,7 @@ class Arguments {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
pid = Integer.parseInt(args[0]);
|
||||
} catch (NumberFormatException ex) {
|
||||
// use as a partial class-name instead
|
||||
if (args[0].charAt(0) != '-') {
|
||||
// unless it starts with a '-'
|
||||
processSubstring = args[0];
|
||||
}
|
||||
}
|
||||
processString = args[0];
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 1; i < args.length; i++) {
|
||||
|
@ -29,22 +29,22 @@ import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import com.sun.tools.attach.AttachOperationFailedException;
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
import com.sun.tools.attach.VirtualMachineDescriptor;
|
||||
import com.sun.tools.attach.AgentLoadException;
|
||||
import com.sun.tools.attach.AttachNotSupportedException;
|
||||
|
||||
import sun.tools.attach.HotSpotVirtualMachine;
|
||||
import sun.tools.common.ProcessArgumentMatcher;
|
||||
import sun.tools.jstat.JStatLogger;
|
||||
import sun.jvmstat.monitor.Monitor;
|
||||
import sun.jvmstat.monitor.MonitoredHost;
|
||||
import sun.jvmstat.monitor.MonitoredVm;
|
||||
import sun.jvmstat.monitor.MonitoredVmUtil;
|
||||
import sun.jvmstat.monitor.MonitorException;
|
||||
import sun.jvmstat.monitor.VmIdentifier;
|
||||
|
||||
@ -73,52 +73,18 @@ public class JCmd {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
List<String> pids = new ArrayList<String>();
|
||||
if (arg.getPid() == 0) {
|
||||
// find all VMs
|
||||
List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
|
||||
for (VirtualMachineDescriptor vmd : vmds) {
|
||||
if (!isJCmdProcess(vmd)) {
|
||||
pids.add(vmd.id());
|
||||
}
|
||||
}
|
||||
} else if (arg.getProcessSubstring() != null) {
|
||||
// use the partial class-name match
|
||||
List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
|
||||
for (VirtualMachineDescriptor vmd : vmds) {
|
||||
if (isJCmdProcess(vmd)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
String mainClass = getMainClass(vmd);
|
||||
if (mainClass != null
|
||||
&& mainClass.indexOf(arg.getProcessSubstring()) != -1) {
|
||||
pids.add(vmd.id());
|
||||
}
|
||||
} catch (MonitorException|URISyntaxException e) {
|
||||
if (e.getMessage() != null) {
|
||||
System.err.println(e.getMessage());
|
||||
} else {
|
||||
Throwable cause = e.getCause();
|
||||
if ((cause != null) && (cause.getMessage() != null)) {
|
||||
System.err.println(cause.getMessage());
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pids.isEmpty()) {
|
||||
System.err.println("Could not find any processes matching : '"
|
||||
+ arg.getProcessSubstring() + "'");
|
||||
System.exit(1);
|
||||
}
|
||||
} else if (arg.getPid() == -1) {
|
||||
Collection<String> pids = Collections.emptyList();
|
||||
try {
|
||||
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(arg.getProcessString(), JCmd.class);
|
||||
pids = ap.getPids();
|
||||
} catch (IllegalArgumentException iae) {
|
||||
System.err.println("Invalid pid specified");
|
||||
System.exit(1);
|
||||
} else {
|
||||
// Use the found pid
|
||||
pids.add(arg.getPid() + "");
|
||||
}
|
||||
if (pids.isEmpty()) {
|
||||
System.err.println("Could not find any processes matching : '"
|
||||
+ arg.getProcessString() + "'");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
boolean success = true;
|
||||
@ -199,36 +165,6 @@ public class JCmd {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isJCmdProcess(VirtualMachineDescriptor vmd) {
|
||||
try {
|
||||
String mainClass = getMainClass(vmd);
|
||||
return mainClass != null && mainClass.equals(JCmd.class.getName());
|
||||
} catch (URISyntaxException|MonitorException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getMainClass(VirtualMachineDescriptor vmd)
|
||||
throws URISyntaxException, MonitorException {
|
||||
try {
|
||||
String mainClass = null;
|
||||
VmIdentifier vmId = new VmIdentifier(vmd.id());
|
||||
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
|
||||
MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1);
|
||||
mainClass = MonitoredVmUtil.mainClass(monitoredVm, true);
|
||||
monitoredHost.detach(monitoredVm);
|
||||
return mainClass;
|
||||
} catch(NullPointerException e) {
|
||||
// There is a potential race, where a running java app is being
|
||||
// queried, unfortunately the java app has shutdown after this
|
||||
// method is started but before getMonitoredVM is called.
|
||||
// If this is the case, then the /tmp/hsperfdata_xxx/pid file
|
||||
// will have disappeared and we will get a NullPointerException.
|
||||
// Handle this gracefully....
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to compare two Monitor objects by name in ascending order.
|
||||
* (from jstat)
|
||||
|
@ -25,13 +25,14 @@
|
||||
|
||||
package sun.tools.jinfo;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
|
||||
import sun.tools.attach.HotSpotVirtualMachine;
|
||||
import sun.tools.common.ProcessArgumentMatcher;
|
||||
|
||||
/*
|
||||
* This class is the main class for the JInfo utility. It parses its arguments
|
||||
@ -82,28 +83,49 @@ final public class JInfo {
|
||||
|
||||
// Next we check the parameter count. -flag allows extra parameters
|
||||
int paramCount = args.length - optionCount;
|
||||
if ((doFlag && paramCount != 2) || (paramCount != 1)) {
|
||||
if ((doFlag && paramCount != 2) || ((!doFlag && paramCount != 1))) {
|
||||
usage(1);
|
||||
}
|
||||
|
||||
if (!doFlag && !doFlags && !doSysprops) {
|
||||
// Print flags and sysporps if no options given
|
||||
sysprops(args[optionCount]);
|
||||
System.out.println();
|
||||
flags(args[optionCount]);
|
||||
System.out.println();
|
||||
commandLine(args[optionCount]);
|
||||
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class);
|
||||
Collection<String> pids = ap.getPids();
|
||||
for (String pid : pids) {
|
||||
if (pids.size() > 1) {
|
||||
System.out.println("Pid:" + pid);
|
||||
}
|
||||
sysprops(pid);
|
||||
System.out.println();
|
||||
flags(pid);
|
||||
System.out.println();
|
||||
commandLine(pid);
|
||||
}
|
||||
}
|
||||
|
||||
if (doFlag) {
|
||||
flag(args[optionCount+1], args[optionCount]);
|
||||
}
|
||||
else {
|
||||
if (doFlags) {
|
||||
flags(args[optionCount]);
|
||||
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount+1], JInfo.class);
|
||||
Collection<String> pids = ap.getPids();
|
||||
for (String pid : pids) {
|
||||
if (pids.size() > 1) {
|
||||
System.out.println("Pid:" + pid);
|
||||
}
|
||||
flag(pid, args[optionCount]);
|
||||
}
|
||||
else if (doSysprops) {
|
||||
sysprops(args[optionCount]);
|
||||
}
|
||||
else if (doFlags || doSysprops) {
|
||||
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class);
|
||||
Collection<String> pids = ap.getPids();
|
||||
for (String pid : pids) {
|
||||
if (pids.size() > 1) {
|
||||
System.out.println("Pid:" + pid);
|
||||
}
|
||||
if (doFlags) {
|
||||
flags(pid);
|
||||
}
|
||||
else if (doSysprops) {
|
||||
sysprops(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -193,24 +215,23 @@ final public class JInfo {
|
||||
private static void checkForUnsupportedOptions(String[] args) {
|
||||
// Check arguments for -F, and non-numeric value
|
||||
// and warn the user that SA is not supported anymore
|
||||
|
||||
int maxCount = 1;
|
||||
int paramCount = 0;
|
||||
|
||||
for (String s : args) {
|
||||
if (s.equals("-F")) {
|
||||
SAOptionError("-F option used");
|
||||
}
|
||||
|
||||
if (s.equals("-flag")) {
|
||||
maxCount = 2;
|
||||
}
|
||||
if (! s.startsWith("-")) {
|
||||
if (! s.matches("[0-9]+")) {
|
||||
SAOptionError("non PID argument");
|
||||
}
|
||||
paramCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (paramCount > 1) {
|
||||
SAOptionError("More than one non-option argument");
|
||||
if (paramCount > maxCount) {
|
||||
SAOptionError("More than " + maxCount + " non-option argument");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,10 +29,12 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
import com.sun.tools.attach.AttachNotSupportedException;
|
||||
import sun.tools.attach.HotSpotVirtualMachine;
|
||||
import sun.tools.common.ProcessArgumentMatcher;
|
||||
|
||||
/*
|
||||
* This class is the main class for the JMap utility. It parses its arguments
|
||||
@ -83,22 +85,29 @@ public class JMap {
|
||||
usage(1);
|
||||
}
|
||||
|
||||
String pid = args[1];
|
||||
String pidArg = args[1];
|
||||
// Here we handle the built-in options
|
||||
// As more options are added we should create an abstract tool class and
|
||||
// have a table to map the options
|
||||
if (option.equals("-histo")) {
|
||||
histo(pid, "");
|
||||
} else if (option.startsWith("-histo:")) {
|
||||
histo(pid, option.substring("-histo:".length()));
|
||||
} else if (option.startsWith("-dump:")) {
|
||||
dump(pid, option.substring("-dump:".length()));
|
||||
} else if (option.equals("-finalizerinfo")) {
|
||||
executeCommandForPid(pid, "jcmd", "GC.finalizer_info");
|
||||
} else if (option.equals("-clstats")) {
|
||||
executeCommandForPid(pid, "jcmd", "GC.class_stats");
|
||||
} else {
|
||||
usage(1);
|
||||
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg, JMap.class);
|
||||
Collection<String> pids = ap.getPids();
|
||||
for (String pid : pids) {
|
||||
if (pids.size() > 1) {
|
||||
System.out.println("Pid:" + pid);
|
||||
}
|
||||
if (option.equals("-histo")) {
|
||||
histo(pid, "");
|
||||
} else if (option.startsWith("-histo:")) {
|
||||
histo(pid, option.substring("-histo:".length()));
|
||||
} else if (option.startsWith("-dump:")) {
|
||||
dump(pid, option.substring("-dump:".length()));
|
||||
} else if (option.equals("-finalizerinfo")) {
|
||||
executeCommandForPid(pid, "jcmd", "GC.finalizer_info");
|
||||
} else if (option.equals("-clstats")) {
|
||||
executeCommandForPid(pid, "jcmd", "GC.class_stats");
|
||||
} else {
|
||||
usage(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,9 +213,6 @@ public class JMap {
|
||||
*/
|
||||
|
||||
if (! s.startsWith("-")) {
|
||||
if (! s.matches("[0-9]+")) {
|
||||
SAOptionError("non PID argument");
|
||||
}
|
||||
paramCount += 1;
|
||||
}
|
||||
}
|
||||
|
@ -26,10 +26,11 @@
|
||||
package sun.tools.jstack;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
import com.sun.tools.attach.AttachNotSupportedException;
|
||||
import sun.tools.attach.HotSpotVirtualMachine;
|
||||
import sun.tools.common.ProcessArgumentMatcher;
|
||||
|
||||
/*
|
||||
* This class is the main class for the JStack utility. It parses its arguments
|
||||
@ -74,14 +75,21 @@ public class JStack {
|
||||
}
|
||||
|
||||
// pass -l to thread dump operation to get extra lock info
|
||||
String pid = args[optionCount];
|
||||
String pidArg = args[optionCount];
|
||||
String params[];
|
||||
if (locks) {
|
||||
params = new String[] { "-l" };
|
||||
} else {
|
||||
params = new String[0];
|
||||
}
|
||||
runThreadDump(pid, params);
|
||||
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg, JStack.class);
|
||||
Collection<String> pids = ap.getPids();
|
||||
for (String pid : pids) {
|
||||
if (pids.size() > 1) {
|
||||
System.out.println("Pid:" + pid);
|
||||
}
|
||||
runThreadDump(pid, params);
|
||||
}
|
||||
}
|
||||
|
||||
// Attach to pid and perform a thread dump
|
||||
@ -133,9 +141,6 @@ public class JStack {
|
||||
}
|
||||
|
||||
if (! s.startsWith("-")) {
|
||||
if (! s.matches("[0-9]+")) {
|
||||
SAOptionError("non PID argument");
|
||||
}
|
||||
paramCount += 1;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user