TtlAgent.java 5.3 KB
Newer Older
1
package com.alibaba.ttl.threadpool.agent;
2 3


oldratlee's avatar
oldratlee 已提交
4
import com.alibaba.ttl.threadpool.agent.internal.logging.Logger;
5 6
import com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlExecutorTransformlet;
import com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlForkJoinTransformlet;
7

8 9
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
10 11
import java.util.HashMap;
import java.util.Map;
12
import java.util.logging.Level;
13

14
/**
15
 * TTL Java Agent.
oldratlee's avatar
oldratlee 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
 * <p>
 * <b><i>NOTE:</i></b><br>
 * Since {@code v2.6.0}, TTL agent jar will auto add self to {@code boot classpath}.
 * But you <b>should <i>NOT</i></b> modify the downloaded TTL jar file name.<br>
 * if you modified the downloaded TTL agent jar file name(eg: {@code ttl-foo-name-changed.jar}),
 * you must add TTL agent jar to {@code boot classpath} manually
 * by java option {@code -Xbootclasspath/a:path/to/ttl-foo-name-changed.jar}.
 * <p>
 * The implementation of auto adding self agent jar to {@code boot classpath} use
 * the {@code Boot-Class-Path} property of manifest file({@code META-INF/MANIFEST.MF}) in the TTL Java Agent Jar:
 * <blockquote>
 * <dl>
 * <dt>Boot-Class-Path</dt>
 * <dd>
 * A list of paths to be searched by the bootstrap class loader. Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms).
 * These paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed. Paths are searched in the order listed.
 * </dd>
 * </dl>
 * </blockquote>
 * <p>
 * More info about {@code Boot-Class-Path} see
 * <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html">The mechanism for instrumentation</a>.
38
 *
oldratlee's avatar
oldratlee 已提交
39
 * @author Jerry Lee (oldratlee at gmail dot com)
oldratlee's avatar
oldratlee 已提交
40
 * @see Instrumentation
41
 * @see <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html">The mechanism for instrumentation</a>
oldratlee's avatar
oldratlee 已提交
42 43
 * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#JAR_Manifest">JAR File Specification - JAR Manifest</a>
 * @see <a href="https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html">Working with Manifest Files - The Java™ TutorialsHide</a>
oldratlee's avatar
oldratlee 已提交
44
 * @since 0.9.0
45
 */
S
smisger 已提交
46 47
public final class TtlAgent {
    private TtlAgent() {
48
        throw new InstantiationError("Must not instantiate this class");
S
smisger 已提交
49
    }
50

oldratlee's avatar
oldratlee 已提交
51 52 53 54 55 56 57 58 59 60
    /**
     * Entrance method of TTL Java Agent.
     * <p>
     * The log of TTL Java Agent is config by agent argument, using key {@code ttl.agent.logger}.
     *
     * <ul>
     * <li>{@code ttl.agent.logger : STDERR}<br>
     * only log to {@code stderr} when error.
     * This is <b>default</b>, when no/unrecognized configuration for key {@code ttl.agent.logger}.</li>
     * <li>{@code ttl.agent.logger : STDOUT}<br>
61
     * log to {@code stdout}, more info than {@code ttl.agent.logger : STDERR} is needed when developing.</li>
oldratlee's avatar
oldratlee 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
     * </ul>
     * <p>
     * configuration example:
     * <ul>
     * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.6.0.jar}</li>
     * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.6.0.jar=ttl.agent.logger:STDOUT}</li>
     * </ul>
     *
     * @see <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html">The mechanism for instrumentation</a>
     * @see Logger
     * @see Logger#TTL_AGENT_LOGGER_KEY
     * @see Logger#STDERR
     * @see Logger#STDOUT
     */
    public static void premain(String agentArgs, Instrumentation inst) {
77 78
        Logger.setLoggerImplType(getLogImplTypeFromAgentArgs(agentArgs));
        final Logger logger = Logger.getLogger(TtlAgent.class);
79

80
        try {
81
            logger.info("[TtlAgent.premain] begin, agentArgs: " + agentArgs + ", Instrumentation: " + inst);
82

83 84
            @SuppressWarnings("unchecked")
            ClassFileTransformer transformer = new TtlTransformer(TtlExecutorTransformlet.class, TtlForkJoinTransformlet.class);
85 86
            inst.addTransformer(transformer, true);
            logger.info("[TtlAgent.premain] addTransformer " + transformer.getClass() + " success");
87

88 89 90
            logger.info("[TtlAgent.premain] end");
        } catch (Exception e) {
            String msg = "Fail to load TtlAgent , cause: " + e.toString();
91
            logger.log(Level.SEVERE, msg, e);
92 93 94
            throw new IllegalStateException(msg, e);
        }
    }
95 96 97

    private static String getLogImplTypeFromAgentArgs(String agentArgs) {
        final Map<String, String> kv = splitCommaColonStringToKV(agentArgs);
oldratlee's avatar
oldratlee 已提交
98
        return kv.get(Logger.TTL_AGENT_LOGGER_KEY);
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    }

    /**
     * Split to {@code json} like String({@code "k1:v1,k2:v2"}) to KV map({"k1"->"v1", "k2" -> "v2"}).
     */
    static Map<String, String> splitCommaColonStringToKV(String commaColonString) {
        Map<String, String> ret = new HashMap<String, String>();
        if (commaColonString == null || commaColonString.trim().length() == 0) return ret;

        final String[] splitKvArray = commaColonString.trim().split("\\s*,\\s*");
        for (String kvString : splitKvArray) {
            final String[] kv = kvString.trim().split("\\s*:\\s*");
            if (kv.length == 0) continue;

            if (kv.length == 1) ret.put(kv[0], "");
            else {
                ret.put(kv[0], kv[1]);
            }
        }

        return ret;
    }
121
}