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
This commit is contained in:
ScienJus 2018-11-07 23:15:36 +08:00 committed by 吴晟 Wu Sheng
parent bdfd531809
commit ca08d1a28b
4 changed files with 152 additions and 15 deletions

View File

@ -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 {
* <p>
* 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<String> 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<List<String>> parseAgentOptions(String agentOptions) {
List<List<String>> options = new ArrayList<List<String>>();
List<String> terms = new ArrayList<String>();
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<String>();
} 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;
}

View File

@ -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<Map.Entry<Object, Object>> it = System.getProperties().entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Object, Object> entry = it.next();
if (entry.getKey().toString().startsWith("skywalking.")) {
it.remove();
}
}
Config.Agent.APPLICATION_CODE = "";
Config.Logging.LEVEL = LogLevel.DEBUG;
}
}

View File

@ -61,7 +61,7 @@ public class SkyWalkingAgent {
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
final PluginFinder pluginFinder;
try {
SnifferConfigInitializer.initialize();
SnifferConfigInitializer.initialize(agentArgs);
pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());

View File

@ -1,22 +1,49 @@
# Setting Override
In default, SkyWalking provide `agent.config` for agent
In default, SkyWalking provide `agent.config` for agent.
Setting override means end user can override the settings in these config file, through using system properties.
Setting override means end user can override the settings in these config file, through using system properties or agent options.
## System properties
Use `skywalking.` + key in config file as system properties key, to override the value.
- Why need this prefix?
The agent system properites and env share with target application, this prefix can avoid variable conflict.
- Override priority
System.Properties(-D) > Config file
The agent system properties and env share with target application, this prefix can avoid variable conflict.
- Example
Override `agent.application_code` by this.
```
-Dskywalking.agent.application_code=31200
```
```
## Agent options
Add the properties after the agent path in JVM arguments.
```
-javaagent:/path/to/skywalking-agent.jar=[option1]=[value1],[option2]=[value2]
```
- Example
Override `agent.application_code` and `logging.level` by this.
```
-javaagent:/path/to/skywalking-agent.jar=agent.application_code=31200,logging.level=debug
```
- Special characters
If a separator(`,` or `=`) in the option or value, it should be wrapped in quotes.
```
-javaagent:/path/to/skywalking-agent.jar=agent.ignore_suffix='.jpg,.jpeg'
```
## Override priority
Agent Options > System.Properties(-D) > Config file