diff --git a/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java b/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java
index 825f04f2af845545a0b565d149ed2ceac00de734..289e84a6439297771ea2b03edbd55bec961083fb 100644
--- a/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java
+++ b/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java
@@ -16,14 +16,44 @@ import java.util.Map;
/**
* TTL Java Agent.
*
- *
The configuration/arguments for TTL agent
+ * The configuration for TTL agent
*
- * Configure TTL agent via agent arguments, format is {@code k1:v1,k2:v2}. Below is available configuration keys.
+ * Configure TTL agent via {@code -D property}({@link System#getProperties()}) or TTL agent arguments.
+ *
+ * - {@code -D property} config format is: {@code -Dkey1=v2 -Dkey2=v2}
+ * - TTL agent arguments config format is {@code key1:v1,key2:v2}.
+ * separate key-value pairs by {@code char ,}, and separate key-value by {@code char :}.
+ *
+ * NOTE about the config sources and the precedence:
+ *
+ * - Read {@code -D property}({@link System#getProperties()}) first.
+ * - if no {@code -D property} configured(including empty property value configured by {@code -Dkey1}/{@code -Dkey1=}), read TTL Agent argument configuration.
+ *
+ * Below is available TTL agent configuration keys.
*
- * Disable inheritable for thread pool
+ * Configuration key: Log Type
+ *
+ * The log of TTL Java Agent is configured by key {@code ttl.agent.logger}. Since version {@code 2.6.0}.
+ *
+ *
+ * - {@code ttl.agent.logger : STDERR}
+ * only log to {@code stderr} when error.
+ * This is default, when no/unrecognized configuration for key {@code ttl.agent.logger}.
+ * - {@code ttl.agent.logger : STDOUT}
+ * Log to {@code stdout}, more info than {@code ttl.agent.logger:STDERR}; This is needed when developing.
+ *
+ *
+ * Configuration example:
+ *
+ *
+ * - {@code -Dttl.agent.logger=STDOUT}
+ * - {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT}
+ *
+ *
+ * Configuration key: Disable inheritable for thread pool
*
* Enable "disable inheritable" for thread pool, config by key {@code ttl.agent.disable.inheritable.for.thread.pool}.
- * When no configuration for this key, default does not enabled. Since version {@code 2.10.1}.
+ * When no configuration for this key, default is {@code false}(aka. dose not disable inheritable). Since version {@code 2.10.1}.
*
*
* - rewrite the {@link java.util.concurrent.ThreadFactory} constructor parameter
@@ -39,27 +69,15 @@ import java.util.Map;
*
* More info about "disable inheritable" see {@link com.alibaba.ttl.TransmittableThreadLocal}.
*
- * Configuration example:
- * {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.disable.inheritable.for.thread.pool:true}
+ * Configuration example:
*
- *
The log configuration
- * The log of TTL Java Agent is config by key {@code ttl.agent.logger}. Since version {@code 2.6.0}.
+ *
+ * - {@code -Dttl.agent.disable.inheritable.for.thread.pool=true}
+ * - {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.disable.inheritable.for.thread.pool:true}
+ *
*
- *
- * - {@code ttl.agent.logger : STDERR}
- * only log to {@code stderr} when error.
- * This is default, when no/unrecognized configuration for key {@code ttl.agent.logger}.
- * - {@code ttl.agent.logger : STDOUT}
- * Log to {@code stdout}, more info than {@code ttl.agent.logger:STDERR}; This is needed when developing.
- *
+ * Configuration key: Enable/Disable TimerTask class decoration
*
- * configuration example:
- *
- * - {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar}
- * - {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT}
- *
- *
- * Enable/disable TimerTask class decoration
* Enable/disable TimerTask class decoration is config by key {@code ttl.agent.enable.timer.task}.
* Since version {@code 2.7.0}.
*
@@ -68,16 +86,23 @@ import java.util.Map;
* Before version {@code 2.11.1} default value is {@code false}.
*
* Configuration example:
- *
+ *
+ *
+ * - {@code -Dttl.agent.enable.timer.task=false}
* - {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:false}
- * - {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:true}
- *
+ *
*
* Multi key configuration example
+ *
+ * For TTL agent arguments config, example:
* {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT,ttl.agent.disable.inheritable.for.thread.pool:true}
+ *
+ * For {@code -D property} config, simply specify multiply {@code -D property}, example:
+ * {@code -Dttl.agent.logger=STDOUT -Dttl.agent.disable.inheritable.for.thread.pool=true}
*
*
About boot classpath for TTL agent
- * NOTE: Since {@code v2.6.0}, TTL agent jar will auto add self to {@code boot classpath}.
+ *
+ * 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 in the maven repo(eg: {@code transmittable-thread-local-2.x.y.jar}).
* 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
@@ -111,18 +136,28 @@ import java.util.Map;
* @since 0.9.0
*/
public final class TtlAgent {
+
+ private static final String TTL_AGENT_LOGGER_KEY = "ttl.agent.logger";
+
+ private static final String TTL_AGENT_LOG_CLASS_TRANSFORM_KEY = "ttl.agent.log.class.transform";
+
+ private static final String TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY = "ttl.agent.disable.inheritable.for.thread.pool";
+
+ private static final String TTL_AGENT_ENABLE_TIMER_TASK_KEY = "ttl.agent.enable.timer.task";
+
+ private static volatile Map kvs;
+
+ private static volatile boolean ttlAgentLoaded = false;
+
/**
* Entrance method of TTL Java Agent.
*
- * @see Logger
- * @see Logger#TTL_AGENT_LOGGER_KEY
- * @see Logger#STDERR
- * @see Logger#STDOUT
+ * @see TtlAgent
*/
public static void premain(final String agentArgs, @NonNull final Instrumentation inst) {
kvs = TtlAgentHelper.splitCommaColonStringToKV(agentArgs);
- Logger.setLoggerImplType(getLogImplTypeFromAgentArgs(kvs));
+ Logger.setLoggerImplType(getLoggerType());
final Logger logger = Logger.getLogger(TtlAgent.class);
try {
@@ -133,8 +168,7 @@ public final class TtlAgent {
transformletList.add(new ForkJoinTtlTransformlet());
if (isEnableTimerTask()) transformletList.add(new TimerTaskTtlTransformlet());
- final boolean logClassTransform = isBooleanOptionSet(TTL_AGENT_LOG_CLASS_TRANSFORM_KEY, false);
- final ClassFileTransformer transformer = new TtlTransformer(transformletList, logClassTransform);
+ final ClassFileTransformer transformer = new TtlTransformer(transformletList, isLogClassTransform());
inst.addTransformer(transformer, true);
logger.info("[TtlAgent.premain] add Transformer " + transformer.getClass().getName() + " success");
@@ -148,14 +182,6 @@ public final class TtlAgent {
}
}
- private static volatile Map kvs;
-
- private static volatile boolean ttlAgentLoaded = false;
-
- private static String getLogImplTypeFromAgentArgs(@NonNull final Map kvs) {
- return kvs.get(Logger.TTL_AGENT_LOGGER_KEY);
- }
-
/**
* Whether TTL agent is loaded.
*
@@ -165,14 +191,10 @@ public final class TtlAgent {
return ttlAgentLoaded;
}
- private static final String TTL_AGENT_LOG_CLASS_TRANSFORM_KEY = "ttl.agent.log.class.transform";
-
- private static final String TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY = "ttl.agent.disable.inheritable.for.thread.pool";
-
- private static final String TTL_AGENT_ENABLE_TIMER_TASK_KEY = "ttl.agent.enable.timer.task";
-
/**
* Whether disable inheritable for thread pool is enhanced by ttl agent, check {@link #isTtlAgentLoaded()} first.
+ *
+ * Same as {@code isBooleanOptionSet(TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY)}.
*
* @see com.alibaba.ttl.threadpool.TtlExecutors#getDefaultDisableInheritableThreadFactory()
* @see com.alibaba.ttl.threadpool.TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)
@@ -180,19 +202,24 @@ public final class TtlAgent {
* @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory()
* @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory)
* @see com.alibaba.ttl.threadpool.DisableInheritableForkJoinWorkerThreadFactory
+ * @see com.alibaba.ttl.TransmittableThreadLocal
+ * @see #isBooleanOptionSet(String)
+ * @see TtlAgent
* @since 2.10.1
*/
public static boolean isDisableInheritableForThreadPool() {
- return isBooleanOptionSet(TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY, false);
+ return isBooleanOptionSet(TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY);
}
/**
* Whether timer task is enhanced by ttl agent, check {@link #isTtlAgentLoaded()} first.
*
- * Same as {@code isBooleanOptionSet(TTL_AGENT_ENABLE_TIMER_TASK_KEY, true)}
+ * Same as {@code isBooleanOptionSet(TTL_AGENT_ENABLE_TIMER_TASK_KEY, true)}.
*
* @see java.util.Timer
* @see java.util.TimerTask
+ * @see #isBooleanOptionSet(String, boolean)
+ * @see TtlAgent
* @since 2.10.1
*/
public static boolean isEnableTimerTask() {
@@ -200,38 +227,92 @@ public final class TtlAgent {
}
/**
+ * Whether logging the class transform when the class received by {@link TtlAgent}.
+ *
+ * Same as {@code isBooleanOptionSet(TTL_AGENT_LOG_CLASS_TRANSFORM_KEY)}.
+ *
+ * @see #isBooleanOptionSet(String)
+ * @see TtlAgent
* @since 2.13.0
*/
- public static boolean isBooleanOptionSet(@NonNull String key, boolean defaultValue) {
- return TtlAgentHelper.isBooleanOptionSet(kvs, key, defaultValue);
+ public static boolean isLogClassTransform() {
+ return isBooleanOptionSet(TTL_AGENT_LOG_CLASS_TRANSFORM_KEY);
}
/**
- * Get option value in TTL Agent configuration.
+ * Get the TTL Agent Log type.
+ *
+ * Same as {@code getStringOptionValue(TTL_AGENT_LOGGER_KEY, Logger.STDERR)}.
+ *
+ * @see Logger
+ * @see Logger#STDERR
+ * @see Logger#STDOUT
+ * @see #getStringOptionValue(String, String)
+ * @see TtlAgent
+ * @since 2.13.0
+ */
+ @NonNull
+ public static String getLoggerType() {
+ return getStringOptionValue(TTL_AGENT_LOGGER_KEY, Logger.STDERR);
+ }
+
+ // ======== Generic Option Getters ========
+
+ /**
+ * Generic Option Getters for {@code boolean type} option.
+ *
+ * @see TtlAgent
+ * @since 2.13.0
+ */
+ public static boolean isBooleanOptionSet(@NonNull String key) {
+ return isBooleanOptionSet(key, false);
+ }
+
+ /**
+ * Generic Option Getters for {@code boolean type} option.
+ *
+ * @see TtlAgent
+ * @since 2.13.0
+ */
+ public static boolean isBooleanOptionSet(@NonNull String key, boolean defaultValueIfKeyAbsent) {
+ return TtlAgentHelper.isBooleanOptionSet(kvs, key, defaultValueIfKeyAbsent);
+ }
+
+ /**
+ * Generic Option Getters for {@code string type} option.
*
* usage example:
*
- * if TTL Agent configuration is {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT},
+ * if {@code -Dttl.agent.logger=STDOUT} or
+ * TTL Agent configuration is {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT},
* {@code getOptionValue("ttl.agent.logger")} return {@code STDOUT}.
*
+ * @see TtlAgent
* @since 2.13.0
*/
- public static String getOptionValue(@NonNull String key) {
- return kvs.get(key);
+ @NonNull
+ public static String getStringOptionValue(@NonNull String key, @NonNull String defaultValue) {
+ return TtlAgentHelper.getStringOptionValue(kvs, key, defaultValue);
}
/**
- * Get list string values of specified option in TTL Agent configuration.
+ * Generic Option Getters for {@code string list type} option.
+ *
+ * TTL configuration use {@code |} to separate items.
*
- * TTL Agent configuration use {@code |} to separate items.
- * if TTL Agent configuration is {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=foo.list:v1|v2|v3},
+ * usage example:
+ * if {@code -Dfoo.list=v1|v2|v3} or
+ * TTL Agent configuration is {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=foo.list:v1|v2|v3},
* {@code getOptionValue("foo.list")} return {@code [v1, v2, v3]}.
+ *
+ * @see TtlAgent
*/
@NonNull
static List getOptionStringListValues(@NonNull String key) {
return TtlAgentHelper.getOptionStringListValues(kvs, key);
}
+
private TtlAgent() {
throw new InstantiationError("Must not instantiate this class");
}
diff --git a/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgentHelper.java b/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgentHelper.java
index 50aaf84077dcd0fdd02c48ceb482b5f8d6d3fdd0..7568459ba9d126f72bd86d3885e309cb02b431e1 100644
--- a/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgentHelper.java
+++ b/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgentHelper.java
@@ -10,23 +10,84 @@ import java.util.*;
* @since 2.13.0
*/
final class TtlAgentHelper {
- static boolean isBooleanOptionSet(@Nullable final Map kvs, @NonNull String key, boolean defaultValue) {
- if (null == kvs) return defaultValue;
- final boolean containsKey = kvs.containsKey(key);
- if (!containsKey) return defaultValue;
+ // ======== Option Getter Methods ========
- return !"false".equalsIgnoreCase(kvs.get(key));
+ static boolean isBooleanOptionSet(
+ @Nullable final Map kvs, @NonNull String key,
+ boolean defaultValueIfKeyAbsent
+ ) {
+ return isBooleanOptionSet(kvs, key, defaultValueIfKeyAbsent, true);
}
+ static boolean isBooleanOptionSet(
+ @Nullable final Map kvs, @NonNull String key,
+ boolean defaultValueIfKeyAbsent, boolean defaultValueIfValueAbsent
+ ) {
+ final String value;
+
+ final Properties properties = System.getProperties();
+ if (properties.containsKey(key)) {
+ value = properties.getProperty(key).trim();
+ } else {
+ if (kvs == null) return defaultValueIfKeyAbsent;
+
+ final boolean containsKey = kvs.containsKey(key);
+ if (!containsKey) return defaultValueIfKeyAbsent;
+
+ value = kvs.get(key).trim();
+ }
+
+ // if value is blank
+ if (value.isEmpty()) return defaultValueIfValueAbsent;
+
+ return !"false".equalsIgnoreCase(value);
+ }
+
+ @NonNull
+ static String getStringOptionValue(
+ @Nullable final Map kvs, @NonNull String key,
+ @NonNull String defaultValue
+ ) {
+ final String value;
+
+ final Properties properties = System.getProperties();
+ if (properties.containsKey(key)) {
+ value = properties.getProperty(key).trim();
+ } else {
+ if (kvs == null) return defaultValue;
+
+ final boolean containsKey = kvs.containsKey(key);
+ if (!containsKey) return defaultValue;
+
+ value = kvs.get(key).trim();
+ }
+
+ // if value is blank
+ if (value.isEmpty()) return defaultValue;
+
+ return value;
+ }
+
+ @NonNull
@SuppressWarnings("unchecked")
static List getOptionStringListValues(@Nullable final Map kvs, @NonNull String key) {
- if (null == kvs) return Collections.EMPTY_LIST;
+ final String value;
+
+ final Properties properties = System.getProperties();
+ if (properties.containsKey(key)) {
+ value = properties.getProperty(key);
+ } else {
+ if (kvs == null) return Collections.EMPTY_LIST;
+
+ value = kvs.get(key);
+ }
- final String value = kvs.get(key);
return splitListStringToStringList(value);
}
+ // ======== Simple Parse Util Methods ========
+
/**
* Split {@code json} like String({@code "k1:v1,k2:v2"}) to KV map({@code "k1"->"v1", "k2"->"v2"}).
*/
@@ -50,6 +111,7 @@ final class TtlAgentHelper {
/**
* Split String {@code "v1|v2|v3"} to String List({@code [v1, v2, v3]}).
*/
+ @NonNull
static List splitListStringToStringList(@Nullable String listString) {
final List ret = new ArrayList();
if (listString == null || listString.trim().length() == 0) return ret;
@@ -64,6 +126,7 @@ final class TtlAgentHelper {
return ret;
}
+
private TtlAgentHelper() {
throw new InstantiationError("Must not instantiate this class");
}
diff --git a/src/main/java/com/alibaba/ttl/threadpool/agent/logging/Logger.java b/src/main/java/com/alibaba/ttl/threadpool/agent/logging/Logger.java
index e4775ff4f652aec29e0c9850290ac148991f246b..7167ec0bc34d01ce23cfdc50b9e0edee13f6c4b1 100644
--- a/src/main/java/com/alibaba/ttl/threadpool/agent/logging/Logger.java
+++ b/src/main/java/com/alibaba/ttl/threadpool/agent/logging/Logger.java
@@ -13,7 +13,6 @@ import java.util.logging.Level;
* @since 2.6.0
*/
public abstract class Logger {
- public static final String TTL_AGENT_LOGGER_KEY = "ttl.agent.logger";
public static final String STDOUT = "STDOUT";
public static final String STDERR = "STDERR";