From ca08d1a28bdacaaded995bf541de4e1dbb30aae9 Mon Sep 17 00:00:00 2001
From: ScienJus
Date: Wed, 7 Nov 2018 23:15:36 +0800
Subject: [PATCH] Support for overriding config with agent options (#1887)
* Support for overriding config with agent options
* Test the separator of options
* support quotes in agent options
* revert imports change
* add more tests
* clear properties after each test
* add document
* fix code style
---
.../core/conf/SnifferConfigInitializer.java | 55 +++++++++++++++-
.../conf/SnifferConfigInitializerTest.java | 65 +++++++++++++++++--
.../skywalking/apm/agent/SkyWalkingAgent.java | 2 +-
.../java-agent/Setting-override.md | 45 ++++++++++---
4 files changed, 152 insertions(+), 15 deletions(-)
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/SnifferConfigInitializer.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/SnifferConfigInitializer.java
index d33d304717..325557140a 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/SnifferConfigInitializer.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/SnifferConfigInitializer.java
@@ -24,7 +24,9 @@ import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.skywalking.apm.agent.core.boot.AgentPackageNotFoundException;
@@ -56,7 +58,7 @@ public class SnifferConfigInitializer {
*
* At the end, `agent.application_code` and `collector.servers` must be not blank.
*/
- public static void initialize() throws ConfigNotFoundException, AgentPackageNotFoundException {
+ public static void initialize(String agentOptions) throws ConfigNotFoundException, AgentPackageNotFoundException {
InputStreamReader configFileStream;
try {
@@ -74,6 +76,17 @@ public class SnifferConfigInitializer {
logger.error(e, "Failed to read the system env.");
}
+ if (!StringUtil.isEmpty(agentOptions)) {
+ try {
+ agentOptions = agentOptions.trim();
+ logger.info("Agent options is {}.", agentOptions);
+
+ overrideConfigByAgentOptions(agentOptions);
+ } catch (Exception e) {
+ logger.error(e, "Failed to parse the agent options, val is {}.", agentOptions);
+ }
+ }
+
if (StringUtil.isEmpty(Config.Agent.APPLICATION_CODE)) {
throw new ExceptionInInitializerError("`agent.application_code` is missing.");
}
@@ -84,6 +97,46 @@ public class SnifferConfigInitializer {
IS_INIT_COMPLETED = true;
}
+ private static void overrideConfigByAgentOptions(String agentOptions) throws IllegalAccessException {
+ Properties properties = new Properties();
+ for (List terms : parseAgentOptions(agentOptions)) {
+ if (terms.size() != 2) {
+ throw new IllegalArgumentException("[" + terms + "] is not a key-value pair.");
+ }
+ properties.put(terms.get(0), terms.get(1));
+ }
+ if (!properties.isEmpty()) {
+ ConfigInitializer.initialize(properties, Config.class);
+ }
+ }
+
+ private static List> parseAgentOptions(String agentOptions) {
+ List> options = new ArrayList>();
+ List terms = new ArrayList();
+ boolean isInQuotes = false;
+ StringBuilder currentTerm = new StringBuilder();
+ for (char c : agentOptions.toCharArray()) {
+ if (c == '\'' || c == '"') {
+ isInQuotes = !isInQuotes;
+ } else if (c == '=' && !isInQuotes) { // key-value pair uses '=' as separator
+ terms.add(currentTerm.toString());
+ currentTerm = new StringBuilder();
+ } else if (c == ',' && !isInQuotes) { // multiple options use ',' as separator
+ terms.add(currentTerm.toString());
+ currentTerm = new StringBuilder();
+
+ options.add(terms);
+ terms = new ArrayList();
+ } else {
+ currentTerm.append(c);
+ }
+ }
+ // add the last term and option without separator
+ terms.add(currentTerm.toString());
+ options.add(terms);
+ return options;
+ }
+
public static boolean isInitCompleted() {
return IS_INIT_COMPLETED;
}
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/SnifferConfigInitializerTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/SnifferConfigInitializerTest.java
index 814c3cd3bc..edd81c97bc 100644
--- a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/SnifferConfigInitializerTest.java
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/conf/SnifferConfigInitializerTest.java
@@ -21,11 +21,15 @@ package org.apache.skywalking.apm.agent.core.conf;
import org.apache.skywalking.apm.agent.core.boot.AgentPackageNotFoundException;
import org.apache.skywalking.apm.agent.core.logging.core.LogLevel;
-import org.junit.AfterClass;
+import org.junit.After;
import org.junit.Test;
+import java.util.Iterator;
+import java.util.Map;
+
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
public class SnifferConfigInitializerTest {
@@ -34,14 +38,67 @@ public class SnifferConfigInitializerTest {
System.setProperty("skywalking.agent.application_code", "testApp");
System.setProperty("skywalking.collector.backend_service", "127.0.0.1:8090");
System.setProperty("skywalking.logging.level", "info");
- SnifferConfigInitializer.initialize();
+ SnifferConfigInitializer.initialize(null);
assertThat(Config.Agent.APPLICATION_CODE, is("testApp"));
assertThat(Config.Collector.BACKEND_SERVICE, is("127.0.0.1:8090"));
assertThat(Config.Logging.LEVEL, is(LogLevel.INFO));
}
- @AfterClass
- public static void clear() {
+ @Test
+ public void testLoadConfigFromAgentOptions() throws AgentPackageNotFoundException, ConfigNotFoundException {
+ String agentOptions = "agent.application_code=testApp,collector.backend_service=127.0.0.1:8090,logging.level=info";
+ SnifferConfigInitializer.initialize(agentOptions);
+ assertThat(Config.Agent.APPLICATION_CODE, is("testApp"));
+ assertThat(Config.Collector.BACKEND_SERVICE, is("127.0.0.1:8090"));
+ assertThat(Config.Logging.LEVEL, is(LogLevel.INFO));
+ }
+
+ @Test
+ public void testConfigOverriding() throws AgentPackageNotFoundException, ConfigNotFoundException {
+ System.setProperty("skywalking.agent.application_code", "testAppFromSystem");
+ System.setProperty("skywalking.collector.backend_service", "127.0.0.1:8090");
+ String agentOptions = "agent.application_code=testAppFromAgentOptions,logging.level=debug";
+ SnifferConfigInitializer.initialize(agentOptions);
+ assertThat(Config.Agent.APPLICATION_CODE, is("testAppFromAgentOptions"));
+ assertThat(Config.Collector.BACKEND_SERVICE, is("127.0.0.1:8090"));
+ assertThat(Config.Logging.LEVEL, is(LogLevel.DEBUG));
+ }
+
+ @Test
+ public void testAgentOptionsSeparator() throws AgentPackageNotFoundException, ConfigNotFoundException {
+ System.setProperty("skywalking.agent.application_code", "testApp");
+ System.setProperty("skywalking.collector.backend_service", "127.0.0.1:8090");
+ String agentOptions = "agent.ignore_suffix='.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg'";
+ SnifferConfigInitializer.initialize(agentOptions);
+ assertThat(Config.Agent.IGNORE_SUFFIX, is(".jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg"));
+ }
+
+ @Test
+ public void testAgentOptionsParser() throws AgentPackageNotFoundException, ConfigNotFoundException {
+ System.setProperty("skywalking.collector.backend_service", "127.0.0.1:8090");
+ String agentOptions = "agent.application_code=test=abc";
+ try {
+ SnifferConfigInitializer.initialize(agentOptions);
+ fail("test=abc without quotes is not a valid value");
+ } catch (ExceptionInInitializerError e) {
+ // ignore
+ }
+ agentOptions = "agent.application_code='test=abc'";
+ SnifferConfigInitializer.initialize(agentOptions);
+ assertThat(Config.Agent.APPLICATION_CODE, is("test=abc"));
+ }
+
+ @After
+ public void clear() {
+ Iterator> it = System.getProperties().entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry