Commit 7c094a26 authored by liang.tang's avatar liang.tang
Browse files

arthas-master

parents
Pipeline #220 failed with stages
in 0 seconds
package com.taobao.arthas.core.command.basic1000;
import com.taobao.arthas.core.advisor.Enhancer;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.ResetModel;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.matcher.Matcher;
import com.taobao.arthas.core.util.SearchUtils;
import com.taobao.arthas.core.util.affect.EnhancerAffect;
import com.taobao.middleware.cli.annotations.Argument;
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 java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
/**
* 恢复所有增强类<br/>
*
* @author vlinux on 15/5/29.
*/
@Name("reset")
@Summary("Reset all the enhanced classes")
@Description(Constants.EXAMPLE +
" reset\n" +
" reset *List\n" +
" reset -E .*List\n")
public class ResetCommand extends AnnotatedCommand {
private String classPattern;
private boolean isRegEx = false;
@Argument(index = 0, argName = "class-pattern", required = false)
@Description("Path and classname of Pattern Matching")
public void setClassPattern(String classPattern) {
this.classPattern = classPattern;
}
@Option(shortName = "E", longName = "regex", flag = true)
@Description("Enable regular expression to match (wildcard matching by default)")
public void setRegEx(boolean regEx) {
isRegEx = regEx;
}
@Override
public void process(CommandProcess process) {
Instrumentation inst = process.session().getInstrumentation();
Matcher matcher = SearchUtils.classNameMatcher(classPattern, isRegEx);
try {
EnhancerAffect enhancerAffect = Enhancer.reset(inst, matcher);
process.appendResult(new ResetModel(enhancerAffect));
process.end();
} catch (UnmodifiableClassException e) {
// ignore
process.end();
}
}
}
package com.taobao.arthas.core.command.basic1000;
import com.taobao.arthas.core.command.model.SessionModel;
import com.taobao.arthas.core.server.ArthasBootstrap;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.shell.session.Session;
import com.taobao.arthas.core.util.UserStatUtil;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
import com.alibaba.arthas.tunnel.client.TunnelClient;
/**
* 查看会话状态命令
*
* @author vlinux on 15/5/3.
*/
@Name("session")
@Summary("Display current session information")
public class SessionCommand extends AnnotatedCommand {
@Override
public void process(CommandProcess process) {
SessionModel result = new SessionModel();
Session session = process.session();
result.setJavaPid(session.getPid());
result.setSessionId(session.getSessionId());
//tunnel
TunnelClient tunnelClient = ArthasBootstrap.getInstance().getTunnelClient();
if (tunnelClient != null) {
String id = tunnelClient.getId();
if (id != null) {
result.setAgentId(id);
}
result.setTunnelServer(tunnelClient.getTunnelServerUrl());
result.setTunnelConnected(tunnelClient.isConnected());
}
//statUrl
String statUrl = UserStatUtil.getStatUrl();
result.setStatUrl(statUrl);
process.appendResult(result);
process.end();
}
}
package com.taobao.arthas.core.command.basic1000;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.core.command.model.MessageModel;
import com.taobao.arthas.core.command.model.ResetModel;
import com.taobao.arthas.core.command.model.ShutdownModel;
import com.taobao.arthas.core.server.ArthasBootstrap;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.affect.EnhancerAffect;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
* @author hengyunabc 2019-07-05
*/
@Name("stop")
@Summary("Stop/Shutdown Arthas server and exit the console.")
public class StopCommand extends AnnotatedCommand {
private static final Logger logger = LoggerFactory.getLogger(StopCommand.class);
@Override
public void process(CommandProcess process) {
shutdown(process);
}
private static void shutdown(CommandProcess process) {
ArthasBootstrap arthasBootstrap = ArthasBootstrap.getInstance();
try {
// 退出之前需要重置所有的增强类
process.appendResult(new MessageModel("Resetting all enhanced classes ..."));
EnhancerAffect enhancerAffect = arthasBootstrap.reset();
process.appendResult(new ResetModel(enhancerAffect));
process.appendResult(new ShutdownModel(true, "Arthas Server is going to shutdown..."));
} catch (Throwable e) {
logger.error("An error occurred when stopping arthas server.", e);
process.appendResult(new ShutdownModel(false, "An error occurred when stopping arthas server."));
} finally {
process.end();
arthasBootstrap.destroy();
}
}
}
package com.taobao.arthas.core.command.basic1000;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.SystemEnvModel;
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.StringUtils;
import com.taobao.middleware.cli.annotations.Argument;
import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
* @author hengyunabc 2018-11-09
*
*/
@Name("sysenv")
@Summary("Display the system env.")
@Description(Constants.EXAMPLE + " sysenv\n" + " sysenv USER\n" + Constants.WIKI + Constants.WIKI_HOME + "sysenv")
public class SystemEnvCommand extends AnnotatedCommand {
private String envName;
@Argument(index = 0, argName = "env-name", required = false)
@Description("env name")
public void setOptionName(String envName) {
this.envName = envName;
}
@Override
public void process(CommandProcess process) {
try {
SystemEnvModel result = new SystemEnvModel();
if (StringUtils.isBlank(envName)) {
// show all system env
result.putAll(System.getenv());
} else {
// view the specified system env
String value = System.getenv(envName);
result.put(envName, value);
}
process.appendResult(result);
process.end();
} catch (Throwable t) {
process.end(-1, "Error during setting system env: " + t.getMessage());
}
}
/**
* First, try to complete with the sysenv command scope. If completion is
* failed, delegates to super class.
*
* @param completion
* the completion object
*/
@Override
public void complete(Completion completion) {
CompletionUtils.complete(completion, System.getenv().keySet());
}
}
package com.taobao.arthas.core.command.basic1000;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.MessageModel;
import com.taobao.arthas.core.command.model.SystemPropertyModel;
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.StringUtils;
import com.taobao.middleware.cli.annotations.Argument;
import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
* @author ralf0131 2017-01-09 14:03.
*/
@Name("sysprop")
@Summary("Display, and change the system properties.")
@Description(Constants.EXAMPLE + " sysprop\n"+ " sysprop file.encoding\n" + " sysprop production.mode true\n" +
Constants.WIKI + Constants.WIKI_HOME + "sysprop")
public class SystemPropertyCommand extends AnnotatedCommand {
private String propertyName;
private String propertyValue;
@Argument(index = 0, argName = "property-name", required = false)
@Description("property name")
public void setOptionName(String propertyName) {
this.propertyName = propertyName;
}
@Argument(index = 1, argName = "property-value", required = false)
@Description("property value")
public void setOptionValue(String propertyValue) {
this.propertyValue = propertyValue;
}
@Override
public void process(CommandProcess process) {
try {
if (StringUtils.isBlank(propertyName) && StringUtils.isBlank(propertyValue)) {
// show all system properties
process.appendResult(new SystemPropertyModel(System.getProperties()));
} else if (StringUtils.isBlank(propertyValue)) {
// view the specified system property
String value = System.getProperty(propertyName);
if (value == null) {
process.end(1, "There is no property with the key " + propertyName);
return;
} else {
process.appendResult(new SystemPropertyModel(propertyName, value));
}
} else {
// change system property
System.setProperty(propertyName, propertyValue);
process.appendResult(new MessageModel("Successfully changed the system property."));
process.appendResult(new SystemPropertyModel(propertyName, System.getProperty(propertyName)));
}
process.end();
} catch (Throwable t) {
process.end(-1, "Error during setting system property: " + t.getMessage());
}
}
/**
* First, try to complete with the sysprop command scope.
* If completion is failed, delegates to super class.
* @param completion the completion object
*/
@Override
public void complete(Completion completion) {
CompletionUtils.complete(completion, System.getProperties().stringPropertyNames());
}
}
package com.taobao.arthas.core.command.basic1000;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.middleware.cli.annotations.*;
/**
* @author min.yang
*/
@Name("tee")
@Summary("tee command for pipes." )
@Description(Constants.EXAMPLE +
" sysprop | tee /path/to/logfile | grep java \n" +
" sysprop | tee -a /path/to/logfile | grep java \n"
+ Constants.WIKI + Constants.WIKI_HOME + "tee")
public class TeeCommand extends AnnotatedCommand {
private String filePath;
private boolean append;
@Argument(index = 0, argName = "file", required = false)
@Description("File path")
public void setFilePath(String filePath) {
this.filePath = filePath;
}
@Option(shortName = "a", longName = "append", flag = true)
@Description("Append to file")
public void setRegEx(boolean append) {
this.append = append;
}
@Override
public void process(CommandProcess process) {
process.end(-1, "The tee command only for pipes. See 'tee --help'");
}
public String getFilePath() {
return filePath;
}
public boolean isAppend() {
return append;
}
}
package com.taobao.arthas.core.command.basic1000;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.sun.management.HotSpotDiagnosticMXBean;
import com.sun.management.VMOption;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.ChangeResultVO;
import com.taobao.arthas.core.command.model.MessageModel;
import com.taobao.arthas.core.command.model.VMOptionModel;
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.StringUtils;
import com.taobao.middleware.cli.annotations.Argument;
import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
* vmoption command
*
* @author hengyunabc 2019-09-02
*
*/
// @formatter:off
@Name("vmoption")
@Summary("Display, and update the vm diagnostic options.")
@Description("\nExamples:\n" +
" vmoption\n" +
" vmoption PrintGC\n" +
" vmoption PrintGC true\n" +
" vmoption PrintGCDetails true\n" +
Constants.WIKI + Constants.WIKI_HOME + "vmoption")
//@formatter:on
public class VMOptionCommand extends AnnotatedCommand {
private static final Logger logger = LoggerFactory.getLogger(VMOptionCommand.class);
private String name;
private String value;
@Argument(index = 0, argName = "name", required = false)
@Description("VMOption name")
public void setOptionName(String name) {
this.name = name;
}
@Argument(index = 1, argName = "value", required = false)
@Description("VMOption value")
public void setOptionValue(String value) {
this.value = value;
}
@Override
public void process(CommandProcess process) {
run(process, name, value);
}
private static void run(CommandProcess process, String name, String value) {
try {
HotSpotDiagnosticMXBean hotSpotDiagnosticMXBean = ManagementFactory
.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
if (StringUtils.isBlank(name) && StringUtils.isBlank(value)) {
// show all options
process.appendResult(new VMOptionModel(hotSpotDiagnosticMXBean.getDiagnosticOptions()));
} else if (StringUtils.isBlank(value)) {
// view the specified option
VMOption option = hotSpotDiagnosticMXBean.getVMOption(name);
if (option == null) {
process.end(-1, "In order to change the system properties, you must specify the property value.");
return;
} else {
process.appendResult(new VMOptionModel(Collections.singletonList(option)));
}
} else {
VMOption vmOption = hotSpotDiagnosticMXBean.getVMOption(name);
String originValue = vmOption.getValue();
// change vm option
hotSpotDiagnosticMXBean.setVMOption(name, value);
process.appendResult(new MessageModel("Successfully updated the vm option."));
process.appendResult(new VMOptionModel(new ChangeResultVO(name, originValue,
hotSpotDiagnosticMXBean.getVMOption(name).getValue())));
}
process.end();
} catch (Throwable t) {
logger.error("Error during setting vm option", t);
process.end(-1, "Error during setting vm option: " + t.getMessage());
}
}
@Override
public void complete(Completion completion) {
HotSpotDiagnosticMXBean hotSpotDiagnosticMXBean = ManagementFactory
.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
List<VMOption> diagnosticOptions = hotSpotDiagnosticMXBean.getDiagnosticOptions();
List<String> names = new ArrayList<String>(diagnosticOptions.size());
for (VMOption option : diagnosticOptions) {
names.add(option.getName());
}
CompletionUtils.complete(completion, names);
}
}
package com.taobao.arthas.core.command.basic1000;
import com.taobao.arthas.core.command.model.VersionModel;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ArthasBanner;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
* 输出版本
*
* @author vlinux
*/
@Name("version")
@Summary("Display Arthas version")
public class VersionCommand extends AnnotatedCommand {
@Override
public void process(CommandProcess process) {
VersionModel result = new VersionModel();
result.setVersion(ArthasBanner.version());
process.appendResult(result);
process.end();
}
}
package com.taobao.arthas.core.command.express;
import java.util.Map;
import com.taobao.arthas.core.GlobalOptions;
import ognl.ObjectPropertyAccessor;
import ognl.OgnlException;
/**
*
* @author hengyunabc 2022-03-24
*
*/
public class ArthasObjectPropertyAccessor extends ObjectPropertyAccessor {
@Override
public Object setPossibleProperty(Map context, Object target, String name, Object value) throws OgnlException {
if (GlobalOptions.strict) {
throw new IllegalAccessError(GlobalOptions.STRICT_MESSAGE);
}
return super.setPossibleProperty(context, target, name, value);
}
}
package com.taobao.arthas.core.command.express;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import ognl.ClassResolver;
/**
*
* @author hengyunabc 2018-10-18
* @see ognl.DefaultClassResolver
*/
public class ClassLoaderClassResolver implements ClassResolver {
private ClassLoader classLoader;
private Map<String, Class<?>> classes = new ConcurrentHashMap<String, Class<?>>(101);
public ClassLoaderClassResolver(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public Class<?> classForName(String className, @SuppressWarnings("rawtypes") Map context)
throws ClassNotFoundException {
Class<?> result = null;
if ((result = classes.get(className)) == null) {
try {
result = classLoader.loadClass(className);
} catch (ClassNotFoundException ex) {
if (className.indexOf('.') == -1) {
result = Class.forName("java.lang." + className);
classes.put("java.lang." + className, result);
}
}
if (result == null) {
return null;
}
classes.put(className, result);
}
return result;
}
}
package com.taobao.arthas.core.command.express;
import ognl.ClassResolver;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author diecui1202 on 2017/9/29.
* @see ognl.DefaultClassResolver
*/
public class CustomClassResolver implements ClassResolver {
public static final CustomClassResolver customClassResolver = new CustomClassResolver();
private Map<String, Class<?>> classes = new ConcurrentHashMap<String, Class<?>>(101);
private CustomClassResolver() {
}
public Class<?> classForName(String className, Map context) throws ClassNotFoundException {
Class<?> result = null;
if ((result = classes.get(className)) == null) {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null) {
result = classLoader.loadClass(className);
} else {
result = Class.forName(className);
}
} catch (ClassNotFoundException ex) {
if (className.indexOf('.') == -1) {
result = Class.forName("java.lang." + className);
classes.put("java.lang." + className, result);
}
}
classes.put(className, result);
}
return result;
}
}
package com.taobao.arthas.core.command.express;
/**
* 表达式
* Created by vlinux on 15/5/20.
*/
public interface Express {
/**
* 根据表达式获取值
*
* @param express 表达式
* @return 表达式运算后的值
* @throws ExpressException 表达式运算出错
*/
Object get(String express) throws ExpressException;
/**
* 根据表达式判断是与否
*
* @param express 表达式
* @return 表达式运算后的布尔值
* @throws ExpressException 表达式运算出错
*/
boolean is(String express) throws ExpressException;
/**
* 绑定对象
*
* @param object 待绑定对象
* @return this
*/
Express bind(Object object);
/**
* 绑定变量
*
* @param name 变量名
* @param value 变量值
* @return this
*/
Express bind(String name, Object value);
/**
* 重置整个表达式
*
* @return this
*/
Express reset();
}
package com.taobao.arthas.core.command.express;
/**
* 表达式异常
* Created by vlinux on 15/5/20.
*/
public class ExpressException extends Exception {
private final String express;
/**
* 表达式异常
*
* @param express 原始表达式
* @param cause 异常原因
*/
public ExpressException(String express, Throwable cause) {
super(cause);
this.express = express;
}
/**
* 获取表达式
*
* @return 返回出问题的表达式
*/
public String getExpress() {
return express;
}
}
package com.taobao.arthas.core.command.express;
/**
* ExpressFactory
* @author ralf0131 2017-01-04 14:40.
* @author hengyunabc 2018-10-08
*/
public class ExpressFactory {
private static final ThreadLocal<Express> expressRef = new ThreadLocal<Express>() {
@Override
protected Express initialValue() {
return new OgnlExpress();
}
};
/**
* get ThreadLocal Express Object
* @param object
* @return
*/
public static Express threadLocalExpress(Object object) {
return expressRef.get().reset().bind(object);
}
public static Express unpooledExpress(ClassLoader classloader) {
if (classloader == null) {
classloader = ClassLoader.getSystemClassLoader();
}
return new OgnlExpress(new ClassLoaderClassResolver(classloader));
}
}
\ No newline at end of file
package com.taobao.arthas.core.command.express;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import ognl.ClassResolver;
import ognl.DefaultMemberAccess;
import ognl.MemberAccess;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlRuntime;
/**
* @author ralf0131 2017-01-04 14:41.
* @author hengyunabc 2018-10-18
*/
public class OgnlExpress implements Express {
private static final MemberAccess MEMBER_ACCESS = new DefaultMemberAccess(true);
private static final Logger logger = LoggerFactory.getLogger(OgnlExpress.class);
private static final ArthasObjectPropertyAccessor OBJECT_PROPERTY_ACCESSOR = new ArthasObjectPropertyAccessor();
private Object bindObject;
private final OgnlContext context;
public OgnlExpress() {
this(CustomClassResolver.customClassResolver);
}
public OgnlExpress(ClassResolver classResolver) {
OgnlRuntime.setPropertyAccessor(Object.class, OBJECT_PROPERTY_ACCESSOR);
context = new OgnlContext();
context.setClassResolver(classResolver);
// allow private field access
context.setMemberAccess(MEMBER_ACCESS);
}
@Override
public Object get(String express) throws ExpressException {
try {
return Ognl.getValue(express, context, bindObject);
} catch (Exception e) {
logger.error("Error during evaluating the expression:", e);
throw new ExpressException(express, e);
}
}
@Override
public boolean is(String express) throws ExpressException {
final Object ret = get(express);
return ret instanceof Boolean && (Boolean) ret;
}
@Override
public Express bind(Object object) {
this.bindObject = object;
return this;
}
@Override
public Express bind(String name, Object value) {
context.put(name, value);
return this;
}
@Override
public Express reset() {
context.clear();
context.setClassResolver(CustomClassResolver.customClassResolver);
// allow private field access
context.setMemberAccess(MEMBER_ACCESS);
return this;
}
}
package com.taobao.arthas.core.command.hidden;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.middleware.cli.annotations.Hidden;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
* @author vlinux on 02/11/2016.
*/
@Name("july")
@Summary("don't ask why")
@Hidden
public class JulyCommand extends AnnotatedCommand {
@Override
public void process(CommandProcess process) {
process.write(new String($$())).write("\n").end();
}
private static byte[] $$() {
return new byte[]{
0x49, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x6d, 0x69, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74,
0x20, 0x79, 0x6f, 0x75, 0x20, 0x64, 0x69, 0x64, 0x0a, 0x49, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x6e, 0x6f, 0x74,
0x20, 0x6c, 0x65, 0x74, 0x20, 0x6d, 0x79, 0x73, 0x65, 0x6c, 0x66, 0x0a, 0x43, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6d,
0x79, 0x20, 0x68, 0x65, 0x61, 0x72, 0x74, 0x20, 0x73, 0x6f, 0x20, 0x6d, 0x75, 0x63, 0x68, 0x20, 0x6d, 0x69, 0x73,
0x65, 0x72, 0x79, 0x0a, 0x49, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x72, 0x65, 0x61,
0x6b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x64, 0x69, 0x64, 0x0a, 0x59,
0x6f, 0x75, 0x20, 0x66, 0x65, 0x6c, 0x6c, 0x20, 0x73, 0x6f, 0x20, 0x68, 0x61, 0x72, 0x64, 0x0a, 0x0a, 0x49, 0x20,
0x76, 0x65, 0x20, 0x6c, 0x65, 0x61, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x72, 0x64,
0x20, 0x77, 0x61, 0x79, 0x0a, 0x54, 0x6f, 0x20, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x69,
0x74, 0x20, 0x67, 0x65, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x66, 0x61, 0x72, 0x0a, 0x0a, 0x42, 0x65, 0x63,
0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x0a, 0x49, 0x20, 0x6e, 0x65, 0x76, 0x65, 0x72,
0x20, 0x73, 0x74, 0x72, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x6f, 0x20, 0x66, 0x61, 0x72, 0x20, 0x66, 0x72, 0x6f, 0x6d,
0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 0x64, 0x65, 0x77, 0x61, 0x6c, 0x6b, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75,
0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x0a, 0x49, 0x20, 0x6c, 0x65, 0x61, 0x72, 0x6e, 0x65, 0x64,
0x20, 0x74, 0x6f, 0x20, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x66,
0x65, 0x20, 0x73, 0x69, 0x64, 0x65, 0x20, 0x73, 0x6f, 0x20, 0x49, 0x20, 0x64, 0x6f, 0x6e, 0x20, 0x74, 0x20, 0x67,
0x65, 0x74, 0x20, 0x68, 0x75, 0x72, 0x74, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20,
0x79, 0x6f, 0x75, 0x0a, 0x49, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, 0x72, 0x64, 0x20,
0x74, 0x6f, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6d,
0x65, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x6f, 0x6e, 0x65, 0x20, 0x61, 0x72, 0x6f,
0x75, 0x6e, 0x64, 0x20, 0x6d, 0x65, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79,
0x6f, 0x75, 0x0a, 0x49, 0x20, 0x61, 0x6d, 0x20, 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, 0x0a, 0x0a, 0x49, 0x20, 0x6c,
0x6f, 0x73, 0x65, 0x20, 0x6d, 0x79, 0x20, 0x77, 0x61, 0x79, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x73,
0x20, 0x6e, 0x6f, 0x74, 0x20, 0x74, 0x6f, 0x6f, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72,
0x65, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6f, 0x75, 0x74, 0x0a,
0x49, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x72, 0x79, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73,
0x65, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x20, 0x77,
0x65, 0x61, 0x6b, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x65, 0x79, 0x65,
0x73, 0x0a, 0x49, 0x20, 0x6d, 0x20, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x61, 0x6b,
0x65, 0x0a, 0x41, 0x20, 0x73, 0x6d, 0x69, 0x6c, 0x65, 0x2c, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x75, 0x67, 0x68, 0x20,
0x65, 0x76, 0x65, 0x72, 0x79, 0x64, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x6d, 0x79, 0x20, 0x6c, 0x69, 0x66, 0x65,
0x0a, 0x4d, 0x79, 0x20, 0x68, 0x65, 0x61, 0x72, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x27, 0x74, 0x20, 0x70, 0x6f, 0x73,
0x73, 0x69, 0x62, 0x6c, 0x79, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x0a, 0x57, 0x68, 0x65, 0x6e, 0x20, 0x69, 0x74,
0x20, 0x77, 0x61, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, 0x77, 0x68, 0x6f, 0x6c, 0x65, 0x20,
0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0a, 0x0a, 0x42, 0x65, 0x63, 0x61,
0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x0a, 0x49, 0x20, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x20,
0x73, 0x74, 0x72, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x6f, 0x20, 0x66, 0x61, 0x72, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20,
0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 0x64, 0x65, 0x77, 0x61, 0x6c, 0x6b, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73,
0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x0a, 0x49, 0x20, 0x6c, 0x65, 0x61, 0x72, 0x6e, 0x65, 0x64, 0x20,
0x74, 0x6f, 0x20, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x66, 0x65,
0x20, 0x73, 0x69, 0x64, 0x65, 0x20, 0x73, 0x6f, 0x20, 0x49, 0x20, 0x64, 0x6f, 0x6e, 0x20, 0x74, 0x20, 0x67, 0x65,
0x74, 0x20, 0x68, 0x75, 0x72, 0x74, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79,
0x6f, 0x75, 0x0a, 0x49, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, 0x72, 0x64, 0x20, 0x74,
0x6f, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6d, 0x65,
0x2c, 0x20, 0x62, 0x75, 0x74, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x6f, 0x6e, 0x65, 0x20, 0x61, 0x72, 0x6f, 0x75,
0x6e, 0x64, 0x20, 0x6d, 0x65, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f,
0x75, 0x0a, 0x49, 0x20, 0x61, 0x6d, 0x20, 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, 0x0a, 0x0a, 0x49, 0x20, 0x77, 0x61,
0x74, 0x63, 0x68, 0x65, 0x64, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x64, 0x69, 0x65, 0x0a, 0x49, 0x20, 0x68, 0x65, 0x61,
0x72, 0x64, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x72, 0x79, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6e, 0x69,
0x67, 0x68, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x49,
0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x6f, 0x20, 0x79, 0x6f, 0x75, 0x6e, 0x67, 0x0a, 0x59, 0x6f, 0x75, 0x20, 0x73,
0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x62, 0x65,
0x74, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x65, 0x61, 0x6e, 0x20, 0x6f,
0x6e, 0x20, 0x6d, 0x65, 0x0a, 0x59, 0x6f, 0x75, 0x20, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x6f, 0x75,
0x67, 0x68, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x79, 0x6f, 0x6e, 0x65, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a,
0x59, 0x6f, 0x75, 0x20, 0x6a, 0x75, 0x73, 0x74, 0x20, 0x73, 0x61, 0x77, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x70,
0x61, 0x69, 0x6e, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x49, 0x20, 0x63, 0x72, 0x79, 0x20, 0x69,
0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65,
0x20, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x0a, 0x46, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65,
0x20, 0x64, 0x61, 0x6d, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x0a, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73,
0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x0a, 0x49, 0x20, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x20, 0x73, 0x74,
0x72, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x6f, 0x20, 0x66, 0x61, 0x72, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x69, 0x64, 0x65, 0x77, 0x61, 0x6c, 0x6b, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20,
0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x0a, 0x49, 0x20, 0x6c, 0x65, 0x61, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f,
0x20, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x66, 0x65, 0x20, 0x73,
0x69, 0x64, 0x65, 0x20, 0x73, 0x6f, 0x20, 0x49, 0x20, 0x64, 0x6f, 0x6e, 0x20, 0x74, 0x20, 0x67, 0x65, 0x74, 0x20,
0x68, 0x75, 0x72, 0x74, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75,
0x0a, 0x49, 0x20, 0x74, 0x72, 0x79, 0x20, 0x6d, 0x79, 0x20, 0x68, 0x61, 0x72, 0x64, 0x65, 0x73, 0x74, 0x20, 0x6a,
0x75, 0x73, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79,
0x74, 0x68, 0x69, 0x6e, 0x67, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f,
0x75, 0x0a, 0x49, 0x20, 0x64, 0x6f, 0x6e, 0x20, 0x74, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x20, 0x68, 0x6f, 0x77, 0x20,
0x74, 0x6f, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x6f, 0x6e, 0x65, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20,
0x69, 0x6e, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x0a, 0x49,
0x20, 0x6d, 0x20, 0x61, 0x73, 0x68, 0x61, 0x6d, 0x65, 0x64, 0x20, 0x6f, 0x66, 0x20, 0x6d, 0x79, 0x20, 0x6c, 0x69,
0x66, 0x65, 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x69, 0x74, 0x20, 0x73, 0x20, 0x65, 0x6d, 0x70,
0x74, 0x79, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x0a, 0x49,
0x20, 0x61, 0x6d, 0x20, 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, 0x0a, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65,
0x20, 0x6f, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x0a, 0x42, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20,
0x79, 0x6f, 0x75, 0x0a, 0x2e, 0x2e, 0x2e, 0x0a, /*0x0a, 0x66, 0x6f, 0x72, 0x20, 0x6a, 0x75, 0x6c, 0x79, 0x0a, 0x0a,*/
};
}
}
package com.taobao.arthas.core.command.hidden;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ArthasBanner;
import com.taobao.middleware.cli.annotations.Hidden;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
/**
* 工具介绍<br/>
* 感谢
*
* @author vlinux on 15/9/1.
*/
@Name("thanks")
@Summary("Credits to all personnel and organization who either contribute or help to this product. Thanks you all!")
@Hidden
public class ThanksCommand extends AnnotatedCommand {
@Override
public void process(CommandProcess process) {
process.write(ArthasBanner.credit()).write("\n").end();
}
}
package com.taobao.arthas.core.command.klass100;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.core.util.FileUtils;
import com.taobao.arthas.core.util.LogUtil;
import java.io.File;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author beiwei30 on 25/11/2016.
*/
class ClassDumpTransformer implements ClassFileTransformer {
private static final Logger logger = LoggerFactory.getLogger(ClassDumpTransformer.class);
private Set<Class<?>> classesToEnhance;
private Map<Class<?>, File> dumpResult;
private File arthasLogHome;
private File directory;
public ClassDumpTransformer(Set<Class<?>> classesToEnhance) {
this(classesToEnhance, null);
}
public ClassDumpTransformer(Set<Class<?>> classesToEnhance, File directory) {
this.classesToEnhance = classesToEnhance;
this.dumpResult = new HashMap<Class<?>, File>();
this.arthasLogHome = new File(LogUtil.loggingDir());
this.directory = directory;
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (classesToEnhance.contains(classBeingRedefined)) {
dumpClassIfNecessary(classBeingRedefined, classfileBuffer);
}
return null;
}
public Map<Class<?>, File> getDumpResult() {
return dumpResult;
}
private void dumpClassIfNecessary(Class<?> clazz, byte[] data) {
String className = clazz.getName();
ClassLoader classLoader = clazz.getClassLoader();
String classDumpDir = "classdump";
// 创建类所在的包路径
File dumpDir = null;
if (directory != null) {
dumpDir = directory;
} else {
dumpDir = new File(arthasLogHome, classDumpDir);
}
if (!dumpDir.mkdirs() && !dumpDir.exists()) {
logger.warn("create dump directory:{} failed.", dumpDir.getAbsolutePath());
return;
}
String fileName;
if (classLoader != null) {
fileName = classLoader.getClass().getName() + "-" + Integer.toHexString(classLoader.hashCode()) +
File.separator + className.replace(".", File.separator) + ".class";
} else {
fileName = className.replace(".", File.separator) + ".class";
}
File dumpClassFile = new File(dumpDir, fileName);
// 将类字节码写入文件
try {
FileUtils.writeByteArrayToFile(dumpClassFile, data);
dumpResult.put(clazz, dumpClassFile);
} catch (IOException e) {
logger.warn("dump class:{} to file {} failed.", className, dumpClassFile, e);
}
}
}
package com.taobao.arthas.core.command.klass100;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.core.command.Constants;
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.command.model.MessageModel;
import com.taobao.arthas.core.command.model.RowAffectModel;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.shell.handlers.Handler;
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.affect.RowAffect;
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 java.lang.instrument.Instrumentation;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
@Name("classloader")
@Summary("Show classloader info")
@Description(Constants.EXAMPLE +
" classloader\n" +
" classloader -t\n" +
" classloader -l\n" +
" classloader -c 327a647b\n" +
" classloader -c 327a647b -r META-INF/MANIFEST.MF\n" +
" classloader -a\n" +
" classloader -a -c 327a647b\n" +
" classloader -c 659e0bfd --load demo.MathGame\n" +
" classloader -u # url statistics\n" +
Constants.WIKI + Constants.WIKI_HOME + "classloader")
public class ClassLoaderCommand extends AnnotatedCommand {
private Logger logger = LoggerFactory.getLogger(ClassLoaderCommand.class);
private boolean isTree = false;
private String hashCode;
private String classLoaderClass;
private boolean all = false;
private String resource;
private boolean includeReflectionClassLoader = true;
private boolean listClassLoader = false;
private boolean urlStat = false;
private String loadClass = null;
private volatile boolean isInterrupted = false;
@Option(shortName = "t", longName = "tree", flag = true)
@Description("Display ClassLoader tree")
public void setTree(boolean tree) {
isTree = tree;
}
@Option(longName = "classLoaderClass")
@Description("The class name of the special class's classLoader.")
public void setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
}
@Option(shortName = "c", longName = "classloader")
@Description("The hash code of the special ClassLoader")
public void setHashCode(String hashCode) {
this.hashCode = hashCode;
}
@Option(shortName = "a", longName = "all", flag = true)
@Description("Display all classes loaded by ClassLoader")
public void setAll(boolean all) {
this.all = all;
}
@Option(shortName = "r", longName = "resource")
@Description("Use ClassLoader to find resources, won't work without -c specified")
public void setResource(String resource) {
this.resource = resource;
}
@Option(shortName = "i", longName = "include-reflection-classloader", flag = true)
@Description("Include sun.reflect.DelegatingClassLoader")
public void setIncludeReflectionClassLoader(boolean includeReflectionClassLoader) {
this.includeReflectionClassLoader = includeReflectionClassLoader;
}
@Option(shortName = "l", longName = "list-classloader", flag = true)
@Description("Display statistics info by classloader instance")
public void setListClassLoader(boolean listClassLoader) {
this.listClassLoader = listClassLoader;
}
@Option(longName = "load")
@Description("Use ClassLoader to load class, won't work without -c specified")
public void setLoadClass(String className) {
this.loadClass = className;
}
@Option(shortName = "u", longName = "url-stat", flag = true)
@Description("Display classloader url statistics")
public void setUrlStat(boolean urlStat) {
this.urlStat = urlStat;
}
@Override
public void process(CommandProcess process) {
// ctrl-C support
process.interruptHandler(new ClassLoaderInterruptHandler(this));
ClassLoader targetClassLoader = null;
boolean classLoaderSpecified = false;
Instrumentation inst = process.session().getInstrumentation();
if (urlStat) {
Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats = this.urlStats(inst);
ClassLoaderModel model = new ClassLoaderModel();
model.setUrlStats(urlStats);
process.appendResult(model);
process.end();
return;
}
if (hashCode != null || classLoaderClass != null) {
classLoaderSpecified = true;
}
if (hashCode != null) {
Set<ClassLoader> allClassLoader = getAllClassLoaders(inst);
for (ClassLoader cl : allClassLoader) {
if (Integer.toHexString(cl.hashCode()).equals(hashCode)) {
targetClassLoader = cl;
break;
}
}
} else if (classLoaderClass != null) {
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
if (matchedClassLoaders.size() == 1) {
targetClassLoader = matchedClassLoaders.get(0);
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
ClassLoaderModel classloaderModel = new ClassLoaderModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(classloaderModel);
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;
}
}
if (all) {
processAllClasses(process, inst);
} else if (classLoaderSpecified && resource != null) {
processResources(process, inst, targetClassLoader);
} else if (classLoaderSpecified && this.loadClass != null) {
processLoadClass(process, inst, targetClassLoader);
} else if (classLoaderSpecified) {
processClassLoader(process, inst, targetClassLoader);
} else if (listClassLoader || isTree){
processClassLoaders(process, inst);
} else {
processClassLoaderStats(process, inst);
}
}
/**
* Calculate classloader statistics.
* e.g. In JVM, there are 100 GrooyClassLoader instances, which loaded 200 classes in total
* @param process
* @param inst
*/
private void processClassLoaderStats(CommandProcess process, Instrumentation inst) {
RowAffect affect = new RowAffect();
List<ClassLoaderInfo> classLoaderInfos = getAllClassLoaderInfo(inst);
Map<String, ClassLoaderStat> classLoaderStats = new HashMap<String, ClassLoaderStat>();
for (ClassLoaderInfo info: classLoaderInfos) {
String name = info.classLoader == null ? "BootstrapClassLoader" : info.classLoader.getClass().getName();
ClassLoaderStat stat = classLoaderStats.get(name);
if (null == stat) {
stat = new ClassLoaderStat();
classLoaderStats.put(name, stat);
}
stat.addLoadedCount(info.loadedClassCount);
stat.addNumberOfInstance(1);
}
// sort the map by value
TreeMap<String, ClassLoaderStat> sorted =
new TreeMap<String, ClassLoaderStat>(new ValueComparator(classLoaderStats));
sorted.putAll(classLoaderStats);
process.appendResult(new ClassLoaderModel().setClassLoaderStats(sorted));
affect.rCnt(sorted.keySet().size());
process.appendResult(new RowAffectModel(affect));
process.end();
}
private void processClassLoaders(CommandProcess process, Instrumentation inst) {
RowAffect affect = new RowAffect();
List<ClassLoaderInfo> classLoaderInfos = includeReflectionClassLoader ? getAllClassLoaderInfo(inst) :
getAllClassLoaderInfo(inst, new SunReflectionClassLoaderFilter());
List<ClassLoaderVO> classLoaderVOs = new ArrayList<ClassLoaderVO>(classLoaderInfos.size());
for (ClassLoaderInfo classLoaderInfo : classLoaderInfos) {
ClassLoaderVO classLoaderVO = ClassUtils.createClassLoaderVO(classLoaderInfo.classLoader);
classLoaderVO.setLoadedCount(classLoaderInfo.loadedClassCount());
classLoaderVOs.add(classLoaderVO);
}
if (isTree){
classLoaderVOs = processClassLoaderTree(classLoaderVOs);
}
process.appendResult(new ClassLoaderModel().setClassLoaders(classLoaderVOs).setTree(isTree));
affect.rCnt(classLoaderInfos.size());
process.appendResult(new RowAffectModel(affect));
process.end();
}
// 根据 ClassLoader 来打印URLClassLoader的urls
private void processClassLoader(CommandProcess process, Instrumentation inst, ClassLoader targetClassLoader) {
RowAffect affect = new RowAffect();
if (targetClassLoader != null) {
if (targetClassLoader instanceof URLClassLoader) {
List<String> classLoaderUrls = getClassLoaderUrls(targetClassLoader);
affect.rCnt(classLoaderUrls.size());
if (classLoaderUrls.isEmpty()) {
process.appendResult(new MessageModel("urls is empty."));
} else {
process.appendResult(new ClassLoaderModel().setUrls(classLoaderUrls));
affect.rCnt(classLoaderUrls.size());
}
} else {
process.appendResult(new MessageModel("not a URLClassLoader."));
}
}
process.appendResult(new RowAffectModel(affect));
process.end();
}
// 使用ClassLoader去getResources
private void processResources(CommandProcess process, Instrumentation inst, ClassLoader targetClassLoader) {
RowAffect affect = new RowAffect();
int rowCount = 0;
List<String> resources = new ArrayList<String>();
if (targetClassLoader != null) {
try {
Enumeration<URL> urls = targetClassLoader.getResources(resource);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
resources.add(url.toString());
rowCount++;
}
} catch (Throwable e) {
logger.warn("get resource failed, resource: {}", resource, e);
}
}
affect.rCnt(rowCount);
process.appendResult(new ClassLoaderModel().setResources(resources));
process.appendResult(new RowAffectModel(affect));
process.end();
}
// Use ClassLoader to loadClass
private void processLoadClass(CommandProcess process, Instrumentation inst, ClassLoader targetClassLoader) {
if (targetClassLoader != null) {
try {
Class<?> clazz = targetClassLoader.loadClass(this.loadClass);
process.appendResult(new MessageModel("load class success."));
ClassDetailVO classInfo = ClassUtils.createClassInfo(clazz, false, null);
process.appendResult(new ClassLoaderModel().setLoadClass(classInfo));
} catch (Throwable e) {
logger.warn("load class error, class: {}", this.loadClass, e);
process.end(-1, "load class error, class: "+this.loadClass+", error: "+e.toString());
return;
}
}
process.end();
}
private void processAllClasses(CommandProcess process, Instrumentation inst) {
RowAffect affect = new RowAffect();
getAllClasses(hashCode, inst, affect, process);
if (checkInterrupted(process)) {
return;
}
process.appendResult(new RowAffectModel(affect));
process.end();
}
/**
* 获取到所有的class, 还有它们的classloader,按classloader归类好,统一输出每个classloader里有哪些class
* <p>
* 当hashCode是null,则把所有的classloader的都打印
*
*/
@SuppressWarnings("rawtypes")
private void getAllClasses(String hashCode, Instrumentation inst, RowAffect affect, CommandProcess process) {
int hashCodeInt = -1;
if (hashCode != null) {
hashCodeInt = Integer.valueOf(hashCode, 16);
}
SortedSet<Class<?>> bootstrapClassSet = new TreeSet<Class<?>>(new Comparator<Class>() {
@Override
public int compare(Class o1, Class o2) {
return o1.getName().compareTo(o2.getName());
}
});
Class[] allLoadedClasses = inst.getAllLoadedClasses();
Map<ClassLoader, SortedSet<Class<?>>> classLoaderClassMap = new HashMap<ClassLoader, SortedSet<Class<?>>>();
for (Class clazz : allLoadedClasses) {
ClassLoader classLoader = clazz.getClassLoader();
// Class loaded by BootstrapClassLoader
if (classLoader == null) {
if (hashCode == null) {
bootstrapClassSet.add(clazz);
}
continue;
}
if (hashCode != null && classLoader.hashCode() != hashCodeInt) {
continue;
}
SortedSet<Class<?>> classSet = classLoaderClassMap.get(classLoader);
if (classSet == null) {
classSet = new TreeSet<Class<?>>(new Comparator<Class<?>>() {
@Override
public int compare(Class<?> o1, Class<?> o2) {
return o1.getName().compareTo(o2.getName());
}
});
classLoaderClassMap.put(classLoader, classSet);
}
classSet.add(clazz);
}
// output bootstrapClassSet
int pageSize = 256;
processClassSet(process, ClassUtils.createClassLoaderVO(null), bootstrapClassSet, pageSize, affect);
// output other classSet
for (Entry<ClassLoader, SortedSet<Class<?>>> entry : classLoaderClassMap.entrySet()) {
if (checkInterrupted(process)) {
return;
}
ClassLoader classLoader = entry.getKey();
SortedSet<Class<?>> classSet = entry.getValue();
processClassSet(process, ClassUtils.createClassLoaderVO(classLoader), classSet, pageSize, affect);
}
}
private void processClassSet(final CommandProcess process, final ClassLoaderVO classLoaderVO, Collection<Class<?>> classes, int pageSize, final RowAffect affect) {
//分批输出classNames, Ctrl+C可以中断执行
ResultUtils.processClassNames(classes, pageSize, new ResultUtils.PaginationHandler<List<String>>() {
@Override
public boolean handle(List<String> classNames, int segment) {
process.appendResult(new ClassLoaderModel().setClassSet(new ClassSetVO(classLoaderVO, classNames, segment)));
affect.rCnt(classNames.size());
return !checkInterrupted(process);
}
});
}
private boolean checkInterrupted(CommandProcess process) {
if (!process.isRunning()) {
return true;
}
if(isInterrupted){
process.end(-1, "Processing has been interrupted");
return true;
} else {
return false;
}
}
private static List<String> getClassLoaderUrls(ClassLoader classLoader) {
List<String> urlStrs = new ArrayList<String>();
if (classLoader instanceof URLClassLoader) {
URLClassLoader cl = (URLClassLoader) classLoader;
URL[] urls = cl.getURLs();
if (urls != null) {
for (URL url : urls) {
urlStrs.add(url.toString());
}
}
}
return urlStrs;
}
private Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats(Instrumentation inst) {
Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats = new HashMap<ClassLoaderVO, ClassLoaderUrlStat>();
Map<ClassLoader, Set<String>> usedUrlsMap = new HashMap<ClassLoader, Set<String>>();
for (Class<?> clazz : inst.getAllLoadedClasses()) {
ClassLoader classLoader = clazz.getClassLoader();
if (classLoader != null) {
ProtectionDomain protectionDomain = clazz.getProtectionDomain();
CodeSource codeSource = protectionDomain.getCodeSource();
if (codeSource != null) {
URL location = codeSource.getLocation();
if (location != null) {
Set<String> urls = usedUrlsMap.get(classLoader);
if (urls == null) {
urls = new HashSet<String>();
usedUrlsMap.put(classLoader, urls);
}
urls.add(location.toString());
}
}
}
}
for (Entry<ClassLoader, Set<String>> entry : usedUrlsMap.entrySet()) {
ClassLoader loader = entry.getKey();
Set<String> usedUrls = entry.getValue();
List<String> allUrls = getClassLoaderUrls(loader);
List<String> unusedUrls = new ArrayList<String>();
for (String url : allUrls) {
if (!usedUrls.contains(url)) {
unusedUrls.add(url);
}
}
urlStats.put(ClassUtils.createClassLoaderVO(loader), new ClassLoaderUrlStat(usedUrls, unusedUrls));
}
return urlStats;
}
// 以树状列出ClassLoader的继承结构
private static List<ClassLoaderVO> processClassLoaderTree(List<ClassLoaderVO> classLoaders) {
List<ClassLoaderVO> rootClassLoaders = new ArrayList<ClassLoaderVO>();
List<ClassLoaderVO> parentNotNullClassLoaders = new ArrayList<ClassLoaderVO>();
for (ClassLoaderVO classLoaderVO : classLoaders) {
if (classLoaderVO.getParent() == null) {
rootClassLoaders.add(classLoaderVO);
} else {
parentNotNullClassLoaders.add(classLoaderVO);
}
}
for (ClassLoaderVO classLoaderVO : rootClassLoaders) {
buildTree(classLoaderVO, parentNotNullClassLoaders);
}
return rootClassLoaders;
}
private static void buildTree(ClassLoaderVO parent, List<ClassLoaderVO> parentNotNullClassLoaders) {
for (ClassLoaderVO classLoaderVO : parentNotNullClassLoaders) {
if (parent.getName().equals(classLoaderVO.getParent())){
parent.addChild(classLoaderVO);
buildTree(classLoaderVO, parentNotNullClassLoaders);
}
}
}
private static Set<ClassLoader> getAllClassLoaders(Instrumentation inst, Filter... filters) {
Set<ClassLoader> classLoaderSet = new HashSet<ClassLoader>();
for (Class<?> clazz : inst.getAllLoadedClasses()) {
ClassLoader classLoader = clazz.getClassLoader();
if (classLoader != null) {
if (shouldInclude(classLoader, filters)) {
classLoaderSet.add(classLoader);
}
}
}
return classLoaderSet;
}
private static List<ClassLoaderInfo> getAllClassLoaderInfo(Instrumentation inst, Filter... filters) {
// 这里认为class.getClassLoader()返回是null的是由BootstrapClassLoader加载的,特殊处理
ClassLoaderInfo bootstrapInfo = new ClassLoaderInfo(null);
Map<ClassLoader, ClassLoaderInfo> loaderInfos = new HashMap<ClassLoader, ClassLoaderInfo>();
for (Class<?> clazz : inst.getAllLoadedClasses()) {
ClassLoader classLoader = clazz.getClassLoader();
if (classLoader == null) {
bootstrapInfo.increase();
} else {
if (shouldInclude(classLoader, filters)) {
ClassLoaderInfo loaderInfo = loaderInfos.get(classLoader);
if (loaderInfo == null) {
loaderInfo = new ClassLoaderInfo(classLoader);
loaderInfos.put(classLoader, loaderInfo);
ClassLoader parent = classLoader.getParent();
while (parent != null) {
ClassLoaderInfo parentLoaderInfo = loaderInfos.get(parent);
if (parentLoaderInfo == null) {
parentLoaderInfo = new ClassLoaderInfo(parent);
loaderInfos.put(parent, parentLoaderInfo);
}
parent = parent.getParent();
}
}
loaderInfo.increase();
}
}
}
// 排序时,把用户自己定的ClassLoader排在最前面,以sun.
// 开头的放后面,因为sun.reflect.DelegatingClassLoader的实例太多
List<ClassLoaderInfo> sunClassLoaderList = new ArrayList<ClassLoaderInfo>();
List<ClassLoaderInfo> otherClassLoaderList = new ArrayList<ClassLoaderInfo>();
for (Entry<ClassLoader, ClassLoaderInfo> entry : loaderInfos.entrySet()) {
ClassLoader classLoader = entry.getKey();
if (classLoader.getClass().getName().startsWith("sun.")) {
sunClassLoaderList.add(entry.getValue());
} else {
otherClassLoaderList.add(entry.getValue());
}
}
Collections.sort(sunClassLoaderList);
Collections.sort(otherClassLoaderList);
List<ClassLoaderInfo> result = new ArrayList<ClassLoaderInfo>();
result.add(bootstrapInfo);
result.addAll(otherClassLoaderList);
result.addAll(sunClassLoaderList);
return result;
}
private static boolean shouldInclude(ClassLoader classLoader, Filter... filters) {
if (filters == null) {
return true;
}
for (Filter filter : filters) {
if (!filter.accept(classLoader)) {
return false;
}
}
return true;
}
private static class ClassLoaderInfo implements Comparable<ClassLoaderInfo> {
private ClassLoader classLoader;
private int loadedClassCount = 0;
ClassLoaderInfo(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public String getName() {
if (classLoader != null) {
return classLoader.toString();
}
return "BootstrapClassLoader";
}
String hashCodeStr() {
if (classLoader != null) {
return "" + Integer.toHexString(classLoader.hashCode());
}
return "null";
}
void increase() {
loadedClassCount++;
}
int loadedClassCount() {
return loadedClassCount;
}
ClassLoader parent() {
return classLoader == null ? null : classLoader.getParent();
}
String parentStr() {
if (classLoader == null) {
return "null";
}
ClassLoader parent = classLoader.getParent();
if (parent == null) {
return "null";
}
return parent.toString();
}
@Override
public int compareTo(ClassLoaderInfo other) {
if (other == null) {
return -1;
}
if (other.classLoader == null) {
return -1;
}
if (this.classLoader == null) {
return -1;
}
return this.classLoader.getClass().getName().compareTo(other.classLoader.getClass().getName());
}
}
private interface Filter {
boolean accept(ClassLoader classLoader);
}
private static class SunReflectionClassLoaderFilter implements Filter {
private static final List<String> REFLECTION_CLASSLOADERS = Arrays.asList("sun.reflect.DelegatingClassLoader",
"jdk.internal.reflect.DelegatingClassLoader");
@Override
public boolean accept(ClassLoader classLoader) {
return !REFLECTION_CLASSLOADERS.contains(classLoader.getClass().getName());
}
}
public static class ClassLoaderUrlStat {
private Collection<String> usedUrls;
private Collection<String> unUsedUrls;
public ClassLoaderUrlStat() {
}
public ClassLoaderUrlStat(Collection<String> usedUrls, Collection<String> unUsedUrls) {
super();
this.usedUrls = usedUrls;
this.unUsedUrls = unUsedUrls;
}
public Collection<String> getUsedUrls() {
return usedUrls;
}
public void setUsedUrls(Collection<String> usedUrls) {
this.usedUrls = usedUrls;
}
public Collection<String> getUnUsedUrls() {
return unUsedUrls;
}
public void setUnUsedUrls(Collection<String> unUsedUrls) {
this.unUsedUrls = unUsedUrls;
}
}
public static class ClassLoaderStat {
private int loadedCount;
private int numberOfInstance;
void addLoadedCount(int count) {
this.loadedCount += count;
}
void addNumberOfInstance(int count) {
this.numberOfInstance += count;
}
public int getLoadedCount() {
return loadedCount;
}
public int getNumberOfInstance() {
return numberOfInstance;
}
}
private static class ValueComparator implements Comparator<String> {
private Map<String, ClassLoaderStat> unsortedStats;
ValueComparator(Map<String, ClassLoaderStat> stats) {
this.unsortedStats = stats;
}
@Override
public int compare(String o1, String o2) {
if (null == unsortedStats) {
return -1;
}
if (!unsortedStats.containsKey(o1)) {
return 1;
}
if (!unsortedStats.containsKey(o2)) {
return -1;
}
return unsortedStats.get(o2).getLoadedCount() - unsortedStats.get(o1).getLoadedCount();
}
}
private static class ClassLoaderInterruptHandler implements Handler<Void> {
private ClassLoaderCommand command;
public ClassLoaderInterruptHandler(ClassLoaderCommand command) {
this.command = command;
}
@Override
public void handle(Void event) {
command.isInterrupted = true;
}
}
}
package com.taobao.arthas.core.command.klass100;
import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.ClassVO;
import com.taobao.arthas.core.command.model.ClassLoaderVO;
import com.taobao.arthas.core.command.model.DumpClassModel;
import com.taobao.arthas.core.command.model.DumpClassVO;
import com.taobao.arthas.core.command.model.MessageModel;
import com.taobao.arthas.core.command.model.RowAffectModel;
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.shell.command.ExitStatus;
import com.taobao.arthas.core.util.ClassUtils;
import com.taobao.arthas.core.util.ClassLoaderUtils;
import com.taobao.arthas.core.util.CommandUtils;
import com.taobao.arthas.core.util.InstrumentationUtils;
import com.taobao.arthas.core.util.SearchUtils;
import com.taobao.arthas.core.util.affect.RowAffect;
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;
import java.io.File;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
/**
* Dump class byte array
*/
@Name("dump")
@Summary("Dump class byte array from JVM")
@Description(Constants.EXAMPLE +
" dump java.lang.String\n" +
" dump -d /tmp/output java.lang.String\n" +
" dump org/apache/commons/lang/StringUtils\n" +
" dump *StringUtils\n" +
" dump -E org\\\\.apache\\\\.commons\\\\.lang\\\\.StringUtils\n" +
Constants.WIKI + Constants.WIKI_HOME + "dump")
public class DumpClassCommand extends AnnotatedCommand {
private static final Logger logger = LoggerFactory.getLogger(DumpClassCommand.class);
private String classPattern;
private String code = null;
private String classLoaderClass;
private boolean isRegEx = false;
private String directory;
private int limit;
@Argument(index = 0, argName = "class-pattern")
@Description("Class name pattern, use either '.' or '/' as separator")
public void setClassPattern(String classPattern) {
this.classPattern = classPattern;
}
@Option(shortName = "c", longName = "code")
@Description("The hash code of the special class's classLoader")
public void setCode(String code) {
this.code = code;
}
@Option(longName = "classLoaderClass")
@Description("The class name of the special class's classLoader.")
public void setClassLoaderClass(String classLoaderClass) {
this.classLoaderClass = classLoaderClass;
}
@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 = "d", longName = "directory")
@Description("Sets the destination directory for class files")
public void setDirectory(String directory) {
this.directory = directory;
}
@Option(shortName = "l", longName = "limit")
@Description("The limit of dump classes size, default value is 50")
@DefaultValue("50")
public void setLimit(int limit) {
this.limit = limit;
}
@Override
public void process(CommandProcess process) {
RowAffect effect = new RowAffect();
try {
if (directory != null) {
File dir = new File(directory);
if (dir.isFile()) {
process.end(-1, directory + " :is not a directory, please check it");
return;
}
}
ExitStatus status = null;
Instrumentation inst = process.session().getInstrumentation();
if (code == null && classLoaderClass != null) {
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
if (matchedClassLoaders.size() == 1) {
code = Integer.toHexString(matchedClassLoaders.get(0).hashCode());
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
DumpClassModel dumpClassModel = new DumpClassModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(dumpClassModel);
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, code);
if (matchedClasses == null || matchedClasses.isEmpty()) {
status = processNoMatch(process);
} else if (matchedClasses.size() > limit) {
status = processMatches(process, matchedClasses);
} else {
status = processMatch(process, effect, inst, matchedClasses);
}
process.appendResult(new RowAffectModel(effect));
CommandUtils.end(process, status);
} catch (Throwable e){
logger.error("processing error", e);
process.end(-1, "processing error");
}
}
@Override
public void complete(Completion completion) {
if (!CompletionUtils.completeClassName(completion)) {
super.complete(completion);
}
}
private ExitStatus processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set<Class<?>> matchedClasses) {
try {
Map<Class<?>, File> classFiles = dump(inst, matchedClasses);
List<DumpClassVO> dumpedClasses = new ArrayList<DumpClassVO>(classFiles.size());
for (Map.Entry<Class<?>, File> entry : classFiles.entrySet()) {
Class<?> clazz = entry.getKey();
File file = entry.getValue();
DumpClassVO dumpClassVO = new DumpClassVO();
dumpClassVO.setLocation(file.getCanonicalPath());
ClassUtils.fillSimpleClassVO(clazz, dumpClassVO);
dumpedClasses.add(dumpClassVO);
}
process.appendResult(new DumpClassModel().setDumpedClasses(dumpedClasses));
effect.rCnt(classFiles.keySet().size());
return ExitStatus.success();
} catch (Throwable t) {
logger.error("dump: fail to dump classes: " + matchedClasses, t);
return ExitStatus.failure(-1, "dump: fail to dump classes: " + matchedClasses);
}
}
private ExitStatus processMatches(CommandProcess process, Set<Class<?>> matchedClasses) {
String msg = String.format(
"Found more than %d class for: %s, Please Try to specify the classloader with the -c option, or try to use --limit option.",
limit, classPattern);
process.appendResult(new MessageModel(msg));
List<ClassVO> classVOs = ClassUtils.createClassVOList(matchedClasses);
process.appendResult(new DumpClassModel().setMatchedClasses(classVOs));
return ExitStatus.failure(-1, msg);
}
private ExitStatus processNoMatch(CommandProcess process) {
return ExitStatus.failure(-1, "No class found for: " + classPattern);
}
private Map<Class<?>, File> dump(Instrumentation inst, Set<Class<?>> classes) throws UnmodifiableClassException {
ClassDumpTransformer transformer = null;
if (directory != null) {
transformer = new ClassDumpTransformer(classes, new File(directory));
} else {
transformer = new ClassDumpTransformer(classes);
}
InstrumentationUtils.retransformClasses(inst, transformer, classes);
return transformer.getDumpResult();
}
}
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