mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
transform command: mbean
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
package com.taobao.arthas.core.command.model;
|
||||
|
||||
/**
|
||||
* MBean attribute
|
||||
*
|
||||
* @author gongdewei 2020/4/26
|
||||
*/
|
||||
public class MBeanAttributeVO {
|
||||
private String name;
|
||||
private Object value;
|
||||
private String error;
|
||||
|
||||
public MBeanAttributeVO(String name, Object value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public MBeanAttributeVO(String name, Object value, String error) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.taobao.arthas.core.command.model;
|
||||
|
||||
import javax.management.MBeanInfo;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Model of 'mbean'
|
||||
*
|
||||
* @author gongdewei 2020/4/26
|
||||
*/
|
||||
public class MBeanModel extends ResultModel {
|
||||
|
||||
private List<String> mbeanNames;
|
||||
|
||||
private Map<String, MBeanInfo> mbeanMetadata;
|
||||
|
||||
private Map<String, List<MBeanAttributeVO>> mbeanAttribute;
|
||||
|
||||
public MBeanModel() {
|
||||
}
|
||||
|
||||
public MBeanModel(List<String> mbeanNames) {
|
||||
this.mbeanNames = mbeanNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "mbean";
|
||||
}
|
||||
|
||||
public List<String> getMbeanNames() {
|
||||
return mbeanNames;
|
||||
}
|
||||
|
||||
public void setMbeanNames(List<String> mbeanNames) {
|
||||
this.mbeanNames = mbeanNames;
|
||||
}
|
||||
|
||||
public Map<String, MBeanInfo> getMbeanMetadata() {
|
||||
return mbeanMetadata;
|
||||
}
|
||||
|
||||
public void setMbeanMetadata(Map<String, MBeanInfo> mbeanMetadata) {
|
||||
this.mbeanMetadata = mbeanMetadata;
|
||||
}
|
||||
|
||||
public Map<String, List<MBeanAttributeVO>> getMbeanAttribute() {
|
||||
return mbeanAttribute;
|
||||
}
|
||||
|
||||
public void setMbeanAttribute(Map<String, List<MBeanAttributeVO>> mbeanAttribute) {
|
||||
this.mbeanAttribute = mbeanAttribute;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.taobao.arthas.core.command.monitor200;
|
||||
|
||||
import com.taobao.arthas.core.command.Constants;
|
||||
import com.taobao.arthas.core.command.model.GcInfoVO;
|
||||
import com.taobao.arthas.core.command.model.JvmModel;
|
||||
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
|
||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.taobao.arthas.core.command.monitor200;
|
||||
import com.alibaba.arthas.deps.org.slf4j.Logger;
|
||||
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
|
||||
import com.taobao.arthas.core.command.Constants;
|
||||
import com.taobao.arthas.core.command.model.MBeanAttributeVO;
|
||||
import com.taobao.arthas.core.command.model.MBeanModel;
|
||||
import com.taobao.arthas.core.shell.cli.CliToken;
|
||||
import com.taobao.arthas.core.shell.cli.Completion;
|
||||
import com.taobao.arthas.core.shell.cli.CompletionUtils;
|
||||
@@ -22,38 +24,25 @@ 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.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.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.TabularData;
|
||||
|
||||
/**
|
||||
* Date: 2019/4/18
|
||||
@@ -63,13 +52,16 @@ import static javax.management.MBeanOperationInfo.UNKNOWN;
|
||||
@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")
|
||||
" mbean\n" +
|
||||
" mbean -m java.lang:type=Threading\n" +
|
||||
" mbean java.lang:type=Threading\n" +
|
||||
" mbean java.lang:type=Threading *Count\n" +
|
||||
" mbean java.lang:type=MemoryPool,name=PS\\ Old\\ Gen\n" +
|
||||
" mbean java.lang:type=MemoryPool,name=*\n" +
|
||||
" mbean java.lang:type=MemoryPool,name=* Usage\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 = LoggerFactory.getLogger(MBeanCommand.class);
|
||||
@@ -84,7 +76,12 @@ public class MBeanCommand extends AnnotatedCommand {
|
||||
private long count = 0;
|
||||
|
||||
@Argument(argName = "name-pattern", index = 0, required = false)
|
||||
@Description("ObjectName pattern, see javax.management.ObjectName for more detail.")
|
||||
@Description("ObjectName pattern, see javax.management.ObjectName for more detail. \n" +
|
||||
"It looks like this: \n" +
|
||||
" domain: key-property-list\n" +
|
||||
"For example: \n" +
|
||||
" java.lang:name=G1 Old Gen,type=MemoryPool\n" +
|
||||
" java.lang:name=*,type=MemoryPool")
|
||||
public void setNamePattern(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -107,7 +104,7 @@ public class MBeanCommand extends AnnotatedCommand {
|
||||
isRegEx = regEx;
|
||||
}
|
||||
|
||||
@Option(shortName = "m", longName = "metadata", flag = false)
|
||||
@Option(shortName = "m", longName = "metadata", flag = true)
|
||||
@Description("Show metadata of mbean.")
|
||||
public void setMetaData(boolean metaData) {
|
||||
this.metaData = metaData;
|
||||
@@ -141,6 +138,7 @@ public class MBeanCommand extends AnnotatedCommand {
|
||||
|
||||
@Override
|
||||
public void process(CommandProcess process) {
|
||||
//每个分支调用process.end()结束执行
|
||||
if (StringUtils.isEmpty(getName())) {
|
||||
listMBean(process);
|
||||
} else if (isMetaData()) {
|
||||
@@ -152,10 +150,11 @@ public class MBeanCommand extends AnnotatedCommand {
|
||||
|
||||
private void listMBean(CommandProcess process) {
|
||||
Set<ObjectName> objectNames = queryObjectNames();
|
||||
List<String> mbeanNames = new ArrayList<String>(objectNames.size());
|
||||
for (ObjectName objectName : objectNames) {
|
||||
process.write(objectName.toString());
|
||||
process.write("\n");
|
||||
mbeanNames.add(objectName.toString());
|
||||
}
|
||||
process.appendResult(new MBeanModel(mbeanNames));
|
||||
process.end();
|
||||
}
|
||||
|
||||
@@ -192,6 +191,8 @@ public class MBeanCommand extends AnnotatedCommand {
|
||||
} else {
|
||||
timer.schedule(new MBeanTimerTask(process), 0);
|
||||
}
|
||||
|
||||
//异步执行,这里不能调用process.end(),在timer task中结束命令执行
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
@@ -214,19 +215,18 @@ public class MBeanCommand extends AnnotatedCommand {
|
||||
Set<ObjectName> objectNames = queryObjectNames();
|
||||
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
try {
|
||||
TableElement table = createTable();
|
||||
MBeanModel mbeanModel = new MBeanModel();
|
||||
Map<String, MBeanInfo> mbeanMetaData = new LinkedHashMap<String, MBeanInfo>();
|
||||
mbeanModel.setMbeanMetadata(mbeanMetaData);
|
||||
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);
|
||||
mbeanMetaData.put(objectName.toString(), mBeanInfo);
|
||||
}
|
||||
process.write(RenderUtil.render(table, process.width()));
|
||||
process.appendResult(mbeanModel);
|
||||
process.end();
|
||||
} catch (Throwable e) {
|
||||
logger.warn("listMetaData error", e);
|
||||
} finally {
|
||||
process.end();
|
||||
process.end(1, "list mbean metadata error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,102 +348,6 @@ public class MBeanCommand extends AnnotatedCommand {
|
||||
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 {
|
||||
|
||||
@@ -475,16 +379,20 @@ public class MBeanCommand extends AnnotatedCommand {
|
||||
// stop the timer
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
process.write("Process ends after " + getNumOfExecutions() + " time(s).\n");
|
||||
process.end();
|
||||
process.end(-1, "Process ends after " + getNumOfExecutions() + " time(s).");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
//result model
|
||||
MBeanModel mBeanModel = new MBeanModel();
|
||||
Map<String, List<MBeanAttributeVO>> mbeanAttributeMap = new LinkedHashMap<String, List<MBeanAttributeVO>>();
|
||||
mBeanModel.setMbeanAttribute(mbeanAttributeMap);
|
||||
|
||||
MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
Set<ObjectName> objectNames = queryObjectNames();
|
||||
TableElement table = createTable();
|
||||
for (ObjectName objectName : objectNames) {
|
||||
List<MBeanAttributeVO> attributeVOs = null;
|
||||
MBeanInfo mBeanInfo = platformMBeanServer.getMBeanInfo(objectName);
|
||||
MBeanAttributeInfo[] attributes = mBeanInfo.getAttributes();
|
||||
for (MBeanAttributeInfo attribute : attributes) {
|
||||
@@ -492,29 +400,99 @@ public class MBeanCommand extends AnnotatedCommand {
|
||||
if (!getAttributeMatcher().matching(attributeName)) {
|
||||
continue;
|
||||
}
|
||||
String value;
|
||||
|
||||
//create attributeVO list
|
||||
if (attributeVOs == null) {
|
||||
attributeVOs = new ArrayList<MBeanAttributeVO>();
|
||||
mbeanAttributeMap.put(objectName.toString(), attributeVOs);
|
||||
}
|
||||
|
||||
if (!attribute.isReadable()) {
|
||||
value = RenderUtil.render(new LabelElement("Unavailable").style(Decoration.bold_off.fg(Color.red)));
|
||||
attributeVOs.add(new MBeanAttributeVO(attributeName, null, "Unavailable"));
|
||||
} else {
|
||||
Object attributeObj = platformMBeanServer.getAttribute(objectName, attributeName);
|
||||
value = String.valueOf(attributeObj);
|
||||
try {
|
||||
Object attributeObj = platformMBeanServer.getAttribute(objectName, attributeName);
|
||||
attributeVOs.add(createMBeanAttributeVO(attributeName, attributeObj));
|
||||
} catch (Throwable e) {
|
||||
logger.error("read mbean attribute failed: objectName={}, attributeName={}", objectName, attributeName, e);
|
||||
String errorStr;
|
||||
Throwable cause = e.getCause();
|
||||
if (cause != null && cause instanceof UnsupportedOperationException) {
|
||||
errorStr = "Unsupported";
|
||||
} else {
|
||||
errorStr = "Failure";
|
||||
}
|
||||
attributeVOs.add(new MBeanAttributeVO(attributeName, null, errorStr));
|
||||
}
|
||||
}
|
||||
table.row(attributeName, value);
|
||||
}
|
||||
process.write(RenderUtil.render(table, process.width()));
|
||||
process.write("\n");
|
||||
}
|
||||
process.appendResult(mBeanModel);
|
||||
} catch (Throwable e) {
|
||||
logger.warn("mbean error", e);
|
||||
logger.warn("read mbean error", e);
|
||||
stop();
|
||||
process.end(1, "read mbean error.");
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
process.times().incrementAndGet();
|
||||
|
||||
if (getInterval() <= 0) {
|
||||
stop();
|
||||
process.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MBeanAttributeVO createMBeanAttributeVO(String attributeName, Object originAttrValue) {
|
||||
Object attrValue = convertAttrValue(attributeName, originAttrValue);
|
||||
|
||||
return new MBeanAttributeVO(attributeName, attrValue);
|
||||
}
|
||||
|
||||
private Object convertAttrValue(String attributeName, Object originAttrValue) {
|
||||
Object attrValue = originAttrValue;
|
||||
|
||||
try {
|
||||
if (originAttrValue instanceof ObjectName) {
|
||||
attrValue = String.valueOf(originAttrValue);
|
||||
} else if (attrValue instanceof CompositeData) {
|
||||
//mbean java.lang:type=MemoryPool,name=*
|
||||
CompositeData compositeData = (CompositeData) attrValue;
|
||||
attrValue = convertCompositeData(attributeName, compositeData);
|
||||
} else if (attrValue instanceof CompositeData[]) {
|
||||
//mbean com.sun.management:type=HotSpotDiagnostic
|
||||
CompositeData[] compositeDataArray = (CompositeData[]) attrValue;
|
||||
List<Map<String, Object>> dataList = new ArrayList<Map<String, Object>>(compositeDataArray.length);
|
||||
for (CompositeData compositeData : compositeDataArray) {
|
||||
dataList.add(convertCompositeData(attributeName, compositeData));
|
||||
}
|
||||
attrValue = dataList;
|
||||
} else if (attrValue instanceof TabularData) {
|
||||
//mbean java.lang:type=GarbageCollector,name=*
|
||||
TabularData tabularData = (TabularData) attrValue;
|
||||
Collection<CompositeData> compositeDataList = (Collection<CompositeData>) tabularData.values();
|
||||
List<Map<String, Object>> dataList = new ArrayList<Map<String, Object>>(compositeDataList.size());
|
||||
for (CompositeData compositeData : compositeDataList) {
|
||||
dataList.add(convertCompositeData(attributeName, compositeData));
|
||||
}
|
||||
attrValue = dataList;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("convert mbean attribute error, attribute: {}={}", attributeName, originAttrValue, e);
|
||||
attrValue = String.valueOf(originAttrValue);
|
||||
}
|
||||
return attrValue;
|
||||
}
|
||||
|
||||
private Map<String, Object> convertCompositeData(String attributeName, CompositeData compositeData) {
|
||||
Set<String> keySet = compositeData.getCompositeType().keySet();
|
||||
String[] keys = keySet.toArray(new String[0]);
|
||||
Object[] values = compositeData.getAll(keys);
|
||||
Map<String, Object> data = new LinkedHashMap<String, Object>();
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
data.put(keys[i], convertAttrValue(attributeName + "." + keys[i], values[i]));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
package com.taobao.arthas.core.command.view;
|
||||
|
||||
import com.taobao.arthas.core.command.model.MBeanAttributeVO;
|
||||
import com.taobao.arthas.core.command.model.MBeanModel;
|
||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||
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 javax.management.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.taobao.text.ui.Element.label;
|
||||
import static javax.management.MBeanOperationInfo.*;
|
||||
import static javax.management.MBeanOperationInfo.UNKNOWN;
|
||||
|
||||
/**
|
||||
* View of 'mbean' command
|
||||
*
|
||||
* @author gongdewei 2020/4/26
|
||||
*/
|
||||
public class MBeanView extends ResultView<MBeanModel> {
|
||||
@Override
|
||||
public void draw(CommandProcess process, MBeanModel result) {
|
||||
if (result.getMbeanNames() != null) {
|
||||
drawMBeanNames(process, result.getMbeanNames());
|
||||
} else if (result.getMbeanMetadata() != null) {
|
||||
drawMBeanMetadata(process, result.getMbeanMetadata());
|
||||
} else if (result.getMbeanAttribute() != null) {
|
||||
drawMBeanAttributes(process, result.getMbeanAttribute());
|
||||
}
|
||||
}
|
||||
|
||||
private void drawMBeanAttributes(CommandProcess process, Map<String, List<MBeanAttributeVO>> mbeanAttributeMap) {
|
||||
for (Map.Entry<String, List<MBeanAttributeVO>> entry : mbeanAttributeMap.entrySet()) {
|
||||
String objectName = entry.getKey();
|
||||
List<MBeanAttributeVO> attributeVOList = entry.getValue();
|
||||
|
||||
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
|
||||
table.row(true, "OBJECT_NAME", objectName);
|
||||
table.row(true, label("NAME").style(Decoration.bold.bold()),
|
||||
label("VALUE").style(Decoration.bold.bold()));
|
||||
|
||||
for (MBeanAttributeVO attributeVO : attributeVOList) {
|
||||
String attributeName = attributeVO.getName();
|
||||
String valueStr;
|
||||
if (attributeVO.getError() != null) {
|
||||
valueStr = RenderUtil.render(new LabelElement(attributeVO.getError()).style(Decoration.bold_off.fg(Color.red)));
|
||||
} else {
|
||||
//convert array to list
|
||||
// TODO support all array type
|
||||
Object value = attributeVO.getValue();
|
||||
if (value instanceof String[]) {
|
||||
value = Arrays.asList((String[]) value);
|
||||
} else if (value instanceof Integer[]) {
|
||||
value = Arrays.asList((Integer[]) value);
|
||||
} else if (value instanceof Long[]) {
|
||||
value = Arrays.asList((Long[]) value);
|
||||
} else if (value instanceof int[]) {
|
||||
value = convertArrayToList((int[]) value);
|
||||
} else if (value instanceof long[]) {
|
||||
value = convertArrayToList((long[]) value);
|
||||
}
|
||||
//to string
|
||||
valueStr = String.valueOf(value);
|
||||
}
|
||||
table.row(attributeName, valueStr);
|
||||
}
|
||||
process.write(RenderUtil.render(table, process.width()));
|
||||
process.write("\n");
|
||||
}
|
||||
}
|
||||
|
||||
private List<Long> convertArrayToList(long[] longs) {
|
||||
List<Long> list = new ArrayList<Long>();
|
||||
for (long aLong : longs) {
|
||||
list.add(aLong);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<Integer> convertArrayToList(int[] ints) {
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
for (int anInt : ints) {
|
||||
list.add(anInt);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void drawMBeanMetadata(CommandProcess process, Map<String, MBeanInfo> mbeanMetadata) {
|
||||
TableElement table = createTable();
|
||||
for (Map.Entry<String, MBeanInfo> entry : mbeanMetadata.entrySet()) {
|
||||
String objectName = entry.getKey();
|
||||
MBeanInfo mBeanInfo = entry.getValue();
|
||||
drawMetaInfo(mBeanInfo, objectName, table);
|
||||
drawAttributeInfo(mBeanInfo.getAttributes(), table);
|
||||
drawOperationInfo(mBeanInfo.getOperations(), table);
|
||||
drawNotificationInfo(mBeanInfo.getNotifications(), table);
|
||||
}
|
||||
process.write(RenderUtil.render(table, process.width()));
|
||||
|
||||
}
|
||||
|
||||
private void drawMBeanNames(CommandProcess process, List<String> mbeanNames) {
|
||||
for (String mbeanName : mbeanNames) {
|
||||
process.write(mbeanName).write("\n");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private void drawMetaInfo(MBeanInfo mBeanInfo, String 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);
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -60,8 +60,14 @@ public class ResultViewResolver {
|
||||
registerView(SearchMethodView.class);
|
||||
|
||||
//logger
|
||||
registerView(LoggerView.class);
|
||||
|
||||
//monitor2000
|
||||
registerView(DashboardView.class);
|
||||
registerView(JvmView.class);
|
||||
registerView(MBeanView.class);
|
||||
registerView(PerfCounterView.class);
|
||||
registerView(ThreadView.class);
|
||||
|
||||
} catch (Throwable e) {
|
||||
logger.error("register result view failed", e);
|
||||
|
||||
Reference in New Issue
Block a user