Commit 5d7c4150 authored by shengnan hu's avatar shengnan hu
Browse files

init

parents
Pipeline #4715 failed with stage
in 30 seconds
package com.taobao.arthas.core.command.monitor200;
import com.taobao.arthas.core.command.model.TraceModel;
import com.taobao.arthas.core.command.model.TraceTree;
import com.taobao.arthas.core.util.ThreadUtil;
/**
* 用于在ThreadLocal中传递的实体
* @author ralf0131 2017-01-05 14:05.
*/
public class TraceEntity {
protected TraceTree tree;
protected int deep;
public TraceEntity(ClassLoader loader) {
this.tree = createTraceTree(loader);
this.deep = 0;
}
private TraceTree createTraceTree(ClassLoader loader) {
return new TraceTree(ThreadUtil.getThreadNode(loader, Thread.currentThread()));
}
public TraceModel getModel() {
tree.trim();
return new TraceModel(tree.getRoot(), tree.getNodeCount());
}
}
package com.taobao.arthas.core.command.monitor200;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.instrument.Instrumentation;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.common.IOUtils;
import com.taobao.arthas.common.VmToolUtils;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.express.Express;
import com.taobao.arthas.core.command.express.ExpressException;
import com.taobao.arthas.core.command.express.ExpressFactory;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.command.model.ObjectVO;
import com.taobao.arthas.core.command.model.VmToolModel;
import com.taobao.arthas.core.shell.cli.Completion;
import com.taobao.arthas.core.shell.cli.CompletionUtils;
import com.taobao.arthas.core.shell.cli.OptionCompleteHandler;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.SearchUtils;
import com.taobao.middleware.cli.annotations.DefaultValue;
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 arthas.VmTool;
/**
*
* @author hengyunabc 2021-04-27
* @author ZhangZiCheng 2021-04-29
*
*/
//@formatter:off
@Name("vmtool")
@Summary("jvm tool")
@Description(Constants.EXAMPLE
+ " vmtool --action getInstances --className demo.MathGame\n"
+ " vmtool --action getInstances --className demo.MathGame --express 'instances.length'\n"
+ " vmtool --action getInstances --className demo.MathGame --express 'instances[0]'\n"
+ " vmtool --action getInstances --className demo.MathGame -x 2\n"
+ " vmtool --action getInstances --className java.lang.String --limit 10\n"
+ " vmtool --action getInstances --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --className org.springframework.context.ApplicationContext\n"
+ " vmtool --action forceGc\n"
+ Constants.WIKI + Constants.WIKI_HOME + "vmtool")
//@formatter:on
public class VmToolCommand extends AnnotatedCommand {
private static final Logger logger = LoggerFactory.getLogger(VmToolCommand.class);
private VmToolAction action;
private String className;
private String express;
private String hashCode = null;
private String classLoaderClass;
/**
* default value 1
*/
private int expand;
/**
* default value 10
*/
private int limit;
private String libPath;
private static String defaultLibPath;
private static VmTool vmTool = null;
static {
String libName = VmToolUtils.detectLibName();
if (libName != null) {
CodeSource codeSource = VmToolCommand.class.getProtectionDomain().getCodeSource();
if (codeSource != null) {
try {
File bootJarPath = new File(codeSource.getLocation().toURI().getSchemeSpecificPart());
File soFile = new File(bootJarPath.getParentFile(), "lib" + File.separator + libName);
if (soFile.exists()) {
defaultLibPath = soFile.getAbsolutePath();
}
} catch (Throwable e) {
logger.error("can not find VmTool so", e);
}
}
}
}
@Option(shortName = "a", longName = "action", required = true)
@Description("Action to execute")
public void setAction(VmToolAction action) {
this.action = action;
}
@Option(longName = "className")
@Description("The class name")
public void setClassName(String className) {
this.className = className;
}
@Option(shortName = "x", longName = "expand")
@Description("Expand level of object (1 by default)")
@DefaultValue("1")
public void setExpand(int expand) {
this.expand = expand;
}
@Option(shortName = "c", longName = "classloader")
@Description("The hash code of the special class's classLoader")
public void setHashCode(String hashCode) {
this.hashCode = hashCode;
}
@Option(longName = "classLoaderClass")
@Description("The class name of the special class's classLoader.")
public void setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
}
@Option(shortName = "l", longName = "limit")
@Description("Set the limit value of the getInstances action, default value is 10, set to -1 is unlimited")
@DefaultValue("10")
public void setLimit(int limit) {
this.limit = limit;
}
@Option(longName = "libPath")
@Description("The specify lib path.")
public void setLibPath(String path) {
libPath = path;
}
@Option(longName = "express", required = false)
@Description("The ognl expression, default valueis `instances`.")
public void setExpress(String express) {
this.express = express;
}
public enum VmToolAction {
getInstances, forceGc
}
@Override
public void process(final CommandProcess process) {
try {
Instrumentation inst = process.session().getInstrumentation();
if (VmToolAction.getInstances.equals(action)) {
if (className == null) {
process.end(-1, "The className option cannot be empty!");
return;
}
ClassLoader classLoader = null;
if (hashCode != null) {
classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode);
if (classLoader == null) {
process.end(-1, "Can not find classloader with hashCode: " + hashCode + ".");
return;
}
}else if ( classLoaderClass != null) {
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst,
classLoaderClass);
if (matchedClassLoaders.size() == 1) {
classLoader = matchedClassLoaders.get(0);
hashCode = Integer.toHexString(matchedClassLoaders.get(0).hashCode());
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils
.createClassLoaderVOList(matchedClassLoaders);
VmToolModel vmToolModel = new VmToolModel().setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(vmToolModel);
process.end(-1,
"Found more than one classloader by class name, please specify classloader with '-c <classloader hash>'");
return;
} else {
process.end(-1, "Can not find classloader by class name: " + classLoaderClass + ".");
return;
}
}else {
classLoader = ClassLoader.getSystemClassLoader();
}
List<Class<?>> matchedClasses = new ArrayList<Class<?>>(
SearchUtils.searchClassOnly(inst, className, false, hashCode));
int matchedClassSize = matchedClasses.size();
if (matchedClassSize == 0) {
process.end(-1, "Can not find class by class name: " + className + ".");
return;
} else if (matchedClassSize > 1) {
process.end(-1, "Found more than one class: " + matchedClasses + ", please specify classloader with '-c <classloader hash>'");
return;
} else {
Object[] instances = vmToolInstance().getInstances(matchedClasses.get(0), limit);
Object value = instances;
if (express != null) {
Express unpooledExpress = ExpressFactory.unpooledExpress(classLoader);
try {
value = unpooledExpress.bind(new InstancesWrapper(instances)).get(express);
} catch (ExpressException e) {
logger.warn("ognl: failed execute express: " + express, e);
process.end(-1, "Failed to execute ognl, exception message: " + e.getMessage()
+ ", please check $HOME/logs/arthas/arthas.log for more details. ");
}
}
VmToolModel vmToolModel = new VmToolModel().setValue(new ObjectVO(value, expand));
process.appendResult(vmToolModel);
process.end();
}
} else if (VmToolAction.forceGc.equals(action)) {
vmToolInstance().forceGc();
process.write("\n");
process.end();
return;
}
process.end();
} catch (Throwable e) {
logger.error("vmtool error", e);
process.end(1, "vmtool error: " + e.getMessage());
}
}
static class InstancesWrapper {
Object instances;
public InstancesWrapper(Object instances) {
this.instances = instances;
}
public Object getInstances() {
return instances;
}
public void setInstances(Object instances) {
this.instances = instances;
}
}
private VmTool vmToolInstance() {
if (vmTool != null) {
return vmTool;
} else {
if (libPath == null) {
libPath = defaultLibPath;
}
// 尝试把lib文件复制到临时文件里,避免多次attach时出现 Native Library already loaded in another classloader
FileOutputStream tmpLibOutputStream = null;
FileInputStream libInputStream = null;
try {
File tmpLibFile = File.createTempFile(VmTool.JNI_LIBRARY_NAME, null);
tmpLibOutputStream = new FileOutputStream(tmpLibFile);
libInputStream = new FileInputStream(libPath);
IOUtils.copy(libInputStream, tmpLibOutputStream);
libPath = tmpLibFile.getAbsolutePath();
logger.debug("copy {} to {}", libPath, tmpLibFile);
} catch (Throwable e) {
logger.error("try to copy lib error! libPath: {}", libPath, e);
} finally {
IOUtils.close(libInputStream);
IOUtils.close(tmpLibOutputStream);
}
vmTool = VmTool.getInstance(libPath);
}
return vmTool;
}
private Set<String> actions() {
Set<String> values = new HashSet<String>();
for (VmToolAction action : VmToolAction.values()) {
values.add(action.toString());
}
return values;
}
@Override
public void complete(Completion completion) {
List<OptionCompleteHandler> handlers = new ArrayList<OptionCompleteHandler>();
handlers.add(new OptionCompleteHandler() {
@Override
public boolean matchName(String token) {
return "-a".equals(token) || "--action".equals(token);
}
@Override
public boolean complete(Completion completion) {
return CompletionUtils.complete(completion, actions());
}
});
handlers.add(new OptionCompleteHandler() {
@Override
public boolean matchName(String token) {
return "--className".equals(token);
}
@Override
public boolean complete(Completion completion) {
return CompletionUtils.completeClassName(completion);
}
});
if (CompletionUtils.completeOptions(completion, handlers)) {
return;
}
super.complete(completion);
}
}
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.advisor.AccessPoint;
import com.taobao.arthas.core.advisor.Advice;
import com.taobao.arthas.core.advisor.AdviceListenerAdapter;
import com.taobao.arthas.core.advisor.ArthasMethod;
import com.taobao.arthas.core.command.model.ObjectVO;
import com.taobao.arthas.core.command.model.WatchModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.LogUtil;
import com.taobao.arthas.core.util.ThreadLocalWatch;
import java.util.Date;
/**
* @author beiwei30 on 29/11/2016.
*/
class WatchAdviceListener extends AdviceListenerAdapter {
private static final Logger logger = LoggerFactory.getLogger(WatchAdviceListener.class);
private final ThreadLocalWatch threadLocalWatch = new ThreadLocalWatch();
private WatchCommand command;
private CommandProcess process;
public WatchAdviceListener(WatchCommand command, CommandProcess process, boolean verbose) {
this.command = command;
this.process = process;
super.setVerbose(verbose);
}
private boolean isFinish() {
return command.isFinish() || !command.isBefore() && !command.isException() && !command.isSuccess();
}
@Override
public void before(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target, Object[] args)
throws Throwable {
// 开始计算本次方法调用耗时
threadLocalWatch.start();
if (command.isBefore()) {
watching(Advice.newForBefore(loader, clazz, method, target, args));
}
}
@Override
public void afterReturning(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target, Object[] args,
Object returnObject) throws Throwable {
Advice advice = Advice.newForAfterReturning(loader, clazz, method, target, args, returnObject);
if (command.isSuccess()) {
watching(advice);
}
finishing(advice);
}
@Override
public void afterThrowing(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target, Object[] args,
Throwable throwable) {
Advice advice = Advice.newForAfterThrowing(loader, clazz, method, target, args, throwable);
if (command.isException()) {
watching(advice);
}
finishing(advice);
}
private void finishing(Advice advice) {
if (isFinish()) {
watching(advice);
}
}
private void watching(Advice advice) {
try {
// 本次调用的耗时
double cost = threadLocalWatch.costInMillis();
boolean conditionResult = isConditionMet(command.getConditionExpress(), advice, cost);
if (this.isVerbose()) {
process.write("Condition express: " + command.getConditionExpress() + " , result: " + conditionResult + "\n");
}
if (conditionResult) {
// TODO: concurrency issues for process.write
Object value = getExpressionResult(command.getExpress(), advice, cost);
WatchModel model = new WatchModel();
model.setTs(new Date());
model.setCost(cost);
model.setValue(new ObjectVO(value, command.getExpand()));
model.setSizeLimit(command.getSizeLimit());
model.setClassName(advice.getClazz().getName());
model.setMethodName(advice.getMethod().getName());
if (advice.isBefore()) {
model.setAccessPoint(AccessPoint.ACCESS_BEFORE.getKey());
} else if (advice.isAfterReturning()) {
model.setAccessPoint(AccessPoint.ACCESS_AFTER_RETUNING.getKey());
} else if (advice.isAfterThrowing()) {
model.setAccessPoint(AccessPoint.ACCESS_AFTER_THROWING.getKey());
}
process.appendResult(model);
process.times().incrementAndGet();
if (isLimitExceeded(command.getNumberOfLimit(), process.times().get())) {
abortProcess(process, command.getNumberOfLimit());
}
}
} catch (Throwable e) {
logger.warn("watch failed.", e);
process.end(-1, "watch failed, condition is: " + command.getConditionExpress() + ", express is: "
+ command.getExpress() + ", " + e.getMessage() + ", visit " + LogUtil.loggingFile()
+ " for more details.");
}
}
}
package com.taobao.arthas.core.command.monitor200;
import java.util.Arrays;
import com.taobao.arthas.core.GlobalOptions;
import com.taobao.arthas.core.advisor.AdviceListener;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.shell.cli.Completion;
import com.taobao.arthas.core.shell.cli.CompletionUtils;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.SearchUtils;
import com.taobao.arthas.core.util.matcher.Matcher;
import com.taobao.arthas.core.view.ObjectView;
import com.taobao.middleware.cli.annotations.Argument;
import com.taobao.middleware.cli.annotations.DefaultValue;
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;
@Name("watch")
@Summary("Display the input/output parameter, return object, and thrown exception of specified method invocation")
@Description(Constants.EXPRESS_DESCRIPTION + "\nExamples:\n" +
" watch org.apache.commons.lang.StringUtils isBlank\n" +
" watch org.apache.commons.lang.StringUtils isBlank '{params, target, returnObj, throwExp}' -x 2\n" +
" watch *StringUtils isBlank params[0] params[0].length==1\n" +
" watch *StringUtils isBlank params '#cost>100'\n" +
" watch -f *StringUtils isBlank params\n" +
" watch *StringUtils isBlank params[0]\n" +
" watch -E -b org\\.apache\\.commons\\.lang\\.StringUtils isBlank params[0]\n" +
" watch javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter\n" +
" watch OuterClass$InnerClass\n" +
Constants.WIKI + Constants.WIKI_HOME + "watch")
public class WatchCommand extends EnhancerCommand {
private String classPattern;
private String methodPattern;
private String express;
private String conditionExpress;
private boolean isBefore = false;
private boolean isFinish = false;
private boolean isException = false;
private boolean isSuccess = false;
private Integer expand = 1;
private Integer sizeLimit = 10 * 1024 * 1024;
private boolean isRegEx = false;
private int numberOfLimit = 100;
@Argument(index = 0, argName = "class-pattern")
@Description("The full qualified class name you want to watch")
public void setClassPattern(String classPattern) {
this.classPattern = classPattern;
}
@Argument(index = 1, argName = "method-pattern")
@Description("The method name you want to watch")
public void setMethodPattern(String methodPattern) {
this.methodPattern = methodPattern;
}
@Argument(index = 2, argName = "express", required = false)
@DefaultValue("{params, target, returnObj}")
@Description("The content you want to watch, written by ognl. Default value is '{params, target, returnObj}'\n" + Constants.EXPRESS_EXAMPLES)
public void setExpress(String express) {
this.express = express;
}
@Argument(index = 3, argName = "condition-express", required = false)
@Description(Constants.CONDITION_EXPRESS)
public void setConditionExpress(String conditionExpress) {
this.conditionExpress = conditionExpress;
}
@Option(shortName = "b", longName = "before", flag = true)
@Description("Watch before invocation")
public void setBefore(boolean before) {
isBefore = before;
}
@Option(shortName = "f", longName = "finish", flag = true)
@Description("Watch after invocation, enable by default")
public void setFinish(boolean finish) {
isFinish = finish;
}
@Option(shortName = "e", longName = "exception", flag = true)
@Description("Watch after throw exception")
public void setException(boolean exception) {
isException = exception;
}
@Option(shortName = "s", longName = "success", flag = true)
@Description("Watch after successful invocation")
public void setSuccess(boolean success) {
isSuccess = success;
}
@Option(shortName = "M", longName = "sizeLimit")
@Description("Upper size limit in bytes for the result (10 * 1024 * 1024 by default)")
public void setSizeLimit(Integer sizeLimit) {
this.sizeLimit = sizeLimit;
}
@Option(shortName = "x", longName = "expand")
@Description("Expand level of object (1 by default), the max value is " + ObjectView.MAX_DEEP)
public void setExpand(Integer expand) {
this.expand = expand;
}
@Option(shortName = "E", longName = "regex", flag = true)
@Description("Enable regular expression to match (wildcard matching by default)")
public void setRegEx(boolean regEx) {
isRegEx = regEx;
}
@Option(shortName = "n", longName = "limits")
@Description("Threshold of execution times")
public void setNumberOfLimit(int numberOfLimit) {
this.numberOfLimit = numberOfLimit;
}
public String getClassPattern() {
return classPattern;
}
public String getMethodPattern() {
return methodPattern;
}
public String getExpress() {
return express;
}
public String getConditionExpress() {
return conditionExpress;
}
public boolean isBefore() {
return isBefore;
}
public boolean isFinish() {
return isFinish;
}
public boolean isException() {
return isException;
}
public boolean isSuccess() {
return isSuccess;
}
public Integer getExpand() {
return expand;
}
public Integer getSizeLimit() {
return sizeLimit;
}
public boolean isRegEx() {
return isRegEx;
}
public int getNumberOfLimit() {
return numberOfLimit;
}
@Override
protected Matcher getClassNameMatcher() {
if (classNameMatcher == null) {
classNameMatcher = SearchUtils.classNameMatcher(getClassPattern(), isRegEx());
}
return classNameMatcher;
}
@Override
protected Matcher getClassNameExcludeMatcher() {
if (classNameExcludeMatcher == null && getExcludeClassPattern() != null) {
classNameExcludeMatcher = SearchUtils.classNameMatcher(getExcludeClassPattern(), isRegEx());
}
return classNameExcludeMatcher;
}
@Override
protected Matcher getMethodNameMatcher() {
if (methodNameMatcher == null) {
methodNameMatcher = SearchUtils.classNameMatcher(getMethodPattern(), isRegEx());
}
return methodNameMatcher;
}
@Override
protected AdviceListener getAdviceListener(CommandProcess process) {
return new WatchAdviceListener(this, process, GlobalOptions.verbose || this.verbose);
}
@Override
protected void completeArgument3(Completion completion) {
CompletionUtils.complete(completion, Arrays.asList(EXPRESS_EXAMPLES));
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.Base64Model;
import com.taobao.arthas.core.shell.command.CommandProcess;
/**
*
* @author hengyunabc 2021-01-05
*
*/
public class Base64View extends ResultView<Base64Model> {
@Override
public void draw(CommandProcess process, Base64Model result) {
String content = result.getContent();
if (content != null) {
process.write(content);
}
process.write("\n");
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.CatModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
/**
* Result view for CatCommand
* @author gongdewei 2020/5/11
*/
public class CatView extends ResultView<CatModel> {
@Override
public void draw(CommandProcess process, CatModel result) {
process.write(result.getContent()).write("\n");
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderStat;
import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderUrlStat;
import com.taobao.arthas.core.command.model.ClassDetailVO;
import com.taobao.arthas.core.command.model.ClassLoaderModel;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.command.model.ClassSetVO;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.text.Decoration;
import com.taobao.text.ui.*;
import com.taobao.text.util.RenderUtil;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* @author gongdewei 2020/4/21
*/
public class ClassLoaderView extends ResultView<ClassLoaderModel> {
@Override
public void draw(CommandProcess process, ClassLoaderModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
if (result.getClassSet() != null) {
drawAllClasses(process, result.getClassSet());
}
if (result.getResources() != null) {
drawResources(process, result.getResources());
}
if (result.getLoadClass() != null) {
drawLoadClass(process, result.getLoadClass());
}
if (result.getUrls() != null) {
drawClassLoaderUrls(process, result.getUrls());
}
if (result.getClassLoaders() != null){
drawClassLoaders(process, result.getClassLoaders(), result.getTree());
}
if (result.getClassLoaderStats() != null){
drawClassLoaderStats(process, result.getClassLoaderStats());
}
if (result.getUrlStats() != null) {
drawUrlStats(process, result.getUrlStats());
}
}
private void drawUrlStats(CommandProcess process, Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats) {
for (Entry<ClassLoaderVO, ClassLoaderUrlStat> entry : urlStats.entrySet()) {
ClassLoaderVO classLoaderVO = entry.getKey();
ClassLoaderUrlStat urlStat = entry.getValue();
// 忽略 sun.reflect.DelegatingClassLoader 等动态ClassLoader
if (urlStat.getUsedUrls().isEmpty() && urlStat.getUnUsedUrls().isEmpty()) {
continue;
}
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
table.row(new LabelElement(classLoaderVO.getName() + ", hash:" + classLoaderVO.getHash())
.style(Decoration.bold.bold()));
Collection<String> usedUrls = urlStat.getUsedUrls();
table.row(new LabelElement("Used URLs:").style(Decoration.bold.bold()));
for (String url : usedUrls) {
table.row(url);
}
Collection<String> UnnsedUrls = urlStat.getUnUsedUrls();
table.row(new LabelElement("Unused URLs:").style(Decoration.bold.bold()));
for (String url : UnnsedUrls) {
table.row(url);
}
process.write(RenderUtil.render(table, process.width()))
.write("\n");
}
}
private void drawClassLoaderStats(CommandProcess process, Map<String, ClassLoaderStat> classLoaderStats) {
Element element = renderStat(classLoaderStats);
process.write(RenderUtil.render(element, process.width()))
.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING);
}
private static TableElement renderStat(Map<String, ClassLoaderStat> classLoaderStats) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.bold()).add("name", "numberOfInstances", "loadedCountTotal"));
for (Map.Entry<String, ClassLoaderStat> entry : classLoaderStats.entrySet()) {
table.row(entry.getKey(), "" + entry.getValue().getNumberOfInstance(), "" + entry.getValue().getLoadedCount());
}
return table;
}
public static void drawClassLoaders(CommandProcess process, Collection<ClassLoaderVO> classLoaders, boolean isTree) {
Element element = isTree ? renderTree(classLoaders) : renderTable(classLoaders);
process.write(RenderUtil.render(element, process.width()))
.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING);
}
private void drawClassLoaderUrls(CommandProcess process, List<String> urls) {
process.write(RenderUtil.render(renderClassLoaderUrls(urls), process.width()));
process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING);
}
private void drawLoadClass(CommandProcess process, ClassDetailVO loadClass) {
process.write(RenderUtil.render(ClassUtils.renderClassInfo(loadClass), process.width()) + "\n");
}
private void drawAllClasses(CommandProcess process, ClassSetVO classSetVO) {
process.write(RenderUtil.render(renderClasses(classSetVO), process.width()));
process.write("\n");
}
private void drawResources(CommandProcess process, List<String> resources) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
for (String resource : resources) {
table.row(resource);
}
process.write(RenderUtil.render(table, process.width()) + "\n");
process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING);
}
private Element renderClasses(ClassSetVO classSetVO) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
if (classSetVO.getSegment() == 0) {
table.row(new LabelElement("hash:" + classSetVO.getClassloader().getHash() + ", " + classSetVO.getClassloader().getName())
.style(Decoration.bold.bold()));
}
for (String className : classSetVO.getClasses()) {
table.row(new LabelElement(className));
}
return table;
}
private static Element renderClassLoaderUrls(List<String> urls) {
StringBuilder sb = new StringBuilder();
for (String url : urls) {
sb.append(url).append("\n");
}
return new LabelElement(sb.toString());
}
// 统计所有的ClassLoader的信息
private static TableElement renderTable(Collection<ClassLoaderVO> classLoaderInfos) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.bold()).add("name", "loadedCount", "hash", "parent"));
for (ClassLoaderVO classLoaderVO : classLoaderInfos) {
table.row(classLoaderVO.getName(), "" + classLoaderVO.getLoadedCount(), classLoaderVO.getHash(), classLoaderVO.getParent());
}
return table;
}
// 以树状列出ClassLoader的继承结构
private static Element renderTree(Collection<ClassLoaderVO> classLoaderInfos) {
TreeElement root = new TreeElement();
for (ClassLoaderVO classLoader : classLoaderInfos) {
TreeElement child = new TreeElement(classLoader.getName());
root.addChild(child);
renderSubtree(child, classLoader);
}
return root;
}
private static void renderSubtree(TreeElement parent, ClassLoaderVO parentClassLoader) {
if (parentClassLoader.getChildren() == null){
return;
}
for (ClassLoaderVO childClassLoader : parentClassLoader.getChildren()) {
TreeElement child = new TreeElement(childClassLoader.getName());
parent.addChild(child);
renderSubtree(child, childClassLoader);
}
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.*;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.text.Color;
import com.taobao.text.Decoration;
import com.taobao.text.ui.RowElement;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* View of 'dashboard' command
*
* @author gongdewei 2020/4/22
*/
public class DashboardView extends ResultView<DashboardModel> {
@Override
public void draw(CommandProcess process, DashboardModel result) {
int width = process.width();
int height = process.height();
// 上半部分放thread top。下半部分再切分为田字格,其中上面两格放memory, gc的信息。下面两格放tomcat,
// runtime的信息
int totalHeight = height - 1;
int threadTopHeight;
if (totalHeight <= 24) {
//总高度较小时取1/2
threadTopHeight = totalHeight / 2;
} else {
//总高度较大时取1/3,但不少于上面的值(24/2=12)
threadTopHeight = totalHeight / 3;
if (threadTopHeight < 12) {
threadTopHeight = 12;
}
}
int lowerHalf = totalHeight - threadTopHeight;
//Memory至少保留8行, 显示metaspace信息
int memoryInfoHeight = lowerHalf / 2;
if (memoryInfoHeight < 8) {
memoryInfoHeight = Math.min(8, lowerHalf);
}
//runtime
TableElement runtimeInfoTable = drawRuntimeInfo(result.getRuntimeInfo());
//tomcat
TableElement tomcatInfoTable = drawTomcatInfo(result.getTomcatInfo());
int runtimeInfoHeight = Math.max(runtimeInfoTable.getRows().size(), tomcatInfoTable == null ? 0 : tomcatInfoTable.getRows().size());
if (runtimeInfoHeight < lowerHalf - memoryInfoHeight) {
//如果runtimeInfo高度有剩余,则增大MemoryInfo的高度
memoryInfoHeight = lowerHalf - runtimeInfoHeight;
} else {
runtimeInfoHeight = lowerHalf - memoryInfoHeight;
}
//如果MemoryInfo高度有剩余,则增大ThreadHeight
int maxMemoryInfoHeight = getMemoryInfoHeight(result.getMemoryInfo());
memoryInfoHeight = Math.min(memoryInfoHeight, maxMemoryInfoHeight);
threadTopHeight = totalHeight - memoryInfoHeight - runtimeInfoHeight;
String threadInfo = ViewRenderUtil.drawThreadInfo(result.getThreads(), width, threadTopHeight);
String memoryAndGc = drawMemoryInfoAndGcInfo(result.getMemoryInfo(), result.getGcInfos(), width, memoryInfoHeight);
String runTimeAndTomcat = drawRuntimeInfoAndTomcatInfo(runtimeInfoTable, tomcatInfoTable, width, runtimeInfoHeight);
process.write(threadInfo + memoryAndGc + runTimeAndTomcat);
}
static String drawMemoryInfoAndGcInfo(Map<String, List<MemoryEntryVO>> memoryInfo, List<GcInfoVO> gcInfos, int width, int height) {
TableElement table = new TableElement(1, 1);
TableElement memoryInfoTable = MemoryView.drawMemoryInfo(memoryInfo);
TableElement gcInfoTable = drawGcInfo(gcInfos);
table.row(memoryInfoTable, gcInfoTable);
return RenderUtil.render(table, width, height);
}
private static int getMemoryInfoHeight(Map<String, List<MemoryEntryVO>> memoryInfo) {
int height = 1;
for (List<MemoryEntryVO> memoryEntryVOS : memoryInfo.values()) {
height += memoryEntryVOS.size();
}
return height;
}
private static TableElement drawGcInfo(List<GcInfoVO> gcInfos) {
TableElement table = new TableElement(1, 1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.fg(Color.black).bg(Color.white)).add("GC", ""));
for (GcInfoVO gcInfo : gcInfos) {
table.add(new RowElement().style(Decoration.bold.bold()).add("gc." + gcInfo.getName() + ".count",
"" + gcInfo.getCollectionCount()));
table.row("gc." + gcInfo.getName() + ".time(ms)", "" + gcInfo.getCollectionTime());
}
return table;
}
String drawRuntimeInfoAndTomcatInfo(TableElement runtimeInfoTable, TableElement tomcatInfoTable, int width, int height) {
if (height <= 0) {
return "";
}
TableElement resultTable = new TableElement(1, 1);
if (tomcatInfoTable != null) {
resultTable.row(runtimeInfoTable, tomcatInfoTable);
} else {
resultTable = runtimeInfoTable;
}
return RenderUtil.render(resultTable, width, height);
}
private static TableElement drawRuntimeInfo(RuntimeInfoVO runtimeInfo) {
TableElement table = new TableElement(1, 1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.fg(Color.black).bg(Color.white)).add("Runtime", ""));
table.row("os.name", runtimeInfo.getOsName());
table.row("os.version", runtimeInfo.getOsVersion());
table.row("java.version", runtimeInfo.getJavaVersion());
table.row("java.home", runtimeInfo.getJavaHome());
table.row("systemload.average", String.format("%.2f", runtimeInfo.getSystemLoadAverage()));
table.row("processors", "" + runtimeInfo.getProcessors());
table.row("timestamp/uptime", new Date(runtimeInfo.getTimestamp()).toString() + "/" + runtimeInfo.getUptime() + "s");
return table;
}
private static String formatBytes(long size) {
int unit = 1;
String unitStr = "B";
if (size / 1024 > 0) {
unit = 1024;
unitStr = "K";
} else if (size / 1024 / 1024 > 0) {
unit = 1024 * 1024;
unitStr = "M";
}
return String.format("%d%s", size / unit, unitStr);
}
private TableElement drawTomcatInfo(TomcatInfoVO tomcatInfo) {
if (tomcatInfo == null) {
return null;
}
//header
TableElement table = new TableElement(1, 1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.fg(Color.black).bg(Color.white)).add("Tomcat", ""));
if (tomcatInfo.getConnectorStats() != null) {
for (TomcatInfoVO.ConnectorStats connectorStat : tomcatInfo.getConnectorStats()) {
table.add(new RowElement().style(Decoration.bold.bold()).add("connector", connectorStat.getName()));
table.row("QPS", String.format("%.2f", connectorStat.getQps()));
table.row("RT(ms)", String.format("%.2f", connectorStat.getRt()));
table.row("error/s", String.format("%.2f", connectorStat.getError()));
table.row("received/s", formatBytes(connectorStat.getReceived()));
table.row("sent/s", formatBytes(connectorStat.getSent()));
}
}
if (tomcatInfo.getThreadPools() != null) {
for (TomcatInfoVO.ThreadPool threadPool : tomcatInfo.getThreadPools()) {
table.add(new RowElement().style(Decoration.bold.bold()).add("threadpool", threadPool.getName()));
table.row("busy", "" + threadPool.getBusy());
table.row("total", "" + threadPool.getTotal());
}
}
return table;
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.DumpClassModel;
import com.taobao.arthas.core.command.model.DumpClassVO;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.TypeRenderUtils;
import com.taobao.text.Color;
import com.taobao.text.Decoration;
import com.taobao.text.ui.Element;
import com.taobao.text.ui.LabelElement;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.util.List;
import static com.taobao.text.ui.Element.label;
/**
* @author gongdewei 2020/4/21
*/
public class DumpClassView extends ResultView<DumpClassModel> {
@Override
public void draw(CommandProcess process, DumpClassModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
if (result.getDumpedClasses() != null) {
drawDumpedClasses(process, result.getDumpedClasses());
} else if (result.getMatchedClasses() != null) {
Element table = ClassUtils.renderMatchedClasses(result.getMatchedClasses());
process.write(RenderUtil.render(table)).write("\n");
}
}
private void drawDumpedClasses(CommandProcess process, List<DumpClassVO> classVOs) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
table.row(new LabelElement("HASHCODE").style(Decoration.bold.bold()),
new LabelElement("CLASSLOADER").style(Decoration.bold.bold()),
new LabelElement("LOCATION").style(Decoration.bold.bold()));
for (DumpClassVO clazz : classVOs) {
table.row(label(clazz.getClassLoaderHash()).style(Decoration.bold.fg(Color.red)),
TypeRenderUtils.drawClassLoader(clazz),
label(clazz.getLocation()).style(Decoration.bold.fg(Color.red)));
}
process.write(RenderUtil.render(table, process.width()))
.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING);
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.EchoModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
/**
* @author gongdewei 2020/5/11
*/
public class EchoView extends ResultView<EchoModel> {
@Override
public void draw(CommandProcess process, EchoModel result) {
process.write(result.getContent()).write("\n");
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.EnhancerModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
/**
* Term view for EnhancerModel
* @author gongdewei 2020/7/21
*/
public class EnhancerView extends ResultView<EnhancerModel> {
@Override
public void draw(CommandProcess process, EnhancerModel result) {
// ignore enhance result status, judge by the following output
if (result.getEffect() != null) {
process.write(ViewRenderUtil.renderEnhancerAffect(result.getEffect()));
}
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.GetStaticModel;
import com.taobao.arthas.core.command.model.ObjectVO;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.arthas.core.view.ObjectView;
import com.taobao.text.ui.Element;
import com.taobao.text.util.RenderUtil;
/**
* @author gongdewei 2020/4/20
*/
public class GetStaticView extends ResultView<GetStaticModel> {
@Override
public void draw(CommandProcess process, GetStaticModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
if (result.getField() != null) {
ObjectVO field = result.getField();
String valueStr = StringUtils.objectToString(field.needExpand() ? new ObjectView(field).draw() : field.getObject());
process.write("field: " + result.getFieldName() + "\n" + valueStr + "\n");
} else if (result.getMatchedClasses() != null) {
Element table = ClassUtils.renderMatchedClasses(result.getMatchedClasses());
process.write(RenderUtil.render(table)).write("\n");
}
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.CommandVO;
import com.taobao.arthas.core.command.model.HelpModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.usage.StyledUsageFormatter;
import com.taobao.middleware.cli.CLI;
import com.taobao.text.Color;
import com.taobao.text.Decoration;
import com.taobao.text.Style;
import com.taobao.text.ui.Element;
import com.taobao.text.ui.LabelElement;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.util.List;
import static com.taobao.text.ui.Element.label;
import static com.taobao.text.ui.Element.row;
/**
* @author gongdewei 2020/4/3
*/
public class HelpView extends ResultView<HelpModel> {
@Override
public void draw(CommandProcess process, HelpModel result) {
if (result.getCommands() != null) {
String message = RenderUtil.render(mainHelp(result.getCommands()), process.width());
process.write(message);
} else if (result.getDetailCommand() != null) {
process.write(commandHelp(result.getDetailCommand().cli(), process.width()));
}
}
private static Element mainHelp(List<CommandVO> commands) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
table.row(new LabelElement("NAME").style(Style.style(Decoration.bold)), new LabelElement("DESCRIPTION"));
for (CommandVO commandVO : commands) {
table.add(row().add(label(commandVO.getName()).style(Style.style(Color.green))).add(label(commandVO.getSummary())));
}
return table;
}
private static String commandHelp(CLI command, int width) {
return StyledUsageFormatter.styledUsage(command, width);
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.ClassVO;
import com.taobao.arthas.core.command.model.JadModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.TypeRenderUtils;
import com.taobao.text.Color;
import com.taobao.text.Decoration;
import com.taobao.text.lang.LangRenderUtil;
import com.taobao.text.ui.Element;
import com.taobao.text.ui.LabelElement;
import com.taobao.text.util.RenderUtil;
/**
* @author gongdewei 2020/4/22
*/
public class JadView extends ResultView<JadModel> {
@Override
public void draw(CommandProcess process, JadModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
int width = process.width();
if (result.getMatchedClasses() != null) {
Element table = ClassUtils.renderMatchedClasses(result.getMatchedClasses());
process.write(RenderUtil.render(table, width)).write("\n");
} else {
ClassVO classInfo = result.getClassInfo();
if (classInfo != null) {
process.write("\n");
process.write(RenderUtil.render(new LabelElement("ClassLoader: ").style(Decoration.bold.fg(Color.red)), width));
process.write(RenderUtil.render(TypeRenderUtils.drawClassLoader(classInfo), width) + "\n");
}
if (result.getLocation() != null) {
process.write(RenderUtil.render(new LabelElement("Location: ").style(Decoration.bold.fg(Color.red)), width));
process.write(RenderUtil.render(new LabelElement(result.getLocation()).style(Decoration.bold.fg(Color.blue)), width) + "\n");
}
process.write(LangRenderUtil.render(result.getSource()) + "\n");
process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING);
}
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.JvmModel;
import com.taobao.arthas.core.command.model.JvmItemVO;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.text.Decoration;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static com.taobao.text.ui.Element.label;
/**
* View of 'jvm' command
*
* @author gongdewei 2020/4/24
*/
public class JvmView extends ResultView<JvmModel> {
@Override
public void draw(CommandProcess process, JvmModel result) {
TableElement table = new TableElement(2, 5).leftCellPadding(1).rightCellPadding(1);
for (Map.Entry<String, List<JvmItemVO>> entry : result.getJvmInfo().entrySet()) {
String group = entry.getKey();
List<JvmItemVO> items = entry.getValue();
table.row(true, label(group).style(Decoration.bold.bold()));
for (JvmItemVO item : items) {
String valueStr;
if (item.getValue() instanceof Map && item.getName().endsWith("MEMORY-USAGE")) {
valueStr = renderMemoryUsage((Map<String, Object>) item.getValue());
} else {
valueStr = renderItemValue(item.getValue());
}
if (item.getDesc() != null) {
table.row(item.getName() + "\n[" + item.getDesc() + "]", valueStr);
} else {
table.row(item.getName(), valueStr);
}
}
table.row("", "");
}
process.write(RenderUtil.render(table, process.width()));
}
private String renderCountTime(long[] value) {
//count/time
return value[0] + "/" + value[1];
}
private String renderItemValue(Object value) {
if (value == null) {
return "null";
}
if (value instanceof Collection) {
return renderCollectionValue((Collection) value);
} else if (value instanceof String[]) {
return renderArrayValue((String[]) value);
} else if (value instanceof Map) {
return renderMapValue((Map) value);
}
return String.valueOf(value);
}
private String renderCollectionValue(Collection<String> strings) {
final StringBuilder colSB = new StringBuilder();
if (strings.isEmpty()) {
colSB.append("[]");
} else {
for (String str : strings) {
colSB.append(str).append("\n");
}
}
return colSB.toString();
}
private String renderArrayValue(String... stringArray) {
final StringBuilder colSB = new StringBuilder();
if (null == stringArray
|| stringArray.length == 0) {
colSB.append("[]");
} else {
for (String str : stringArray) {
colSB.append(str).append("\n");
}
}
return colSB.toString();
}
private String renderMapValue(Map<String, Object> valueMap) {
final StringBuilder colSB = new StringBuilder();
if (valueMap != null) {
for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
colSB.append(entry.getKey()).append(" : ").append(entry.getValue()).append("\n");
}
}
return colSB.toString();
}
private String renderMemoryUsage(Map<String, Object> valueMap) {
final StringBuilder colSB = new StringBuilder();
String[] keys = new String[]{"init", "used", "committed", "max"};
for (String key : keys) {
Object value = valueMap.get(key);
String valueStr = value != null ? formatMemoryByte((Long) value) : "";
colSB.append(key).append(" : ").append(valueStr).append("\n");
}
return colSB.toString();
}
private String formatMemoryByte(long bytes) {
return String.format("%s(%s)", bytes, StringUtils.humanReadableByteCount(bytes));
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.logger.LoggerHelper;
import com.taobao.arthas.core.command.model.LoggerModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.text.Decoration;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.util.List;
import java.util.Map;
import static com.taobao.text.ui.Element.label;
/**
* View of 'logger' command
*
* @author gongdewei 2020/4/22
*/
public class LoggerView extends ResultView<LoggerModel> {
@Override
public void draw(CommandProcess process, LoggerModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
process.write(renderLoggerInfo(result.getLoggerInfoMap(), process.width()));
}
private String renderLoggerInfo(Map<String, Map<String, Object>> loggerInfos, int width) {
StringBuilder sb = new StringBuilder(8192);
for (Map.Entry<String, Map<String, Object>> entry : loggerInfos.entrySet()) {
Map<String, Object> info = entry.getValue();
TableElement table = new TableElement(2, 10).leftCellPadding(1).rightCellPadding(1);
TableElement appendersTable = new TableElement().rightCellPadding(1);
Class<?> clazz = (Class<?>) info.get(LoggerHelper.clazz);
table.row(label(LoggerHelper.name).style(Decoration.bold.bold()), label("" + info.get(LoggerHelper.name)))
.row(label(LoggerHelper.clazz).style(Decoration.bold.bold()), label("" + clazz.getName()))
.row(label(LoggerHelper.classLoader).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.classLoader)))
.row(label(LoggerHelper.classLoaderHash).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.classLoaderHash)))
.row(label(LoggerHelper.level).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.level)));
if (info.get(LoggerHelper.effectiveLevel) != null) {
table.row(label(LoggerHelper.effectiveLevel).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.effectiveLevel)));
}
if (info.get(LoggerHelper.config) != null) {
table.row(label(LoggerHelper.config).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.config)));
}
table.row(label(LoggerHelper.additivity).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.additivity)))
.row(label(LoggerHelper.codeSource).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.codeSource)));
@SuppressWarnings("unchecked")
List<Map<String, Object>> appenders = (List<Map<String, Object>>) info.get(LoggerHelper.appenders);
if (appenders != null && !appenders.isEmpty()) {
for (Map<String, Object> appenderInfo : appenders) {
Class<?> appenderClass = (Class<?>) appenderInfo.get(LoggerHelper.clazz);
appendersTable.row(label(LoggerHelper.name).style(Decoration.bold.bold()),
label("" + appenderInfo.get(LoggerHelper.name)));
appendersTable.row(label(LoggerHelper.clazz), label("" + appenderClass.getName()));
appendersTable.row(label(LoggerHelper.classLoader), label("" + info.get(LoggerHelper.classLoader)));
appendersTable.row(label(LoggerHelper.classLoaderHash),
label("" + info.get(LoggerHelper.classLoaderHash)));
if (appenderInfo.get(LoggerHelper.file) != null) {
appendersTable.row(label(LoggerHelper.file), label("" + appenderInfo.get(LoggerHelper.file)));
}
if (appenderInfo.get(LoggerHelper.target) != null) {
appendersTable.row(label(LoggerHelper.target),
label("" + appenderInfo.get(LoggerHelper.target)));
}
if (appenderInfo.get(LoggerHelper.blocking) != null) {
appendersTable.row(label(LoggerHelper.blocking),
label("" + appenderInfo.get(LoggerHelper.blocking)));
}
if (appenderInfo.get(LoggerHelper.appenderRef) != null) {
appendersTable.row(label(LoggerHelper.appenderRef),
label("" + appenderInfo.get(LoggerHelper.appenderRef)));
}
}
table.row(label("appenders").style(Decoration.bold.bold()), appendersTable);
}
sb.append(RenderUtil.render(table, width)).append('\n');
}
return sb.toString();
}
}
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.*;
/**
* 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 == null ? "" : fieldValue.toString());
}
}
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.MemoryCompilerModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
/**
* @author gongdewei 2020/4/20
*/
public class MemoryCompilerView extends ResultView<MemoryCompilerModel> {
@Override
public void draw(CommandProcess process, MemoryCompilerModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
process.write("Memory compiler output:\n");
for (String file : result.getFiles()) {
process.write(file + '\n');
}
}
}
package com.taobao.arthas.core.command.view;
import java.lang.management.MemoryUsage;
import java.util.List;
import java.util.Map;
import com.taobao.arthas.core.command.model.MemoryEntryVO;
import com.taobao.arthas.core.command.model.MemoryModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.text.Color;
import com.taobao.text.Decoration;
import com.taobao.text.Style;
import com.taobao.text.ui.RowElement;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
/**
* View of 'memory' command
*
* @author hengyunabc 2022-03-01
*/
public class MemoryView extends ResultView<MemoryModel> {
@Override
public void draw(CommandProcess process, MemoryModel result) {
TableElement table = drawMemoryInfo(result.getMemoryInfo());
process.write(RenderUtil.render(table, process.width()));
}
static TableElement drawMemoryInfo(Map<String, List<MemoryEntryVO>> memoryInfo) {
TableElement table = new TableElement(3, 1, 1, 1, 1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.fg(Color.black).bg(Color.white)).add("Memory",
"used", "total", "max", "usage"));
List<MemoryEntryVO> heapMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_HEAP);
//heap memory
for (MemoryEntryVO memoryEntryVO : heapMemoryEntries) {
if (MemoryEntryVO.TYPE_HEAP.equals(memoryEntryVO.getName())) {
new MemoryEntry(memoryEntryVO).addTableRow(table, Decoration.bold.bold());
} else {
new MemoryEntry(memoryEntryVO).addTableRow(table);
}
}
//non-heap memory
List<MemoryEntryVO> nonheapMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_NON_HEAP);
for (MemoryEntryVO memoryEntryVO : nonheapMemoryEntries) {
if (MemoryEntryVO.TYPE_NON_HEAP.equals(memoryEntryVO.getName())) {
new MemoryEntry(memoryEntryVO).addTableRow(table, Decoration.bold.bold());
} else {
new MemoryEntry(memoryEntryVO).addTableRow(table);
}
}
//buffer-pool
List<MemoryEntryVO> bufferPoolMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_BUFFER_POOL);
if (bufferPoolMemoryEntries != null) {
for (MemoryEntryVO memoryEntryVO : bufferPoolMemoryEntries) {
new MemoryEntry(memoryEntryVO).addTableRow(table);
}
}
return table;
}
static class MemoryEntry {
String name;
long used;
long total;
long max;
int unit;
String unitStr;
public MemoryEntry(String name, long used, long total, long max) {
this.name = name;
this.used = used;
this.total = total;
this.max = max;
unitStr = "K";
unit = 1024;
if (used / 1024 / 1024 > 0) {
unitStr = "M";
unit = 1024 * 1024;
}
}
public MemoryEntry(String name, MemoryUsage usage) {
this(name, usage.getUsed(), usage.getCommitted(), usage.getMax());
}
public MemoryEntry(MemoryEntryVO memoryEntryVO) {
this(memoryEntryVO.getName(), memoryEntryVO.getUsed(), memoryEntryVO.getTotal(), memoryEntryVO.getMax());
}
private String format(long value) {
String valueStr = "-";
if (value == -1) {
return "-1";
}
if (value != Long.MIN_VALUE) {
valueStr = value / unit + unitStr;
}
return valueStr;
}
public void addTableRow(TableElement table) {
double usage = used / (double) (max == -1 || max == Long.MIN_VALUE ? total : max) * 100;
if (Double.isNaN(usage) || Double.isInfinite(usage)) {
usage = 0;
}
table.row(name, format(used), format(total), format(max), String.format("%.2f%%", usage));
}
public void addTableRow(TableElement table, Style.Composite style) {
double usage = used / (double) (max == -1 || max == Long.MIN_VALUE ? total : max) * 100;
if (Double.isNaN(usage) || Double.isInfinite(usage)) {
usage = 0;
}
table.add(new RowElement().style(style).add(name, format(used), format(total), format(max),
String.format("%.2f%%", usage)));
}
}
}
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.MessageModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
/**
* @author gongdewei 2020/4/2
*/
public class MessageView extends ResultView<MessageModel> {
@Override
public void draw(CommandProcess process, MessageModel result) {
writeln(process, result.getMessage());
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment