Add --classLoaderClass for sc/sm (#1433)

This commit is contained in:
Hollow Man
2020-08-18 14:00:52 +08:00
committed by GitHub
parent 1bfda2b827
commit ea262bd52b
10 changed files with 120 additions and 1 deletions
@@ -3,6 +3,7 @@ package com.taobao.arthas.core.command.klass100;
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -11,11 +12,13 @@ import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.ClassDetailVO;
import com.taobao.arthas.core.command.model.SearchClassModel;
import com.taobao.arthas.core.command.model.RowAffectModel;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.shell.cli.Completion;
import com.taobao.arthas.core.shell.cli.CompletionUtils;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.ResultUtils;
import com.taobao.arthas.core.util.SearchUtils;
import com.taobao.arthas.core.util.StringUtils;
@@ -46,6 +49,7 @@ public class SearchClassCommand extends AnnotatedCommand {
private boolean isField = false;
private boolean isRegEx = false;
private String hashCode = null;
private String classLoaderClass;
private Integer expand;
private int numberOfLimit = 100;
@@ -85,6 +89,12 @@ public class SearchClassCommand 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 = "n", longName = "limits")
@Description("Maximum number of matching classes with details (100 by default)")
public void setNumberOfLimit(int numberOfLimit) {
@@ -96,6 +106,25 @@ public class SearchClassCommand extends AnnotatedCommand {
// TODO: null check
RowAffect affect = new RowAffect();
Instrumentation inst = process.session().getInstrumentation();
if (hashCode == null && classLoaderClass != null) {
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
if (matchedClassLoaders.size() == 1) {
hashCode = Integer.toHexString(matchedClassLoaders.get(0).hashCode());
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
SearchClassModel searchclassModel = new SearchClassModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(searchclassModel);
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;
}
}
List<Class<?>> matchedClasses = new ArrayList<Class<?>>(SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode));
Collections.sort(matchedClasses, new Comparator<Class<?>>() {
@Override
@@ -5,6 +5,8 @@ import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.Collection;
import java.util.List;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
@@ -12,11 +14,13 @@ import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.SearchMethodModel;
import com.taobao.arthas.core.command.model.MethodVO;
import com.taobao.arthas.core.command.model.RowAffectModel;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.shell.cli.Completion;
import com.taobao.arthas.core.shell.cli.CompletionUtils;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.SearchUtils;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.arthas.core.util.affect.RowAffect;
@@ -50,6 +54,7 @@ public class SearchMethodCommand extends AnnotatedCommand {
private String classPattern;
private String methodPattern;
private String hashCode = null;
private String classLoaderClass;
private boolean isDetail = false;
private boolean isRegEx = false;
private int numberOfLimit = 100;
@@ -84,6 +89,12 @@ public class SearchMethodCommand 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 = "n", longName = "limits")
@Description("Maximum number of matching classes (100 by default)")
public void setNumberOfLimit(int numberOfLimit) {
@@ -96,6 +107,25 @@ public class SearchMethodCommand extends AnnotatedCommand {
Instrumentation inst = process.session().getInstrumentation();
Matcher<String> methodNameMatcher = methodNameMatcher();
if (hashCode == null && classLoaderClass != null) {
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
if (matchedClassLoaders.size() == 1) {
hashCode = Integer.toHexString(matchedClassLoaders.get(0).hashCode());
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
SearchMethodModel searchmethodModel = new SearchMethodModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(searchmethodModel);
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;
}
}
Set<Class<?>> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode);
if (numberOfLimit > 0 && matchedClasses.size() > numberOfLimit) {
@@ -1,6 +1,6 @@
package com.taobao.arthas.core.command.model;
import java.util.Collection;
import java.util.List;
/**
@@ -15,6 +15,9 @@ public class SearchClassModel extends ResultModel {
private List<String> classNames;
private int segment;
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
public SearchClassModel() {
}
@@ -70,4 +73,22 @@ public class SearchClassModel extends ResultModel {
public Integer getExpand() {
return expand;
}
public String getClassLoaderClass() {
return classLoaderClass;
}
public SearchClassModel setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
return this;
}
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
return matchedClassLoaders;
}
public SearchClassModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
}
@@ -1,5 +1,6 @@
package com.taobao.arthas.core.command.model;
import java.util.Collection;
/**
* Model of SearchMethodCommand
@@ -9,6 +10,9 @@ public class SearchMethodModel extends ResultModel {
private MethodVO methodInfo;
private boolean detail;
private Collection<ClassLoaderVO> matchedClassLoaders;
private String classLoaderClass;
public SearchMethodModel() {
}
@@ -33,6 +37,24 @@ public class SearchMethodModel extends ResultModel {
this.detail = detail;
}
public String getClassLoaderClass() {
return classLoaderClass;
}
public SearchMethodModel setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
return this;
}
public Collection<ClassLoaderVO> getMatchedClassLoaders() {
return matchedClassLoaders;
}
public SearchMethodModel setMatchedClassLoaders(Collection<ClassLoaderVO> matchedClassLoaders) {
this.matchedClassLoaders = matchedClassLoaders;
return this;
}
@Override
public String getType() {
return "sm";
@@ -11,6 +11,12 @@ import com.taobao.text.util.RenderUtil;
public class SearchClassView extends ResultView<SearchClassModel> {
@Override
public void draw(CommandProcess process, SearchClassModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
if (result.isDetailed()) {
process.write(RenderUtil.render(ClassUtils.renderClassInfo(result.getClassInfo(),
@@ -14,6 +14,13 @@ import com.taobao.text.util.RenderUtil;
public class SearchMethodView extends ResultView<SearchMethodModel> {
@Override
public void draw(CommandProcess process, SearchMethodModel result) {
if (result.getMatchedClassLoaders() != null) {
process.write("Matched classloaders: \n");
ClassLoaderView.drawClassLoaders(process, result.getMatchedClassLoaders(), false);
process.write("\n");
return;
}
boolean detail = result.isDetail();
MethodVO methodInfo = result.getMethodInfo();
+1
View File
@@ -18,6 +18,7 @@ sc
|`[f]`|print the fields info of the current class, MUST be used with `-d` together|
|`[x:]`|specify the depth of recursive traverse the static fields, the default value is '0' - equivalent to use `toString` to output|
|`[c:]`|The hash code of the special class's classLoader|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|`[n:]`|Maximum number of matching classes with details (100 by default)|
> *class-patten* supports full qualified class name, e.g. com.taobao.test.AAA and com/taobao/test/AAA. It also supports the format of 'com/taobao/test/AAA', so that it is convenient to directly copy class name from the exception stack trace without replacing '/' to '.'. <br/><br/>
+1
View File
@@ -17,6 +17,7 @@ sm
|`[d]`|print the details of the method|
|`[E]`|turn on regex matching while the default mode is wildcard matching|
|`[c:]`|The hash code of the special class's classLoader|
|`[classLoaderClass:]`| The class name of the ClassLoader that executes the expression. |
|`[n:]`|Maximum number of matching classes with details (100 by default)|
### Usage
+1
View File
@@ -21,6 +21,7 @@ sc
|[f]|输出当前类的成员变量信息(需要配合参数-d一起使用)|
|[x:]|指定输出静态变量时属性的遍历深度,默认为 0,即直接使用 `toString` 输出|
|`[c:]`|指定class的 ClassLoader 的 hashcode|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|`[n:]`|具有详细信息的匹配类的最大数量(默认为100)|
> class-pattern支持全限定名,如com.taobao.test.AAA,也支持com/taobao/test/AAA这样的格式,这样,我们从异常堆栈里面把类名拷贝过来的时候,不需要在手动把`/`替换为`.`啦。
+1
View File
@@ -18,6 +18,7 @@ sm
|[d]|展示每个方法的详细信息|
|[E]|开启正则表达式匹配,默认为通配符匹配|
|`[c:]`|指定class的 ClassLoader 的 hashcode|
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|`[n:]`|具有详细信息的匹配类的最大数量(默认为100)|
### 使用参考