classloader command support the classLoaderClass option (#1360)

This commit is contained in:
gongdewei
2020-08-06 11:48:41 +08:00
committed by GitHub
parent 247281b2c5
commit 8d88d2bff5
8 changed files with 169 additions and 15 deletions
@@ -1,6 +1,8 @@
package com.taobao.arthas.core.command.klass100;
import java.lang.instrument.Instrumentation;
import java.util.Collection;
import java.util.List;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
@@ -8,10 +10,12 @@ 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.OgnlModel;
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.middleware.cli.annotations.Argument;
import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Name;
@@ -37,8 +41,8 @@ public class OgnlCommand extends AnnotatedCommand {
private static final Logger logger = LoggerFactory.getLogger(OgnlCommand.class);
private String express;
private String hashCode;
private String classLoaderClass;
private int expand = 1;
@Argument(argName = "express", index = 0, required = true)
@@ -53,6 +57,12 @@ public class OgnlCommand extends AnnotatedCommand {
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 = "x", longName = "expand")
@Description("Expand level of object (1 by default).")
public void setExpand(Integer expand) {
@@ -63,15 +73,30 @@ public class OgnlCommand extends AnnotatedCommand {
public void process(CommandProcess process) {
Instrumentation inst = process.session().getInstrumentation();
ClassLoader classLoader = null;
if (hashCode == null) {
classLoader = ClassLoader.getSystemClassLoader();
} else {
if (hashCode != null) {
classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode);
}
if (classLoader == null) {
process.end(-1, "Can not find classloader with hashCode: " + hashCode + ".");
return;
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);
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
OgnlModel ognlModel = new OgnlModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(ognlModel);
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();
}
Express unpooledExpress = ExpressFactory.unpooledExpress(classLoader);
@@ -1,12 +1,18 @@
package com.taobao.arthas.core.command.model;
import java.util.Collection;
/**
* Data model of OgnlCommand
* @author gongdewei 2020/4/29
*/
public class OgnlModel extends ResultModel {
private Object value;
private int expand = 1;
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
@Override
public String getType() {
@@ -30,4 +36,22 @@ public class OgnlModel extends ResultModel {
this.expand = expand;
return this;
}
public String getClassLoaderClass() {
return classLoaderClass;
}
public OgnlModel setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
return this;
}
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
return matchedClassLoaders;
}
public OgnlModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
}
@@ -11,6 +11,7 @@ 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;
@@ -57,7 +58,7 @@ public class ClassLoaderView extends ResultView<ClassLoaderModel> {
return table;
}
private void drawClassLoaders(CommandProcess process, List<ClassLoaderVO> classLoaders, Boolean isTree) {
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);
@@ -107,7 +108,7 @@ public class ClassLoaderView extends ResultView<ClassLoaderModel> {
}
// 统计所有的ClassLoader的信息
private static TableElement renderTable(List<ClassLoaderVO> classLoaderInfos) {
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) {
@@ -117,7 +118,7 @@ public class ClassLoaderView extends ResultView<ClassLoaderModel> {
}
// 以树状列出ClassLoader的继承结构
private static Element renderTree(List<ClassLoaderVO> classLoaderInfos) {
private static Element renderTree(Collection<ClassLoaderVO> classLoaderInfos) {
TreeElement root = new TreeElement();
for (ClassLoaderVO classLoader : classLoaderInfos) {
TreeElement child = new TreeElement(classLoader.getName());
@@ -6,13 +6,21 @@ import com.taobao.arthas.core.util.StringUtils;
import com.taobao.arthas.core.view.ObjectView;
/**
* Term view of OgnlCommand
* @author gongdewei 2020/4/29
*/
public class OgnlView extends ResultView<OgnlModel> {
@Override
public void draw(CommandProcess process, OgnlModel result) {
int expand = result.getExpand();
Object value = result.getValue();
public void draw(CommandProcess process, OgnlModel model) {
if (model.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, model.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
int expand = model.getExpand();
Object value = model.getValue();
String resultStr = StringUtils.objectToString(expand >= 0 ? new ObjectView(value, expand).draw() : value);
process.write(resultStr).write("\n");
}
@@ -1,7 +1,9 @@
package com.taobao.arthas.core.util;
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
@@ -39,6 +41,26 @@ public class ClassLoaderUtils {
return null;
}
/**
* 通过类名查找classloader
* @param inst
* @param classLoaderClassName
* @return
*/
public static List<ClassLoader> getClassLoaderByClassName(Instrumentation inst, String classLoaderClassName) {
if (classLoaderClassName == null || classLoaderClassName.isEmpty()) {
return null;
}
Set<ClassLoader> classLoaderSet = getAllClassLoader(inst);
List<ClassLoader> matchClassLoaders = new ArrayList<ClassLoader>();
for (ClassLoader classLoader : classLoaderSet) {
if (classLoader.getClass().getName().equals(classLoaderClassName)) {
matchClassLoaders.add(classLoader);
}
}
return matchClassLoaders;
}
public static String classLoaderHash(ClassLoader classLoader) {
int hashCode = 0;
if (classLoader == null) {
@@ -199,6 +199,14 @@ public class ClassUtils {
return classLoaderVO;
}
public static List<ClassLoaderVO> createClassLoaderVOList(Collection<ClassLoader> classLoaders) {
List<ClassLoaderVO> classLoaderVOList = new ArrayList<ClassLoaderVO>();
for (ClassLoader classLoader : classLoaders) {
classLoaderVOList.add(createClassLoaderVO(classLoader));
}
return classLoaderVOList;
}
public static String classLoaderHash(Class<?> clazz) {
if (clazz == null || clazz.getClassLoader() == null) {
return "null";