diff --git a/core/src/main/java/com/taobao/arthas/core/advisor/Enhancer.java b/core/src/main/java/com/taobao/arthas/core/advisor/Enhancer.java index 67bd06001..7656b4c76 100644 --- a/core/src/main/java/com/taobao/arthas/core/advisor/Enhancer.java +++ b/core/src/main/java/com/taobao/arthas/core/advisor/Enhancer.java @@ -72,6 +72,7 @@ public class Enhancer implements ClassFileTransformer { private final boolean isTracing; private final boolean skipJDKTrace; private final Matcher classNameMatcher; + private final Matcher classNameExcludeMatcher; private final Matcher methodNameMatcher; private final EnhancerAffect affect; private Set> matchingClasses = null; @@ -93,11 +94,13 @@ public class Enhancer implements ClassFileTransformer { * @param affect 影响统计 */ public Enhancer(AdviceListener listener, boolean isTracing, boolean skipJDKTrace, Matcher classNameMatcher, + Matcher classNameExcludeMatcher, Matcher methodNameMatcher) { this.listener = listener; this.isTracing = isTracing; this.skipJDKTrace = skipJDKTrace; this.classNameMatcher = classNameMatcher; + this.classNameExcludeMatcher = classNameExcludeMatcher; this.methodNameMatcher = methodNameMatcher; this.affect = new EnhancerAffect(); affect.setListenerId(listener.id()); @@ -308,16 +311,23 @@ public class Enhancer implements ClassFileTransformer { * * @param classes 类集合 */ - private static void filter(Set> classes) { + private void filter(Set> classes) { final Iterator> it = classes.iterator(); while (it.hasNext()) { final Class clazz = it.next(); - if (null == clazz || isSelf(clazz) || isUnsafeClass(clazz) || isUnsupportedClass(clazz)) { + if (null == clazz || isSelf(clazz) || isUnsafeClass(clazz) || isUnsupportedClass(clazz) || isExclude(clazz)) { it.remove(); } } } + private boolean isExclude(Class clazz) { + if (this.classNameExcludeMatcher != null) { + return classNameExcludeMatcher.matching(clazz.getName()); + } + return false; + } + /** * 是否过滤Arthas加载的类 */ diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java index 056543938..fa3c11cf6 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java @@ -1,7 +1,6 @@ package com.taobao.arthas.core.command.monitor200; import java.lang.instrument.Instrumentation; -import java.lang.instrument.UnmodifiableClassException; import java.util.Collections; import java.util.List; @@ -21,8 +20,10 @@ import com.taobao.arthas.core.shell.handlers.shell.QExitHandler; import com.taobao.arthas.core.shell.session.Session; import com.taobao.arthas.core.util.Constants; import com.taobao.arthas.core.util.LogUtil; +import com.taobao.arthas.core.util.SearchUtils; import com.taobao.arthas.core.util.affect.EnhancerAffect; import com.taobao.arthas.core.util.matcher.Matcher; +import com.taobao.middleware.cli.annotations.Argument; import com.taobao.middleware.cli.annotations.Description; import com.taobao.middleware.cli.annotations.Option; @@ -35,14 +36,22 @@ public abstract class EnhancerCommand extends AnnotatedCommand { protected static final List EMPTY = Collections.emptyList(); public static final String[] EXPRESS_EXAMPLES = { "params", "returnObj", "throwExp", "target", "clazz", "method", "{params,returnObj}", "params[0]" }; + private String excludeClassPattern; protected Matcher classNameMatcher; + protected Matcher classNameExcludeMatcher; protected Matcher methodNameMatcher; protected long listenerId; protected boolean verbose; + @Option(longName = "exclude-class-pattern") + @Description("exclude class name pattern, use either '.' or '/' as separator") + public void setExcludeClassPattern(String excludeClassPattern) { + this.excludeClassPattern = excludeClassPattern; + } + @Option(longName = "listenerId") @Description("The special listenerId") public void setListenerId(long listenerId) { @@ -62,6 +71,11 @@ public abstract class EnhancerCommand extends AnnotatedCommand { */ protected abstract Matcher getClassNameMatcher(); + /** + * 排除类名匹配 + */ + protected abstract Matcher getClassNameExcludeMatcher(); + /** * 方法名匹配 * @@ -143,7 +157,7 @@ public abstract class EnhancerCommand extends AnnotatedCommand { skipJDKTrace = ((AbstractTraceAdviceListener) listener).getCommand().isSkipJDKTrace(); } - Enhancer enhancer = new Enhancer(listener, listener instanceof InvokeTraceable, skipJDKTrace, getClassNameMatcher(), getMethodNameMatcher()); + Enhancer enhancer = new Enhancer(listener, listener instanceof InvokeTraceable, skipJDKTrace, getClassNameMatcher(), getClassNameExcludeMatcher(), getMethodNameMatcher()); // 注册通知监听器 process.register(listener, enhancer); effect = enhancer.enhance(inst); @@ -194,4 +208,8 @@ public abstract class EnhancerCommand extends AnnotatedCommand { protected void completeArgument3(Completion completion) { super.complete(completion); } + + public String getExcludeClassPattern() { + return excludeClassPattern; + } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/GroovyScriptCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/GroovyScriptCommand.java index 2abd721ec..5090785dd 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/GroovyScriptCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/GroovyScriptCommand.java @@ -79,6 +79,11 @@ public class GroovyScriptCommand extends EnhancerCommand implements ScriptSuppor throw new UnsupportedOperationException("groovy command is not supported yet!"); } + @Override + protected Matcher getClassNameExcludeMatcher() { + throw new UnsupportedOperationException("groovy command is not supported yet!"); + } + @Override protected Matcher getMethodNameMatcher() { throw new UnsupportedOperationException("groovy command is not supported yet!"); diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/MonitorCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/MonitorCommand.java index 2184a4d0f..0a54e98d0 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/MonitorCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/MonitorCommand.java @@ -115,6 +115,14 @@ public class MonitorCommand extends EnhancerCommand { return classNameMatcher; } + @Override + protected Matcher getClassNameExcludeMatcher() { + if (classNameExcludeMatcher == null) { + classNameExcludeMatcher = SearchUtils.classNameMatcher(getExcludeClassPattern(), isRegEx()); + } + return classNameExcludeMatcher; + } + @Override protected Matcher getMethodNameMatcher() { if (methodNameMatcher == null) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/StackCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/StackCommand.java index d5a721860..6a4bacfa9 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/StackCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/StackCommand.java @@ -93,6 +93,14 @@ public class StackCommand extends EnhancerCommand { return classNameMatcher; } + @Override + protected Matcher getClassNameExcludeMatcher() { + if (classNameExcludeMatcher == null) { + classNameExcludeMatcher = SearchUtils.classNameMatcher(getExcludeClassPattern(), isRegEx()); + } + return classNameExcludeMatcher; + } + @Override protected Matcher getMethodNameMatcher() { if (methodNameMatcher == null) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java index 9a6279eee..d3cab59c6 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java @@ -305,6 +305,14 @@ public class TimeTunnelCommand extends EnhancerCommand { return classNameMatcher; } + @Override + protected Matcher getClassNameExcludeMatcher() { + if (classNameExcludeMatcher == null) { + classNameExcludeMatcher = SearchUtils.classNameMatcher(getExcludeClassPattern(), isRegEx()); + } + return classNameExcludeMatcher; + } + @Override protected Matcher getMethodNameMatcher() { if (methodNameMatcher == null) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceCommand.java index 849b7682f..26b69e750 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TraceCommand.java @@ -38,6 +38,7 @@ import java.util.List; " trace -E com.test.ClassA|org.test.ClassB method1|method2|method3\n" + " trace demo.MathGame run -n 5\n" + " trace demo.MathGame run --skipJDKMethod false\n" + + " trace javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter\n" + Constants.WIKI + Constants.WIKI_HOME + "trace") //@formatter:on public class TraceCommand extends EnhancerCommand { @@ -133,6 +134,14 @@ public class TraceCommand extends EnhancerCommand { return classNameMatcher; } + @Override + protected Matcher getClassNameExcludeMatcher() { + if (classNameExcludeMatcher == null) { + classNameExcludeMatcher = SearchUtils.classNameMatcher(getExcludeClassPattern(), isRegEx()); + } + return classNameExcludeMatcher; + } + @Override protected Matcher getMethodNameMatcher() { if (methodNameMatcher == null) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/WatchCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/WatchCommand.java index 7dd04e678..9bd6c48bb 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/WatchCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/WatchCommand.java @@ -28,6 +28,7 @@ import com.taobao.middleware.cli.annotations.Summary; " watch *StringUtils isBlank params[0] params[0].length==1\n" + " watch *StringUtils isBlank params '#cost>100'\n" + " watch -E -b org\\.apache\\.commons\\.lang\\.StringUtils isBlank params[0]\n" + + " watch javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter\n" + Constants.WIKI + Constants.WIKI_HOME + "watch") public class WatchCommand extends EnhancerCommand { @@ -173,6 +174,14 @@ public class WatchCommand extends EnhancerCommand { return classNameMatcher; } + @Override + protected Matcher getClassNameExcludeMatcher() { + if (classNameExcludeMatcher == null) { + classNameExcludeMatcher = SearchUtils.classNameMatcher(getExcludeClassPattern(), isRegEx()); + } + return classNameExcludeMatcher; + } + @Override protected Matcher getMethodNameMatcher() { if (methodNameMatcher == null) { diff --git a/site/src/site/sphinx/en/trace.md b/site/src/site/sphinx/en/trace.md index 5f84b3c4b..38e10cc9b 100644 --- a/site/src/site/sphinx/en/trace.md +++ b/site/src/site/sphinx/en/trace.md @@ -143,6 +143,16 @@ Trace -E com.test.ClassA|org.test.ClassB method1|method2|method3 ``` +#### Exclude the specified class + +> The watch/trace/monitor/stack/tt commands all support the `--exclude-class-pattern` parameter + +Use the `--exclude-class-pattern` parameter to exclude the specified class, for example: + +```bash +watch javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter +``` + #### Dynamic trace > Supported since version 3.3.0. diff --git a/site/src/site/sphinx/en/watch.md b/site/src/site/sphinx/en/watch.md index eaaa7fc02..c1d67bcde 100644 --- a/site/src/site/sphinx/en/watch.md +++ b/site/src/site/sphinx/en/watch.md @@ -236,6 +236,24 @@ ts=2018-12-03 20:04:35; [cost=0.961441ms] result=@Integer[8] ``` +#### Exclude the specified class + +> The watch/trace/monitor/stack/tt commands all support the `--exclude-class-pattern` parameter + +Use the `--exclude-class-pattern` parameter to exclude the specified class, for example: + +```bash +watch javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter +``` +#### Does not match subclass + +By default, the watch/trace/monitor/stack/tt commands will match subclass. If you don't want to match, you can turn it off. + +```bash +options disable-sub-class true +``` + + #### Use the -v parameter to print more information > The watch/trace/monitor/stack/tt commands all support the `-v` parameter. diff --git a/site/src/site/sphinx/trace.md b/site/src/site/sphinx/trace.md index fd4ddfa51..d72d447ba 100644 --- a/site/src/site/sphinx/trace.md +++ b/site/src/site/sphinx/trace.md @@ -148,6 +148,14 @@ trace命令只会trace匹配到的函数里的子调用,并不会向下trace trace -E com.test.ClassA|org.test.ClassB method1|method2|method3 ``` +#### 排除掉指定的类 + +使用 `--exclude-class-pattern` 参数可以排除掉指定的类,比如: + +```bash +trace javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter +``` + ### 动态trace > 3.3.0 版本后支持。 diff --git a/site/src/site/sphinx/watch.md b/site/src/site/sphinx/watch.md index a413a7c74..e843dbc7f 100644 --- a/site/src/site/sphinx/watch.md +++ b/site/src/site/sphinx/watch.md @@ -235,6 +235,23 @@ ts=2018-12-03 20:04:34; [cost=131.303498ms] result=@Integer[8] ts=2018-12-03 20:04:35; [cost=0.961441ms] result=@Integer[8] ``` +#### 排除掉指定的类 + +> watch/trace/monitor/stack/tt 命令都支持 `--exclude-class-pattern` 参数 + +使用 `--exclude-class-pattern` 参数可以排除掉指定的类,比如: + +```bash +watch javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter +``` +#### 不匹配子类 + +默认情况下 watch/trace/monitor/stack/tt 命令都会匹配子类。如果想不匹配,可以通过全局参数关掉。 + +```bash +options disable-sub-class true +``` + #### 使用 -v 参数打印更多信息 > watch/trace/monitor/stack/tt 命令都支持 `-v` 参数