mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
add mbean command (#666)
This commit is contained in:
@@ -26,6 +26,7 @@ import com.taobao.arthas.core.command.klass100.SearchClassCommand;
|
||||
import com.taobao.arthas.core.command.klass100.SearchMethodCommand;
|
||||
import com.taobao.arthas.core.command.monitor200.DashboardCommand;
|
||||
import com.taobao.arthas.core.command.monitor200.JvmCommand;
|
||||
import com.taobao.arthas.core.command.monitor200.MBeanCommand;
|
||||
import com.taobao.arthas.core.command.monitor200.MonitorCommand;
|
||||
import com.taobao.arthas.core.command.monitor200.StackCommand;
|
||||
import com.taobao.arthas.core.command.monitor200.ThreadCommand;
|
||||
@@ -89,5 +90,6 @@ public class BuiltinCommandPack implements CommandResolver {
|
||||
commands.add(Command.create(HistoryCommand.class));
|
||||
commands.add(Command.create(CatCommand.class));
|
||||
commands.add(Command.create(PwdCommand.class));
|
||||
commands.add(Command.create(MBeanCommand.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ public class DashboardCommand extends AnnotatedCommand {
|
||||
return RenderUtil.render(table, width, height);
|
||||
}
|
||||
|
||||
String drawRuntineInfoAndTomcatInfo(int width, int height) {
|
||||
String drawRuntimeInfoAndTomcatInfo(int width, int height) {
|
||||
TableElement table = new TableElement(1, 1);
|
||||
|
||||
TableElement runtimeInfoTable = new TableElement(1, 1).rightCellPadding(1);
|
||||
@@ -405,7 +405,7 @@ public class DashboardCommand extends AnnotatedCommand {
|
||||
|
||||
String threadInfo = drawThreadInfo(width, threadTopHeight);
|
||||
String memoryAndGc = drawMemoryInfoAndGcInfo(width, runtimeInfoHeight);
|
||||
String runTimeAndTomcat = drawRuntineInfoAndTomcatInfo(width, heapInfoHeight);
|
||||
String runTimeAndTomcat = drawRuntimeInfoAndTomcatInfo(width, heapInfoHeight);
|
||||
|
||||
process.write(threadInfo + memoryAndGc + runTimeAndTomcat);
|
||||
|
||||
|
||||
@@ -0,0 +1,520 @@
|
||||
package com.taobao.arthas.core.command.monitor200;
|
||||
|
||||
import com.taobao.arthas.core.command.Constants;
|
||||
import com.taobao.arthas.core.shell.cli.CliToken;
|
||||
import com.taobao.arthas.core.shell.cli.Completion;
|
||||
import com.taobao.arthas.core.shell.cli.CompletionUtils;
|
||||
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
|
||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||
import com.taobao.arthas.core.shell.handlers.Handler;
|
||||
import com.taobao.arthas.core.shell.handlers.command.CommandInterruptHandler;
|
||||
import com.taobao.arthas.core.shell.handlers.shell.QExitHandler;
|
||||
import com.taobao.arthas.core.shell.session.Session;
|
||||
import com.taobao.arthas.core.util.LogUtil;
|
||||
import com.taobao.arthas.core.util.StringUtils;
|
||||
import com.taobao.arthas.core.util.TokenUtils;
|
||||
import com.taobao.arthas.core.util.matcher.Matcher;
|
||||
import com.taobao.arthas.core.util.matcher.RegexMatcher;
|
||||
import com.taobao.arthas.core.util.matcher.WildcardMatcher;
|
||||
import com.taobao.middleware.cli.annotations.Argument;
|
||||
import com.taobao.middleware.cli.annotations.Description;
|
||||
import com.taobao.middleware.cli.annotations.Name;
|
||||
import com.taobao.middleware.cli.annotations.Option;
|
||||
import com.taobao.middleware.cli.annotations.Summary;
|
||||
import com.taobao.middleware.logger.Logger;
|
||||
import com.taobao.text.Color;
|
||||
import com.taobao.text.Decoration;
|
||||
import com.taobao.text.ui.LabelElement;
|
||||
import com.taobao.text.ui.TableElement;
|
||||
import com.taobao.text.util.RenderUtil;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.DescriptorRead;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import static com.taobao.text.ui.Element.label;
|
||||
import static javax.management.MBeanOperationInfo.ACTION;
|
||||
import static javax.management.MBeanOperationInfo.ACTION_INFO;
|
||||
import static javax.management.MBeanOperationInfo.INFO;
|
||||
import static javax.management.MBeanOperationInfo.UNKNOWN;
|
||||
|
||||
/**
|
||||
* Date: 2019/4/18
|
||||
*
|
||||
* @author xuzhiyi
|
||||
*/
|
||||
@Name("mbean")
|
||||
@Summary("Display the mbean information")
|
||||
@Description("\nExamples:\n" +
|
||||
" mbean\n" +
|
||||
" mbean -m java.lang:type=Threading\n" +
|
||||
" mbean java.lang:type=Threading\n" +
|
||||
" mbean java.lang:type=Threading *Count\n" +
|
||||
" mbean -E java.lang:type=Threading PeakThreadCount|ThreadCount|DaemonThreadCount\n" +
|
||||
" mbean -i 1000 java.lang:type=Threading *Count\n" +
|
||||
Constants.WIKI + Constants.WIKI_HOME + "mbean")
|
||||
public class MBeanCommand extends AnnotatedCommand {
|
||||
|
||||
private static final Logger logger = LogUtil.getArthasLogger();
|
||||
|
||||
private String name;
|
||||
private String attribute;
|
||||
private boolean isRegEx = false;
|
||||
private long interval = 0;
|
||||
private boolean metaData;
|
||||
private int numOfExecutions = 100;
|
||||
private Timer timer;
|
||||
private long count = 0;
|
||||
|
||||
@Argument(argName = "name-pattern", index = 0, required = false)
|
||||
@Description("ObjectName pattern, see javax.management.ObjectName for more detail.")
|
||||
public void setNamePattern(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Argument(argName = "attribute-pattern", index = 1, required = false)
|
||||
@Description("Attribute name pattern.")
|
||||
public void setAttributePattern(String attribute) {
|
||||
this.attribute = attribute;
|
||||
}
|
||||
|
||||
@Option(shortName = "i", longName = "interval")
|
||||
@Description("The interval (in ms) between two executions.")
|
||||
public void setInterval(long interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
@Option(shortName = "E", longName = "regex", flag = true)
|
||||
@Description("Enable regular expression to match attribute name (wildcard matching by default).")
|
||||
public void setRegEx(boolean regEx) {
|
||||
isRegEx = regEx;
|
||||
}
|
||||
|
||||
@Option(shortName = "m", longName = "metadata", flag = false)
|
||||
@Description("Show metadata of mbean.")
|
||||
public void setMetaData(boolean metaData) {
|
||||
this.metaData = metaData;
|
||||
}
|
||||
|
||||
@Option(shortName = "n", longName = "number-of-execution")
|
||||
@Description("The number of times this command will be executed.")
|
||||
public void setNumOfExecutions(int numOfExecutions) {
|
||||
this.numOfExecutions = numOfExecutions;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isRegEx() {
|
||||
return isRegEx;
|
||||
}
|
||||
|
||||
public boolean isMetaData() {
|
||||
return metaData;
|
||||
}
|
||||
|
||||
public long getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
public int getNumOfExecutions() {
|
||||
return numOfExecutions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(CommandProcess process) {
|
||||
if (StringUtils.isEmpty(getName())) {
|
||||
listMBean(process);
|
||||
} else if (isMetaData()) {
|
||||
listMetaData(process);
|
||||
} else {
|
||||
listAttribute(process);
|
||||
}
|
||||
}
|
||||
|
||||
private void listMBean(CommandProcess process) {
|
||||
Set<ObjectName> objectNames = queryObjectNames();
|
||||
for (ObjectName objectName : objectNames) {
|
||||
process.write(objectName.toString());
|
||||
process.write("\n");
|
||||
}
|
||||
process.end();
|
||||
}
|
||||
|
||||
private void listAttribute(final CommandProcess process) {
|
||||
Session session = process.session();
|
||||
timer = new Timer("Timer-for-arthas-mbean-" + session.getSessionId(), true);
|
||||
|
||||
// ctrl-C support
|
||||
process.interruptHandler(new MBeanInterruptHandler(process, timer));
|
||||
|
||||
// 通过handle回调,在suspend和end时停止timer,resume时重启timer
|
||||
Handler<Void> stopHandler = new Handler<Void>() {
|
||||
@Override
|
||||
public void handle(Void event) {
|
||||
stop();
|
||||
}
|
||||
};
|
||||
|
||||
Handler<Void> restartHandler = new Handler<Void>() {
|
||||
@Override
|
||||
public void handle(Void event) {
|
||||
restart(process);
|
||||
}
|
||||
};
|
||||
process.suspendHandler(stopHandler);
|
||||
process.resumeHandler(restartHandler);
|
||||
process.endHandler(stopHandler);
|
||||
// q exit support
|
||||
process.stdinHandler(new QExitHandler(process));
|
||||
|
||||
// start the timer
|
||||
if (getInterval() > 0) {
|
||||
timer.scheduleAtFixedRate(new MBeanTimerTask(process), 0, getInterval());
|
||||
} else {
|
||||
timer.schedule(new MBeanTimerTask(process), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void restart(CommandProcess process) {
|
||||
if (timer == null) {
|
||||
Session session = process.session();
|
||||
timer = new Timer("Timer-for-arthas-mbean-" + session.getSessionId(), true);
|
||||
timer.scheduleAtFixedRate(new MBeanTimerTask(process), 0, getInterval());
|
||||
}
|
||||
}
|
||||
|
||||
private void listMetaData(CommandProcess process) {
|
||||
Set<ObjectName> objectNames = queryObjectNames();
|
||||
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
try {
|
||||
TableElement table = createTable();
|
||||
for (ObjectName objectName : objectNames) {
|
||||
MBeanInfo mBeanInfo = mBeanServer.getMBeanInfo(objectName);
|
||||
drawMetaInfo(mBeanInfo, objectName, table);
|
||||
drawAttributeInfo(mBeanInfo.getAttributes(), table);
|
||||
drawOperationInfo(mBeanInfo.getOperations(), table);
|
||||
drawNotificationInfo(mBeanInfo.getNotifications(), table);
|
||||
}
|
||||
process.write(RenderUtil.render(table, process.width()));
|
||||
} catch (Throwable e) {
|
||||
logger.warn("listMetaData error", e);
|
||||
} finally {
|
||||
process.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete(Completion completion) {
|
||||
int argumentIndex = CompletionUtils.detectArgumentIndex(completion);
|
||||
if (argumentIndex == 1) {
|
||||
if (!completeBeanName(completion)) {
|
||||
super.complete(completion);
|
||||
}
|
||||
return;
|
||||
} else if (argumentIndex == 2) {
|
||||
if (!completeAttributeName(completion)) {
|
||||
super.complete(completion);
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.complete(completion);
|
||||
}
|
||||
|
||||
private boolean completeBeanName(Completion completion) {
|
||||
List<CliToken> tokens = completion.lineTokens();
|
||||
String lastToken = TokenUtils.getLast(tokens).value();
|
||||
|
||||
if (StringUtils.isBlank(lastToken)) {
|
||||
lastToken = "";
|
||||
}
|
||||
|
||||
if (lastToken.startsWith("-") || lastToken.startsWith("--")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<ObjectName> objectNames = queryObjectNames();
|
||||
Set<String> names = new HashSet<String>();
|
||||
|
||||
if (objectNames == null) {
|
||||
return false;
|
||||
}
|
||||
for (ObjectName objectName : objectNames) {
|
||||
String name = objectName.toString();
|
||||
if (name.startsWith(lastToken)) {
|
||||
int index = name.indexOf('.', lastToken.length());
|
||||
if (index > 0) {
|
||||
names.add(name.substring(0, index + 1));
|
||||
continue;
|
||||
}
|
||||
index = name.indexOf(':', lastToken.length());
|
||||
if (index > 0) {
|
||||
names.add(name.substring(0, index + 1));
|
||||
continue;
|
||||
}
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
String next = names.iterator().next();
|
||||
if (names.size() == 1 && (next.endsWith(".") || next.endsWith(":"))) {
|
||||
completion.complete(next.substring(lastToken.length()), false);
|
||||
return true;
|
||||
} else {
|
||||
return CompletionUtils.complete(completion, names);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean completeAttributeName(Completion completion) {
|
||||
List<CliToken> tokens = completion.lineTokens();
|
||||
String lastToken = TokenUtils.getLast(tokens).value();
|
||||
|
||||
if (StringUtils.isBlank(lastToken)) {
|
||||
lastToken = "";
|
||||
}
|
||||
|
||||
MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
String beanName = TokenUtils.retrievePreviousArg(tokens, lastToken);
|
||||
Set<ObjectName> objectNames = null;
|
||||
try {
|
||||
objectNames = platformMBeanServer.queryNames(new ObjectName(beanName), null);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
logger.warn("queryNames error", e);
|
||||
}
|
||||
if (objectNames == null || objectNames.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
MBeanInfo mBeanInfo = platformMBeanServer.getMBeanInfo(objectNames.iterator().next());
|
||||
List<String> attributeNames = new ArrayList<String>();
|
||||
MBeanAttributeInfo[] attributes = mBeanInfo.getAttributes();
|
||||
for (MBeanAttributeInfo attribute : attributes) {
|
||||
if (StringUtils.isBlank(lastToken)) {
|
||||
attributeNames.add(attribute.getName());
|
||||
} else if (attribute.getName().startsWith(lastToken)) {
|
||||
attributeNames.add(attribute.getName());
|
||||
}
|
||||
}
|
||||
return CompletionUtils.complete(completion, attributeNames);
|
||||
} catch (Throwable e) {
|
||||
logger.warn("getMBeanInfo error", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Set<ObjectName> queryObjectNames() {
|
||||
MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
Set<ObjectName> objectNames = new HashSet<ObjectName>();
|
||||
try {
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
name = "*:*";
|
||||
}
|
||||
objectNames = platformMBeanServer.queryNames(new ObjectName(name), null);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
logger.warn("queryObjectNames error", e);
|
||||
}
|
||||
return objectNames;
|
||||
}
|
||||
|
||||
private Matcher<String> getAttributeMatcher() {
|
||||
if (StringUtils.isEmpty(attribute)) {
|
||||
attribute = isRegEx ? ".*" : "*";
|
||||
}
|
||||
return isRegEx ? new RegexMatcher(attribute) : new WildcardMatcher(attribute);
|
||||
}
|
||||
|
||||
private void drawMetaInfo(MBeanInfo mBeanInfo, ObjectName objectName, TableElement table) {
|
||||
table.row(new LabelElement("MBeanInfo").style(Decoration.bold.fg(Color.red)));
|
||||
table.row(new LabelElement("Info:").style(Decoration.bold.fg(Color.yellow)));
|
||||
table.row("ObjectName", objectName.toString());
|
||||
table.row("ClassName", mBeanInfo.getClassName());
|
||||
table.row("Description", mBeanInfo.getDescription());
|
||||
drawDescriptorInfo("Info Descriptor:", mBeanInfo, table);
|
||||
MBeanConstructorInfo[] constructors = mBeanInfo.getConstructors();
|
||||
if (constructors.length > 0) {
|
||||
for (int i = 0; i < constructors.length; i++) {
|
||||
table.row(new LabelElement("Constructor-" + i).style(Decoration.bold.fg(Color.yellow)));
|
||||
table.row("Name", constructors[i].getName());
|
||||
table.row("Description", constructors[i].getDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawAttributeInfo(MBeanAttributeInfo[] attributes, TableElement table) {
|
||||
for (MBeanAttributeInfo attribute : attributes) {
|
||||
table.row(new LabelElement("MBeanAttributeInfo").style(Decoration.bold.fg(Color.red)));
|
||||
table.row(new LabelElement("Attribute:").style(Decoration.bold.fg(Color.yellow)));
|
||||
table.row("Name", attribute.getName());
|
||||
table.row("Description", attribute.getDescription());
|
||||
table.row("Readable", String.valueOf(attribute.isReadable()));
|
||||
table.row("Writable", String.valueOf(attribute.isWritable()));
|
||||
table.row("Is", String.valueOf(attribute.isIs()));
|
||||
table.row("Type", attribute.getType());
|
||||
drawDescriptorInfo("Attribute Descriptor:", attribute, table);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawOperationInfo(MBeanOperationInfo[] operations, TableElement table) {
|
||||
for (MBeanOperationInfo operation : operations) {
|
||||
table.row(new LabelElement("MBeanOperationInfo").style(Decoration.bold.fg(Color.red)));
|
||||
table.row(new LabelElement("Operation:").style(Decoration.bold.fg(Color.yellow)));
|
||||
table.row("Name", operation.getName());
|
||||
table.row("Description", operation.getDescription());
|
||||
String impact = "";
|
||||
switch (operation.getImpact()) {
|
||||
case ACTION:
|
||||
impact = "action";
|
||||
break;
|
||||
case ACTION_INFO:
|
||||
impact = "action/info";
|
||||
break;
|
||||
case INFO:
|
||||
impact = "info";
|
||||
break;
|
||||
case UNKNOWN:
|
||||
impact = "unknown";
|
||||
break;
|
||||
}
|
||||
table.row("Impact", impact);
|
||||
table.row("ReturnType", operation.getReturnType());
|
||||
MBeanParameterInfo[] signature = operation.getSignature();
|
||||
if (signature.length > 0) {
|
||||
for (int i = 0; i < signature.length; i++) {
|
||||
table.row(new LabelElement("Parameter-" + i).style(Decoration.bold.fg(Color.yellow)));
|
||||
table.row("Name", signature[i].getName());
|
||||
table.row("Type", signature[i].getType());
|
||||
table.row("Description", signature[i].getDescription());
|
||||
}
|
||||
}
|
||||
drawDescriptorInfo("Operation Descriptor:", operation, table);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawNotificationInfo(MBeanNotificationInfo[] notificationInfos, TableElement table) {
|
||||
for (MBeanNotificationInfo notificationInfo : notificationInfos) {
|
||||
table.row(new LabelElement("MBeanNotificationInfo").style(Decoration.bold.fg(Color.red)));
|
||||
table.row(new LabelElement("Notification:").style(Decoration.bold.fg(Color.yellow)));
|
||||
table.row("Name", notificationInfo.getName());
|
||||
table.row("Description", notificationInfo.getDescription());
|
||||
table.row("NotifTypes", Arrays.toString(notificationInfo.getNotifTypes()));
|
||||
drawDescriptorInfo("Notification Descriptor:", notificationInfo, table);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawDescriptorInfo(String title, DescriptorRead descriptorRead, TableElement table) {
|
||||
Descriptor descriptor = descriptorRead.getDescriptor();
|
||||
String[] fieldNames = descriptor.getFieldNames();
|
||||
if (fieldNames.length > 0) {
|
||||
table.row(new LabelElement(title).style(Decoration.bold.fg(Color.yellow)));
|
||||
for (String fieldName : fieldNames) {
|
||||
Object fieldValue = descriptor.getFieldValue(fieldName);
|
||||
table.row(fieldName, fieldValue.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TableElement createTable() {
|
||||
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
|
||||
table.row(true, label("NAME").style(Decoration.bold.bold()),
|
||||
label("VALUE").style(Decoration.bold.bold()));
|
||||
return table;
|
||||
}
|
||||
|
||||
public class MBeanInterruptHandler extends CommandInterruptHandler {
|
||||
|
||||
private volatile Timer timer;
|
||||
|
||||
public MBeanInterruptHandler(CommandProcess process, Timer timer) {
|
||||
super(process);
|
||||
this.timer = timer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Void event) {
|
||||
timer.cancel();
|
||||
super.handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
private class MBeanTimerTask extends TimerTask {
|
||||
|
||||
private CommandProcess process;
|
||||
|
||||
public MBeanTimerTask(CommandProcess process) {
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (count >= getNumOfExecutions()) {
|
||||
// stop the timer
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
process.write("Process ends after " + getNumOfExecutions() + " time(s).\n");
|
||||
process.end();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
Set<ObjectName> objectNames = queryObjectNames();
|
||||
TableElement table = createTable();
|
||||
for (ObjectName objectName : objectNames) {
|
||||
MBeanInfo mBeanInfo = platformMBeanServer.getMBeanInfo(objectName);
|
||||
MBeanAttributeInfo[] attributes = mBeanInfo.getAttributes();
|
||||
for (MBeanAttributeInfo attribute : attributes) {
|
||||
String attributeName = attribute.getName();
|
||||
if (!getAttributeMatcher().matching(attributeName)) {
|
||||
continue;
|
||||
}
|
||||
String value;
|
||||
if (!attribute.isReadable()) {
|
||||
value = RenderUtil.render(new LabelElement("Unavailable").style(Decoration.bold_off.fg(Color.red)));
|
||||
} else {
|
||||
Object attributeObj = platformMBeanServer.getAttribute(objectName, attributeName);
|
||||
value = String.valueOf(attributeObj);
|
||||
}
|
||||
table.row(attributeName, value);
|
||||
}
|
||||
process.write(RenderUtil.render(table, process.width()));
|
||||
process.write("\n");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.warn("mbean error", e);
|
||||
}
|
||||
|
||||
count++;
|
||||
process.times().incrementAndGet();
|
||||
|
||||
if (getInterval() <= 0) {
|
||||
stop();
|
||||
process.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ public class CompletionUtils {
|
||||
return true;
|
||||
} else {
|
||||
completion.complete(candidates);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,11 +65,23 @@ public class TokenUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CliToken getLast(List<CliToken> tokens){
|
||||
public static CliToken getLast(List<CliToken> tokens) {
|
||||
if (tokens == null || tokens.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return tokens.get(tokens.size() -1);
|
||||
}
|
||||
}
|
||||
|
||||
public static String retrievePreviousArg(List<CliToken> tokens, String lastToken) {
|
||||
if (StringUtils.isBlank(lastToken) && tokens.size() > 2) {
|
||||
// tokens = { " ", "CLASS_NAME", " "}
|
||||
return tokens.get(tokens.size() - 2).value();
|
||||
} else if (tokens.size() > 3) {
|
||||
// tokens = { " ", "CLASS_NAME", " ", "PARTIAL_METHOD_NAME"}
|
||||
return tokens.get(tokens.size() - 3).value();
|
||||
} else {
|
||||
return Constants.EMPTY_STRING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
* [sysenv](sysenv.md)——查看JVM的环境变量
|
||||
* [getstatic](getstatic.md)——查看类的静态属性
|
||||
* **New!** [ognl](ognl.md)——执行ognl表达式
|
||||
* **New!** [mbean](mbean.md)——查看 Mbean 的信息
|
||||
|
||||
## class/classloader相关
|
||||
|
||||
|
||||
@@ -22,8 +22,9 @@ Advanced Usage
|
||||
* [jvm](jvm.md) - show JVM information
|
||||
* [sysprop](sysprop.md) - view/modify system properties
|
||||
* [sysenv](sysenv.md) — view system environment variables
|
||||
* **New!** [getstatic](getstatic.md) - examine class's static properties
|
||||
* [getstatic](getstatic.md) - examine class's static properties
|
||||
* **New!** [ognl](ognl.md) - execute ongl expression
|
||||
* **New!** [mbean](mbean.md) - show Mbean information
|
||||
|
||||
## class/classloader
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
mbean
|
||||
=======
|
||||
|
||||
> show Mbean information
|
||||
|
||||
This command can show or monitor Mbean attribute information.
|
||||
|
||||
### Parameters
|
||||
|
||||
|Name|Specification|
|
||||
|---:|:---|
|
||||
|*name-pattern*|pattern for the Mbean name|
|
||||
|*attribute-pattern*|pattern for the attribute name|
|
||||
|[m]|show meta information|
|
||||
|[i:]|specify the interval to refresh attribute value (ms)|
|
||||
|[n:]|execution times|
|
||||
|[E]|turn on regex matching while the default mode is wildcard matching. Only effect on the attribute name|
|
||||
|
||||
### Usage
|
||||
|
||||
show all Mbean names:
|
||||
|
||||
```bash
|
||||
mbean
|
||||
```
|
||||
|
||||
show meta data of Mbean:
|
||||
|
||||
```bash
|
||||
mbean -m java.lang:type=Threading
|
||||
```
|
||||
|
||||
show attributes of Mbean:
|
||||
|
||||
```bash
|
||||
mbean java.lang:type=Threading
|
||||
```
|
||||
|
||||
|
||||
Mbean name support wildcard matcher:
|
||||
|
||||
```bash
|
||||
mbean java.lang:type=Th*
|
||||
```
|
||||
|
||||
> Notes:ObjectName matching rules differ from normal wildcards, Reference resources:[javax.management.ObjectName](https://docs.oracle.com/javase/6/docs/api/javax/management/ObjectName.html?is-external=true)
|
||||
|
||||
Wildcards match specific attributes:
|
||||
|
||||
```bash
|
||||
mbean java.lang:type=Threading *Count
|
||||
```
|
||||
|
||||
Switch to regular matching using the `-E` command:
|
||||
|
||||
```bash
|
||||
mbean -E java.lang:type=Threading PeakThreadCount|ThreadCount|DaemonThreadCount
|
||||
```
|
||||
|
||||
Real-time monitoring using `-i` command:
|
||||
|
||||
```bash
|
||||
mbean -i 1000 java.lang:type=Threading *Count
|
||||
```
|
||||
@@ -0,0 +1,63 @@
|
||||
mbean
|
||||
=======
|
||||
|
||||
> 查看 Mbean 的信息
|
||||
|
||||
这个命令可以便捷的查看或监控 Mbean 的属性信息。
|
||||
|
||||
### 参数说明
|
||||
|
||||
|参数名称|参数说明|
|
||||
|---:|:---|
|
||||
|*name-pattern*|名称表达式匹配|
|
||||
|*attribute-pattern*|属性名表达式匹配|
|
||||
|[m]|查看元信息|
|
||||
|[i:]|刷新属性值的时间间隔 (ms)|
|
||||
|[n:]|刷新属性值的次数|
|
||||
|[E]|开启正则表达式匹配,默认为通配符匹配。仅对属性名有效|
|
||||
|
||||
### 使用参考
|
||||
|
||||
列出所有 Mbean 的名称:
|
||||
|
||||
```bash
|
||||
mbean
|
||||
```
|
||||
|
||||
查看 Mbean 的元信息:
|
||||
|
||||
```bash
|
||||
mbean -m java.lang:type=Threading
|
||||
```
|
||||
|
||||
查看mbean属性信息:
|
||||
|
||||
```bash
|
||||
mbean java.lang:type=Threading
|
||||
```
|
||||
|
||||
mbean的name支持通配符匹配:
|
||||
|
||||
```bash
|
||||
mbean java.lang:type=Th*
|
||||
```
|
||||
|
||||
>注意:ObjectName 的匹配规则与正常的通配符存在差异,详细参见:[javax.management.ObjectName](https://docs.oracle.com/javase/6/docs/api/javax/management/ObjectName.html?is-external=true)
|
||||
|
||||
通配符匹配特定的属性字段:
|
||||
|
||||
```bash
|
||||
mbean java.lang:type=Threading *Count
|
||||
```
|
||||
|
||||
使用`-E`命令切换为正则匹配:
|
||||
|
||||
```bash
|
||||
mbean -E java.lang:type=Threading PeakThreadCount|ThreadCount|DaemonThreadCount
|
||||
```
|
||||
|
||||
使用`-i`命令实时监控:
|
||||
|
||||
```bash
|
||||
mbean -i 1000 java.lang:type=Threading *Count
|
||||
```
|
||||
Reference in New Issue
Block a user