package com.alibaba.ttl.threadpool.agent; import com.alibaba.ttl.threadpool.agent.internal.logging.Logger; import com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlExecutorTransformlet; import com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlForkJoinTransformlet; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; /** * TTL Java Agent. *

* NOTE:
* Since {@code v2.6.0}, TTL agent jar will auto add self to {@code boot classpath}. * But you should NOT modify the downloaded TTL jar file name.
* 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}. *

* 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: *

*
*
Boot-Class-Path
*
* 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. *
*
*
*

* More info about {@code Boot-Class-Path} see * The mechanism for instrumentation. * * @author Jerry Lee (oldratlee at gmail dot com) * @see Instrumentation * @see The mechanism for instrumentation * @see JAR File Specification - JAR Manifest * @see Working with Manifest Files - The Java™ TutorialsHide * @since 0.9.0 */ public final class TtlAgent { private TtlAgent() { throw new InstantiationError("Must not instantiate this class"); } /** * Entrance method of TTL Java Agent. *

* The log of TTL Java Agent is config by agent argument, using key {@code ttl.agent.logger}. * *

*

* configuration example: *

* * @see The mechanism for instrumentation * @see Logger * @see Logger#TTL_AGENT_LOGGER_KEY * @see Logger#STDERR * @see Logger#STDOUT */ public static void premain(String agentArgs, Instrumentation inst) { Logger.setLoggerImplType(getLogImplTypeFromAgentArgs(agentArgs)); final Logger logger = Logger.getLogger(TtlAgent.class); try { logger.info("[TtlAgent.premain] begin, agentArgs: " + agentArgs + ", Instrumentation: " + inst); @SuppressWarnings("unchecked") ClassFileTransformer transformer = new TtlTransformer(TtlExecutorTransformlet.class, TtlForkJoinTransformlet.class); inst.addTransformer(transformer, true); logger.info("[TtlAgent.premain] addTransformer " + transformer.getClass() + " success"); logger.info("[TtlAgent.premain] end"); } catch (Exception e) { String msg = "Fail to load TtlAgent , cause: " + e.toString(); logger.log(Level.SEVERE, msg, e); throw new IllegalStateException(msg, e); } } private static String getLogImplTypeFromAgentArgs(String agentArgs) { final Map kv = splitCommaColonStringToKV(agentArgs); return kv.get(Logger.TTL_AGENT_LOGGER_KEY); } /** * Split to {@code json} like String({@code "k1:v1,k2:v2"}) to KV map({"k1"->"v1", "k2" -> "v2"}). */ static Map splitCommaColonStringToKV(String commaColonString) { Map ret = new HashMap(); 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; } }