mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
classloader command support the classLoaderClass option (#1360)
This commit is contained in:
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user