forked from alibaba/arthas
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ebfb0c6
commit 3fbfab4
Showing
235 changed files
with
30,452 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
在线诊断利器Arthas | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
|
||
* 代码还是很乱,需要继续重构 | ||
* 依赖需要清理,几个问题: | ||
* 所有 apache 的 common 库应当不需要 | ||
* json 库有好几份 | ||
* `jopt-simple` 看下能不能用 `cli` 取代 | ||
* `cli`, `termd` 的 artifactId, version 需要想下。是不是应该直接拿进来。他们的依赖也需要仔细看一下 | ||
* termd 依赖 netty,感觉有点重,而且第一次 attach 比较慢,不确定是 netty 的问题还是 attach 的问题 | ||
* 目前 web console 依赖 termd 中自带的 term.js 和 css,需要美化,需要想下如何集成到研发门户上 | ||
* 因为现在没有 Java 客户端了,所以 batch mode 也就没有了 | ||
* `com.taobao.arthas.core.shell.session.Session` 的能力需要和以前的 session 的实现对标。其中: | ||
* 真的需要 textmode 吗?我觉得这个应该是 option 的事情 | ||
* 真的需要 encoding 吗?我觉得仍然应该在 option 中定义,就算是真的需要,因为我觉得就应该是 UTF-8 | ||
* duration 是应当展示的,session 的列表也许也应当展示 | ||
* 需要仔细看下 session 过期是否符合预期 | ||
* 多人协作的时候 session 原来是在多人之间共享的吗? | ||
* 所有的命令现在实现的是 AnnotatedCommand,需要继续增强的是: | ||
* Help 中的格式化输出被删除。需要为 `@Description` 定义一套统一的格式 | ||
* 命令的输入以及输出的日志 (record logger) 被删除,需要重新实现,因为现在是用 `CommandProcess` 来输出,所以,需要在 `CommandProcess` 的实现里打日志 | ||
* `com.taobao.arthas.core.GlobalOptions` 看上去好奇怪,感觉是 OptionCommand 应当做的事情 | ||
* `com.taobao.arthas.core.config.Configure` 需要清理,尤其是和 http 相关的 | ||
* 需要合并 develop 分支上后续的修复 | ||
* 代码中的 TODO/FIXME |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?xml version="1.0"?> | ||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" | ||
xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>com.taobao.arthas</groupId> | ||
<artifactId>arthas-all</artifactId> | ||
<version>3.0.0-SNAPSHOT</version> | ||
</parent> | ||
<artifactId>arthas-agent</artifactId> | ||
<name>arthas-agent</name> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>com.taobao.arthas</groupId> | ||
<artifactId>arthas-spy</artifactId> | ||
<version>${project.version}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<finalName>arthas-agent</finalName> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<configuration> | ||
<source>1.6</source> | ||
<target>1.6</target> | ||
<encoding>UTF-8</encoding> | ||
<showDeprecation>true</showDeprecation> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-assembly-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<goals> | ||
<goal>attached</goal> | ||
</goals> | ||
<phase>package</phase> | ||
<configuration> | ||
<descriptorRefs> | ||
<descriptorRef>jar-with-dependencies</descriptorRef> | ||
</descriptorRefs> | ||
<archive> | ||
<manifestEntries> | ||
<Premain-Class>com.taobao.arthas.agent.AgentBootstrap</Premain-Class> | ||
<Agent-Class>com.taobao.arthas.agent.AgentBootstrap</Agent-Class> | ||
<Can-Redefine-Classes>true</Can-Redefine-Classes> | ||
<Can-Retransform-Classes>true</Can-Retransform-Classes> | ||
</manifestEntries> | ||
</archive> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
168 changes: 168 additions & 0 deletions
168
agent/src/main/java/com/taobao/arthas/agent/AgentBootstrap.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
package com.taobao.arthas.agent; | ||
|
||
import java.arthas.Spy; | ||
import java.io.*; | ||
import java.lang.instrument.Instrumentation; | ||
import java.lang.reflect.Method; | ||
import java.net.URL; | ||
import java.util.jar.JarFile; | ||
|
||
/** | ||
* 代理启动类 | ||
* | ||
* @author vlinux on 15/5/19. | ||
*/ | ||
public class AgentBootstrap { | ||
|
||
private static final String ADVICEWEAVER = "com.taobao.arthas.core.advisor.AdviceWeaver"; | ||
private static final String ON_BEFORE = "methodOnBegin"; | ||
private static final String ON_RETURN = "methodOnReturnEnd"; | ||
private static final String ON_THROWS = "methodOnThrowingEnd"; | ||
private static final String BEFORE_INVOKE = "methodOnInvokeBeforeTracing"; | ||
private static final String AFTER_INVOKE = "methodOnInvokeAfterTracing"; | ||
private static final String THROW_INVOKE = "methodOnInvokeThrowTracing"; | ||
private static final String RESET = "resetArthasClassLoader"; | ||
private static final String ARTHAS_SPY_JAR = "arthas-spy.jar"; | ||
private static final String ARTHAS_CONFIGURE = "com.taobao.arthas.core.config.Configure"; | ||
private static final String ARTHAS_BOOTSTRAP = "com.taobao.arthas.core.server.ArthasBootstrap"; | ||
private static final String TO_CONFIGURE = "toConfigure"; | ||
private static final String GET_JAVA_PID = "getJavaPid"; | ||
private static final String GET_INSTANCE = "getInstance"; | ||
private static final String IS_BIND = "isBind"; | ||
private static final String BIND = "bind"; | ||
|
||
private static PrintStream ps = System.err; | ||
static { | ||
try { | ||
File log = new File(System.getProperty("user.home") + File.separator + "logs" + File.separator | ||
+ "arthas" + File.separator + "arthas.log"); | ||
if (!log.exists()) { | ||
log.getParentFile().mkdir(); | ||
log.createNewFile(); | ||
} | ||
ps = new PrintStream(new FileOutputStream(log, true)); | ||
} catch (Throwable t) { | ||
t.printStackTrace(ps); | ||
} | ||
} | ||
|
||
// 全局持有classloader用于隔离 Arthas 实现 | ||
private static volatile ClassLoader arthasClassLoader; | ||
|
||
public static void premain(String args, Instrumentation inst) { | ||
main(args, inst); | ||
} | ||
|
||
public static void agentmain(String args, Instrumentation inst) { | ||
main(args, inst); | ||
} | ||
|
||
/** | ||
* 让下次再次启动时有机会重新加载 | ||
*/ | ||
public synchronized static void resetArthasClassLoader() { | ||
arthasClassLoader = null; | ||
} | ||
|
||
private static ClassLoader getClassLoader(Instrumentation inst, File spyJarFile, File agentJarFile) throws Throwable { | ||
// 将Spy添加到BootstrapClassLoader | ||
inst.appendToBootstrapClassLoaderSearch(new JarFile(spyJarFile)); | ||
|
||
// 构造自定义的类加载器,尽量减少Arthas对现有工程的侵蚀 | ||
return loadOrDefineClassLoader(agentJarFile); | ||
} | ||
|
||
private static ClassLoader loadOrDefineClassLoader(File agentJar) throws Throwable { | ||
if (arthasClassLoader == null) { | ||
arthasClassLoader = new ArthasClassloader(new URL[]{agentJar.toURI().toURL()}); | ||
} | ||
return arthasClassLoader; | ||
} | ||
|
||
private static void initSpy(ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException { | ||
Class<?> adviceWeaverClass = classLoader.loadClass(ADVICEWEAVER); | ||
Method onBefore = adviceWeaverClass.getMethod(ON_BEFORE, int.class, ClassLoader.class, String.class, | ||
String.class, String.class, Object.class, Object[].class); | ||
Method onReturn = adviceWeaverClass.getMethod(ON_RETURN, Object.class); | ||
Method onThrows = adviceWeaverClass.getMethod(ON_THROWS, Throwable.class); | ||
Method beforeInvoke = adviceWeaverClass.getMethod(BEFORE_INVOKE, int.class, String.class, String.class, String.class); | ||
Method afterInvoke = adviceWeaverClass.getMethod(AFTER_INVOKE, int.class, String.class, String.class, String.class); | ||
Method throwInvoke = adviceWeaverClass.getMethod(THROW_INVOKE, int.class, String.class, String.class, String.class); | ||
Method reset = AgentBootstrap.class.getMethod(RESET); | ||
Spy.initForAgentLauncher(classLoader, onBefore, onReturn, onThrows, beforeInvoke, afterInvoke, throwInvoke, reset); | ||
} | ||
|
||
private static synchronized void main(final String args, final Instrumentation inst) { | ||
try { | ||
ps.println("Arthas server agent start..."); | ||
// 传递的args参数分两个部分:agentJar路径和agentArgs, 分别是Agent的JAR包路径和期望传递到服务端的参数 | ||
int index = args.indexOf(';'); | ||
String agentJar = args.substring(0, index); | ||
final String agentArgs = args.substring(index, args.length()); | ||
|
||
File agentJarFile = new File(agentJar); | ||
if (!agentJarFile.exists()) { | ||
ps.println("Agent jar file does not exist: " + agentJarFile); | ||
return; | ||
} | ||
|
||
File spyJarFile = new File(agentJarFile.getParentFile(), ARTHAS_SPY_JAR); | ||
if (!spyJarFile.exists()) { | ||
ps.println("Spy jar file does not exist: " + spyJarFile); | ||
return; | ||
} | ||
|
||
/** | ||
* Use a dedicated thread to run the binding logic to prevent possible memory leak. #195 | ||
*/ | ||
final ClassLoader agentLoader = getClassLoader(inst, spyJarFile, agentJarFile); | ||
initSpy(agentLoader); | ||
|
||
Thread bindingThread = new Thread() { | ||
@Override | ||
public void run() { | ||
try { | ||
bind(inst, agentLoader, agentArgs); | ||
} catch (Throwable throwable) { | ||
throwable.printStackTrace(ps); | ||
} | ||
} | ||
}; | ||
|
||
bindingThread.setName("arthas-binding-thread"); | ||
bindingThread.start(); | ||
bindingThread.join(); | ||
} catch (Throwable t) { | ||
t.printStackTrace(ps); | ||
try { | ||
if (ps != System.err) { | ||
ps.close(); | ||
} | ||
} catch (Throwable tt) { | ||
// ignore | ||
} | ||
throw new RuntimeException(t); | ||
} | ||
} | ||
|
||
private static void bind(Instrumentation inst, ClassLoader agentLoader, String args) throws Throwable { | ||
Class<?> classOfConfigure = agentLoader.loadClass(ARTHAS_CONFIGURE); | ||
Object configure = classOfConfigure.getMethod(TO_CONFIGURE, String.class).invoke(null, args); | ||
int javaPid = (Integer) classOfConfigure.getMethod(GET_JAVA_PID).invoke(configure); | ||
Class<?> bootstrapClass = agentLoader.loadClass(ARTHAS_BOOTSTRAP); | ||
Object bootstrap = bootstrapClass.getMethod(GET_INSTANCE, int.class, Instrumentation.class).invoke(null, javaPid, inst); | ||
boolean isBind = (Boolean) bootstrapClass.getMethod(IS_BIND).invoke(bootstrap); | ||
if (!isBind) { | ||
try { | ||
ps.println("Arthas start to bind..."); | ||
bootstrapClass.getMethod(BIND, classOfConfigure).invoke(bootstrap, configure); | ||
ps.println("Arthas server bind success."); | ||
return; | ||
} catch (Exception e) { | ||
ps.println("Arthas server port binding failed! Please check $HOME/logs/arthas/arthas.log for more details."); | ||
throw e; | ||
} | ||
} | ||
ps.println("Arthas server already bind."); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
agent/src/main/java/com/taobao/arthas/agent/ArthasClassloader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package com.taobao.arthas.agent; | ||
|
||
import java.net.URL; | ||
import java.net.URLClassLoader; | ||
|
||
/** | ||
* @author beiwei30 on 09/12/2016. | ||
*/ | ||
public class ArthasClassloader extends URLClassLoader { | ||
public ArthasClassloader(URL[] urls) { | ||
super(urls, ClassLoader.getSystemClassLoader().getParent()); | ||
} | ||
|
||
@Override | ||
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { | ||
final Class<?> loadedClass = findLoadedClass(name); | ||
if (loadedClass != null) { | ||
return loadedClass; | ||
} | ||
|
||
// 优先从parent(SystemClassLoader)里加载系统类,避免抛出ClassNotFoundException | ||
if (name != null && (name.startsWith("sun.") || name.startsWith("java."))) { | ||
return super.loadClass(name, resolve); | ||
} | ||
try { | ||
Class<?> aClass = findClass(name); | ||
if (resolve) { | ||
resolveClass(aClass); | ||
} | ||
return aClass; | ||
} catch (Exception e) { | ||
// ignore | ||
} | ||
return super.loadClass(name, resolve); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#!/bin/bash | ||
|
||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | ||
|
||
CUR_VERSION="3.0" | ||
|
||
# arthas's target dir | ||
ARTHAS_TARGET_DIR=$DIR/target/arthas | ||
|
||
# arthas's version | ||
DATE=$(date '+%Y%m%d%H%M%S') | ||
|
||
ARTHAS_VERSION="${CUR_VERSION}.${DATE}" | ||
|
||
echo ${ARTHAS_VERSION} > $DIR/core/src/main/resources/com/taobao/arthas/core/res/version | ||
|
||
# define newset arthas lib home | ||
NEWEST_ARTHAS_LIB_HOME=${HOME}/.arthas/lib/${ARTHAS_VERSION}/arthas | ||
|
||
|
||
# exit shell with err_code | ||
# $1 : err_code | ||
# $2 : err_msg | ||
exit_on_err() | ||
{ | ||
[[ ! -z "${2}" ]] && echo "${2}" 1>&2 | ||
exit ${1} | ||
} | ||
|
||
# maven package the arthas | ||
mvn clean package -Dmaven.test.skip=true -f $DIR/pom.xml \ | ||
|| exit_on_err 1 "package arthas failed." | ||
|
||
rm -r $DIR/core/src/main/resources/com/taobao/arthas/core/res/version | ||
|
||
# reset the target dir | ||
mkdir -p ${ARTHAS_TARGET_DIR} | ||
|
||
# copy jar to TARGET_DIR | ||
cp $DIR/spy/target/arthas-spy.jar ${ARTHAS_TARGET_DIR}/arthas-spy.jar | ||
cp $DIR/core/target/arthas-core-jar-with-dependencies.jar ${ARTHAS_TARGET_DIR}/arthas-core.jar | ||
cp $DIR/agent/target/arthas-agent-jar-with-dependencies.jar ${ARTHAS_TARGET_DIR}/arthas-agent.jar | ||
cp $DIR/client/target/arthas-client-jar-with-dependencies.jar ${ARTHAS_TARGET_DIR}/arthas-client.jar | ||
|
||
# copy shell to TARGET_DIR | ||
cat $DIR/bin/install-local.sh|sed "s/ARTHAS_VERSION=0.0/ARTHAS_VERSION=${ARTHAS_VERSION}/g" > ${ARTHAS_TARGET_DIR}/install-local.sh | ||
chmod +x ${ARTHAS_TARGET_DIR}/install-local.sh | ||
cp $DIR/bin/as.sh ${ARTHAS_TARGET_DIR}/as.sh | ||
cp $DIR/bin/as.bat ${ARTHAS_TARGET_DIR}/as.bat | ||
|
||
# zip the arthas | ||
cd $DIR/target/ | ||
zip -r arthas-${ARTHAS_VERSION}-bin.zip arthas/ | ||
cd - | ||
|
||
# install to local | ||
mkdir -p ${NEWEST_ARTHAS_LIB_HOME} | ||
cp $DIR/target/arthas/* ${NEWEST_ARTHAS_LIB_HOME}/ | ||
|
||
if [ $# -gt 0 ] && [ "$1" = "-release" ]; then | ||
echo "creating git tag ${ARTHAS_VERSION}..." | ||
git tag -a ${ARTHAS_VERSION} -m "release ${ARTHAS_VERSION}" | ||
if [ $? -eq 0 ]; then | ||
echo "A local git tag ${ARTHAS_VERSION} has been created, please use 'git tag -l' to verify it." | ||
echo "To commit the tag to remote repo, please run 'git push --tags' manually. " | ||
fi | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
dashboard -n 1 | ||
sysprop | ||
watch arthas.Test test "@com.alibaba.arthas.Test@n.entrySet().iterator.{? #this.key.name()=='STOP' }" -n 2 |
Oops, something went wrong.