All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taobao.arthas.agent334.AgentBootstrap Maven / Gradle / Ivy

package com.taobao.arthas.agent334;

import java.arthas.SpyAPI;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.lang.instrument.Instrumentation;
import java.net.URL;
import java.net.URLDecoder;
import java.security.CodeSource;

import com.taobao.arthas.agent.ArthasClassloader;

/**
 * 代理启动类
 *
 * @author vlinux on 15/5/19.
 */
public class AgentBootstrap {
    private static final String ARTHAS_CORE_JAR = "arthas-core.jar";
    private static final String ARTHAS_BOOTSTRAP = "com.taobao.arthas.core.server.ArthasBootstrap";
    private static final String GET_INSTANCE = "getInstance";
    private static final String IS_BIND = "isBind";

    private static PrintStream ps = System.err;
    static {
        try {
            File arthasLogDir = new File(System.getProperty("user.home") + File.separator + "logs" + File.separator
                    + "arthas" + File.separator);
            if (!arthasLogDir.exists()) {
                arthasLogDir.mkdirs();
            }
            if (!arthasLogDir.exists()) {
                // #572
                arthasLogDir = new File(System.getProperty("java.io.tmpdir") + File.separator + "logs" + File.separator
                        + "arthas" + File.separator);
                if (!arthasLogDir.exists()) {
                    arthasLogDir.mkdirs();
                }
            }

            File log = new File(arthasLogDir, "arthas.log");

            if (!log.exists()) {
                log.createNewFile();
            }
            ps = new PrintStream(new FileOutputStream(log, true));
        } catch (Throwable t) {
            t.printStackTrace(ps);
        }
    }

    /**
     * 
     * 1. 全局持有classloader用于隔离 Arthas 实现,防止多次attach重复初始化
     * 2. ClassLoader在arthas停止时会被reset
     * 3. 如果ClassLoader一直没变,则 com.taobao.arthas.core.server.ArthasBootstrap#getInstance 返回结果一直是一样的
     * 
*/ 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 static void resetArthasClassLoader() { arthasClassLoader = null; } private static ClassLoader getClassLoader(Instrumentation inst, File arthasCoreJarFile) throws Throwable { // 构造自定义的类加载器,尽量减少Arthas对现有工程的侵蚀 return loadOrDefineClassLoader(arthasCoreJarFile); } private static ClassLoader loadOrDefineClassLoader(File arthasCoreJarFile) throws Throwable { if (arthasClassLoader == null) { arthasClassLoader = new ArthasClassloader(new URL[]{arthasCoreJarFile.toURI().toURL()}); } return arthasClassLoader; } private static synchronized void main(String args, final Instrumentation inst) { // 尝试判断arthas是否已在运行,如果是的话,直接就退出 try { Class.forName("java.arthas.SpyAPI"); // 加载不到会抛异常 if (SpyAPI.isInited()) { ps.println("Arthas server already stared, skip attach."); ps.flush(); return; } } catch (Throwable e) { // ignore } try { ps.println("Arthas server agent start..."); // 传递的args参数分两个部分:arthasCoreJar路径和agentArgs, 分别是Agent的JAR包路径和期望传递到服务端的参数 if (args == null) { args = ""; } args = decodeArg(args); String arthasCoreJar; final String agentArgs; int index = args.indexOf(';'); if (index != -1) { arthasCoreJar = args.substring(0, index); agentArgs = args.substring(index); } else { arthasCoreJar = ""; agentArgs = args; } File arthasCoreJarFile = new File(arthasCoreJar); if (!arthasCoreJarFile.exists()) { ps.println("Can not find arthas-core jar file from args: " + arthasCoreJarFile); // try to find from arthas-agent.jar directory CodeSource codeSource = AgentBootstrap.class.getProtectionDomain().getCodeSource(); if (codeSource != null) { try { File arthasAgentJarFile = new File(codeSource.getLocation().toURI().getSchemeSpecificPart()); arthasCoreJarFile = new File(arthasAgentJarFile.getParentFile(), ARTHAS_CORE_JAR); if (!arthasCoreJarFile.exists()) { ps.println("Can not find arthas-core jar file from agent jar directory: " + arthasAgentJarFile); } } catch (Throwable e) { ps.println("Can not find arthas-core jar file from " + codeSource.getLocation()); e.printStackTrace(ps); } } } if (!arthasCoreJarFile.exists()) { return; } /** * Use a dedicated thread to run the binding logic to prevent possible memory leak. #195 */ final ClassLoader agentLoader = getClassLoader(inst, arthasCoreJarFile); 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 { /** *
         * ArthasBootstrap bootstrap = ArthasBootstrap.getInstance(inst);
         * 
*/ Class bootstrapClass = agentLoader.loadClass(ARTHAS_BOOTSTRAP); Object bootstrap = bootstrapClass.getMethod(GET_INSTANCE, Instrumentation.class, String.class).invoke(null, inst, args); boolean isBind = (Boolean) bootstrapClass.getMethod(IS_BIND).invoke(bootstrap); if (!isBind) { String errorMsg = "Arthas server port binding failed! Please check $HOME/logs/arthas/arthas.log for more details."; ps.println(errorMsg); throw new RuntimeException(errorMsg); } ps.println("Arthas server already bind."); } private static String decodeArg(String arg) { try { return URLDecoder.decode(arg, "utf-8"); } catch (UnsupportedEncodingException e) { return arg; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy