diff --git a/config/pom.xml b/config/pom.xml index 57d9b415..c66a64c7 100644 --- a/config/pom.xml +++ b/config/pom.xml @@ -53,10 +53,19 @@ ${project.version} test - org.yaml snakeyaml + + com.google.guava + guava + + + com.github.stefanbirkner + system-rules + 1.19.0 + test + diff --git a/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java b/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java index 05fab1f7..171c9061 100644 --- a/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java +++ b/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java @@ -19,52 +19,61 @@ import com.megaease.easeagent.log4j2.Logger; import com.megaease.easeagent.log4j2.LoggerFactory; +import com.megaease.easeagent.plugin.utils.ImmutableMap; import com.megaease.easeagent.plugin.utils.SystemEnv; import com.megaease.easeagent.plugin.utils.common.JsonUtil; import com.megaease.easeagent.plugin.utils.common.StringUtils; import java.io.File; -import java.util.*; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; public class ConfigFactory { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigFactory.class); private static final String CONFIG_PROP_FILE = "agent.properties"; private static final String CONFIG_YAML_FILE = "agent.yaml"; - private static final String AGENT_SERVICE_NAME = "easeagent.name"; - private static final String AGENT_SYSTEM_NAME = "easeagent.system"; + public static final String AGENT_CONFIG_PATH_PROP_KEY = "easeagent.config.path"; - private static final String AGENT_SERVER_PORT_KEY = "easeagent.server.port"; - private static final String AGENT_SERVER_ENABLED_KEY = "easeagent.server.enabled"; + public static final String AGENT_SERVICE = "name"; + public static final String AGENT_SYSTEM = "system"; + + public static final String AGENT_SERVER_PORT = "easeagent.server.port"; + public static final String AGENT_SERVER_ENABLED = "easeagent.server.enabled"; public static final String EASEAGENT_ENV_CONFIG = "EASEAGENT_ENV_CONFIG"; - private static final List subEnvKeys = new LinkedList<>(); - private static final List envKeys = new LinkedList<>(); + private static final Map AGENT_CONFIG_KEYS_TO_PROPS = + ImmutableMap.builder() + .put("easeagent.name", AGENT_SERVICE) + .put("easeagent.system", AGENT_SYSTEM) + .put("easeagent.server.port", AGENT_SERVER_PORT) + .put("easeagent.server.enabled", AGENT_SERVER_ENABLED) + .build(); + + // OTEL_SERVICE_NAME=xxx + private static final Map AGENT_ENV_KEY_TO_PROPS = new HashMap<>(); + static { - subEnvKeys.add(AGENT_SERVICE_NAME); - subEnvKeys.add(AGENT_SYSTEM_NAME); - envKeys.add(AGENT_SERVER_ENABLED_KEY); - envKeys.add(AGENT_SERVER_PORT_KEY); + for (Map.Entry entry : AGENT_CONFIG_KEYS_TO_PROPS.entrySet()) { + // dot.case -> UPPER_UNDERSCORE + AGENT_ENV_KEY_TO_PROPS.put( + ConfigPropertiesUtils.toEnvVarName(entry.getKey()), + entry.getValue() + ); + } } + /** + * update config value from environment variables and java properties + *

+ * java properties > environment variables > env:EASEAGENT_ENV_CONFIG={} > default + */ static Map updateEnvCfg() { Map envCfg = new TreeMap<>(); - for (String key : subEnvKeys) { - String value = System.getProperty(key); - if (!StringUtils.isEmpty(value)) { - envCfg.put(key.substring("easeagent.".length()), value); - } - } - for (String key : envKeys) { - String value = System.getProperty(key); - if (!StringUtils.isEmpty(value)) { - envCfg.put(key, value); - } - } - String configEnv = SystemEnv.get(EASEAGENT_ENV_CONFIG); if (StringUtils.isNotEmpty(configEnv)) { Map map = JsonUtil.toMap(configEnv); @@ -77,12 +86,41 @@ static Map updateEnvCfg() { envCfg.putAll(strMap); } + // override by environment variables, eg: export EASEAGENT_NAME=xxx + for (Map.Entry entry : AGENT_ENV_KEY_TO_PROPS.entrySet()) { + String value = SystemEnv.get(entry.getKey()); + if (!StringUtils.isEmpty(value)) { + envCfg.put(entry.getValue(), value); + } + } + + // override by java properties; eg: java -Deaseagent.name=xxx + for (Map.Entry entry : AGENT_CONFIG_KEYS_TO_PROPS.entrySet()) { + String value = System.getProperty(entry.getKey()); + if (!StringUtils.isEmpty(value)) { + envCfg.put(entry.getValue(), value); + } + } + return envCfg; } private ConfigFactory() { } + /** + * Get config file path from system properties or environment variables + */ + public static String getConfigPath() { + // get config path from -Deaseagent.config.path=/easeagent/agent.properties || export EASEAGENT_CONFIG_PATH=/easeagent/agent.properties + String path = ConfigPropertiesUtils.getString(AGENT_CONFIG_PATH_PROP_KEY); + + if (StringUtils.isEmpty(path)) { + // eg: -Dotel.javaagent.configuration-file=/easeagent/agent.properties || export OTEL_JAVAAGENT_CONFIGURATION_FILE=/easeagent/agent.properties + path = OtelSdkConfigs.getConfigPath(); + } + return path; + } public static GlobalConfigs loadConfigs(String pathname, ClassLoader loader) { // load property configuration file if exist @@ -99,6 +137,9 @@ public static GlobalConfigs loadConfigs(String pathname, ClassLoader loader) { configs.mergeConfigs(configsFromOuterFile); } + // override by opentelemetry sdk env config + configs.updateConfigsNotNotify(OtelSdkConfigs.updateEnvCfg()); + // check environment cfg override configs.updateConfigsNotNotify(updateEnvCfg()); diff --git a/config/src/main/java/com/megaease/easeagent/config/ConfigPropertiesUtils.java b/config/src/main/java/com/megaease/easeagent/config/ConfigPropertiesUtils.java new file mode 100644 index 00000000..b9b79a11 --- /dev/null +++ b/config/src/main/java/com/megaease/easeagent/config/ConfigPropertiesUtils.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.megaease.easeagent.config; + +import com.megaease.easeagent.plugin.utils.SystemEnv; + +import javax.annotation.Nullable; +import java.util.Locale; + +/** + * Get config from system properties or environment variables. + */ +final class ConfigPropertiesUtils { + + public static boolean getBoolean(String propertyName, boolean defaultValue) { + String strValue = getString(propertyName); + return strValue == null ? defaultValue : Boolean.parseBoolean(strValue); + } + + public static int getInt(String propertyName, int defaultValue) { + String strValue = getString(propertyName); + if (strValue == null) { + return defaultValue; + } + try { + return Integer.parseInt(strValue); + } catch (NumberFormatException ignored) { + return defaultValue; + } + } + + @Nullable + public static String getString(String propertyName) { + String value = System.getProperty(propertyName); + if (value != null) { + return value; + } + return SystemEnv.get(toEnvVarName(propertyName)); + } + + /** + * dot.case -> UPPER_UNDERSCORE + */ + public static String toEnvVarName(String propertyName) { + return propertyName.toUpperCase(Locale.ROOT).replace('-', '_').replace('.', '_'); + } + + private ConfigPropertiesUtils() { + } +} diff --git a/config/src/main/java/com/megaease/easeagent/config/OtelSdkConfigs.java b/config/src/main/java/com/megaease/easeagent/config/OtelSdkConfigs.java new file mode 100644 index 00000000..d5b48416 --- /dev/null +++ b/config/src/main/java/com/megaease/easeagent/config/OtelSdkConfigs.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2022, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.megaease.easeagent.config; + +import com.google.common.base.Splitter; +import com.megaease.easeagent.plugin.utils.ImmutableMap; +import com.megaease.easeagent.plugin.utils.SystemEnv; +import com.megaease.easeagent.plugin.utils.common.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + + +/** + * Compatible with opentelemetry-java. + *

+ * {@see https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#disabling-opentelemetrysdk} + */ +public class OtelSdkConfigs { + private static final String OTEL_RESOURCE_ATTRIBUTES_KEY = "otel.resource.attributes"; + + private static final String CONFIG_PATH_PROP_KEY = "otel.javaagent.configuration-file"; + + private static final Splitter.MapSplitter OTEL_RESOURCE_ATTRIBUTES_SPLITTER + = Splitter.on(",") + .omitEmptyStrings() + .withKeyValueSeparator("="); + + private static final Map SDK_ATTRIBUTES_TO_EASE_AGENT_PROPS = + ImmutableMap.builder() + .put("sdk.disabled", "easeagent.server.enabled") + .put("service.name", "name") //"easeagent.name" + .put("service.namespace", "system") //"easeagent.system" + .build(); + + // -Dotel.service.name=xxx + private static final Map OTEL_SDK_PROPS_TO_EASE_AGENT_PROPS = new HashMap<>(); + + // OTEL_SERVICE_NAME=xxx + private static final Map OTEL_SDK_ENV_VAR_TO_EASE_AGENT_PROPS = new HashMap<>(); + + static { + for (Map.Entry entry : SDK_ATTRIBUTES_TO_EASE_AGENT_PROPS.entrySet()) { + // lower.hyphen -> UPPER_UNDERSCORE + OTEL_SDK_PROPS_TO_EASE_AGENT_PROPS.put( + "otel." + entry.getKey(), + entry.getValue() + ); + } + + for (Map.Entry entry : OTEL_SDK_PROPS_TO_EASE_AGENT_PROPS.entrySet()) { + // dot.case -> UPPER_UNDERSCORE + OTEL_SDK_ENV_VAR_TO_EASE_AGENT_PROPS.put( + ConfigPropertiesUtils.toEnvVarName(entry.getKey()), + entry.getValue() + ); + } + } + + /** + * Get config path from java properties or environment variables + */ + static String getConfigPath() { + return ConfigPropertiesUtils.getString(CONFIG_PATH_PROP_KEY); + } + + + /** + * update config value from environment variables and java properties + *

+ * java properties > environment variables > OTEL_RESOURCE_ATTRIBUTES + */ + static Map updateEnvCfg() { + Map envCfg = new TreeMap<>(); + + String configEnv = ConfigPropertiesUtils.getString(OTEL_RESOURCE_ATTRIBUTES_KEY); + if (StringUtils.isNotEmpty(configEnv)) { + Map map = OTEL_RESOURCE_ATTRIBUTES_SPLITTER.split(configEnv); + if (!map.isEmpty()) { + for (Map.Entry entry : SDK_ATTRIBUTES_TO_EASE_AGENT_PROPS.entrySet()) { + String value = map.get(entry.getKey()); + if (!StringUtils.isEmpty(value)) { + envCfg.put(entry.getValue(), value); + } + } + } + } + + // override by environment variables, eg: export OTEL_SERVICE_NAME=xxx + for (Map.Entry entry : OTEL_SDK_ENV_VAR_TO_EASE_AGENT_PROPS.entrySet()) { + String value = SystemEnv.get(entry.getKey()); + if (!StringUtils.isEmpty(value)) { + envCfg.put(entry.getValue(), value); + } + } + + // override by java properties; eg: java -Dotel.service.name=xxx + for (Map.Entry entry : OTEL_SDK_PROPS_TO_EASE_AGENT_PROPS.entrySet()) { + String value = System.getProperty(entry.getKey()); + if (!StringUtils.isEmpty(value)) { + envCfg.put(entry.getValue(), value); + } + } + + return envCfg; + } +} diff --git a/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java b/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java index cee034ac..14796e3e 100644 --- a/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java +++ b/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java @@ -20,22 +20,76 @@ import com.megaease.easeagent.plugin.utils.SystemEnv; import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import java.io.File; +import java.net.URISyntaxException; + +import static com.megaease.easeagent.config.ConfigFactory.AGENT_SERVICE; +import static com.megaease.easeagent.config.ConfigFactory.AGENT_SYSTEM; import static org.junit.Assert.assertEquals; public class ConfigFactoryTest { + @Test public void test_yaml() { Configs config = ConfigFactory.loadConfigs(null, this.getClass().getClassLoader()); - assertEquals("test-service", config.getString("name")); - assertEquals("demo-system", config.getString("system")); + assertEquals("test-service", config.getString(AGENT_SERVICE)); + assertEquals("demo-system", config.getString(AGENT_SYSTEM)); } @Test public void test_env() { - SystemEnv.set(ConfigFactory.EASEAGENT_ENV_CONFIG, "{\"name\":\"env-service\"}"); - Configs config = ConfigFactory.loadConfigs(null, this.getClass().getClassLoader()); - assertEquals("env-service", config.getString("name")); - assertEquals("demo-system", config.getString("system")); + try (MockedStatic mock = Mockito.mockStatic(SystemEnv.class)) { + mock.when(() -> SystemEnv.get(ConfigFactory.EASEAGENT_ENV_CONFIG)).thenReturn("{\"name\":\"env-service\"}"); + + Configs config = ConfigFactory.loadConfigs(null, this.getClass().getClassLoader()); + assertEquals("env-service", config.getString(AGENT_SERVICE)); + assertEquals("demo-system", config.getString(AGENT_SYSTEM)); + } + } + + + @Test + public void test_loadConfigs() { + try (MockedStatic mockSystemEnv = Mockito.mockStatic(SystemEnv.class)) { + mockSystemEnv.when(() -> SystemEnv.get("EASEAGENT_NAME")).thenReturn("service1"); + mockSystemEnv.when(() -> SystemEnv.get("EASEAGENT_SYSTEM")).thenReturn("system1"); + + Configs config = ConfigFactory.loadConfigs(null, this.getClass().getClassLoader()); + assertEquals("service1", config.getString(AGENT_SERVICE)); + assertEquals("system1", config.getString(AGENT_SYSTEM)); + + System.setProperty("easeagent.name", "service2"); + System.setProperty("easeagent.system", "system2"); + config = ConfigFactory.loadConfigs(null, this.getClass().getClassLoader()); + assertEquals("service2", config.getString(AGENT_SERVICE)); + assertEquals("system2", config.getString(AGENT_SYSTEM)); + } + + } + + @Test + public void test_loadConfigsFromUserSpec() throws URISyntaxException { + String userSpec = new File(this.getClass().getClassLoader().getResource("user-spec.properties").toURI()).getPath(); + + try (MockedStatic mockSystemEnv = Mockito.mockStatic(SystemEnv.class)) { + mockSystemEnv.when(() -> SystemEnv.get("EASEAGENT_CONFIG_PATH")).thenReturn(userSpec); + String path = ConfigFactory.getConfigPath(); + assertEquals(userSpec, path); + } + } + + + @Test + public void test_loadConfigsFromOtelUserSpec() throws URISyntaxException { + String userSpec = new File(this.getClass().getClassLoader().getResource("user-spec.properties").toURI()).getPath(); + + try (MockedStatic mockSystemEnv = Mockito.mockStatic(SystemEnv.class)) { + mockSystemEnv.when(() -> SystemEnv.get("OTEL_JAVAAGENT_CONFIGURATION_FILE")).thenReturn(userSpec); + String path = ConfigFactory.getConfigPath(); + assertEquals(userSpec, path); + } } } diff --git a/config/src/test/java/com/megaease/easeagent/config/ConfigPropertiesUtilsTest.java b/config/src/test/java/com/megaease/easeagent/config/ConfigPropertiesUtilsTest.java new file mode 100644 index 00000000..89bb555c --- /dev/null +++ b/config/src/test/java/com/megaease/easeagent/config/ConfigPropertiesUtilsTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2022, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.megaease.easeagent.config; + +import org.junit.*; +import org.junit.contrib.java.lang.system.EnvironmentVariables; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; + +public class ConfigPropertiesUtilsTest { + + @Rule + public final EnvironmentVariables environmentVariables + = new EnvironmentVariables(); + + @Rule + public final RestoreSystemProperties restoreSystemProperties + = new RestoreSystemProperties(); + + @BeforeClass + public static void beforeClass() { + // EnvironmentVariables and restoreSystemProperties does not work with Java 16 + Assume.assumeTrue( + System.getProperty("java.version").startsWith("1.8") + || System.getProperty("java.version").startsWith("11") + ); + } + + @Test + public void getString_systemProperty() { + environmentVariables.set("TEST_PROPERTY_STRING", "env"); + System.setProperty("test.property.string", "sys"); + Assert.assertEquals("sys", ConfigPropertiesUtils.getString("test.property.string")); + } + + @Test + public void getString_environmentVariable() { + environmentVariables.set("TEST_PROPERTY_STRING", "env"); + Assert.assertEquals("env", ConfigPropertiesUtils.getString("test.property.string")); + } + + @Test + public void getString_none() { + Assert.assertNull(ConfigPropertiesUtils.getString("test.property.string.none")); + } + + @Test + public void getInt_systemProperty() { + environmentVariables.set("TEST_PROPERTY_INT", "12"); + System.setProperty("test.property.int", "42"); + Assert.assertEquals(42, ConfigPropertiesUtils.getInt("test.property.int", -1)); + } + + @Test + public void getInt_environmentVariable() { + environmentVariables.set("TEST_PROPERTY_INT", "12"); + Assert.assertEquals(12, ConfigPropertiesUtils.getInt("test.property.int", -1)); + } + + @Test + public void getInt_none() { + Assert.assertEquals(-1, ConfigPropertiesUtils.getInt("test.property.int", -1)); + } + + @Test + public void getInt_invalidNumber() { + System.setProperty("test.property.int", "not a number"); + Assert.assertEquals(-1, ConfigPropertiesUtils.getInt("test.property.int", -1)); + } + + @Test + public void getBoolean_systemProperty() { + environmentVariables.set("TEST_PROPERTY_BOOLEAN", "false"); + System.setProperty("test.property.boolean", "true"); + Assert.assertTrue(ConfigPropertiesUtils.getBoolean("test.property.boolean", false)); + } + + @Test + public void getBoolean_environmentVariable() { + environmentVariables.set("TEST_PROPERTY_BOOLEAN", "true"); + Assert.assertTrue(ConfigPropertiesUtils.getBoolean("test.property.boolean", false)); + } + + @Test + public void getBoolean_none() { + Assert.assertFalse(ConfigPropertiesUtils.getBoolean("test.property.boolean", false)); + } +} diff --git a/config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java b/config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java new file mode 100644 index 00000000..3a6f8201 --- /dev/null +++ b/config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022, MegaEase + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.megaease.easeagent.config; + +import com.megaease.easeagent.plugin.utils.SystemEnv; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Map; + + +public class OtelSdkConfigsTest { + + @Test + public void updateEnvCfg() { + //value from system env "OTEL_RESOURCE_ATTRIBUTES + String attributes = "service.name=service1,service.namespace=namespace1"; + SystemEnv.set("OTEL_RESOURCE_ATTRIBUTES", attributes); + Map envCfg = OtelSdkConfigs.updateEnvCfg(); + Assert.assertEquals("service1", envCfg.get("name")); + Assert.assertEquals("namespace1", envCfg.get("system")); + + // override by system env + SystemEnv.set("OTEL_SERVICE_NAME", "service2"); + SystemEnv.set("OTEL_SERVICE_NAMESPACE", "namespace2"); + envCfg = OtelSdkConfigs.updateEnvCfg(); + Assert.assertEquals("service2", envCfg.get("name")); + Assert.assertEquals("namespace2", envCfg.get("system")); + + // override by system property + System.setProperty("otel.service.name", "service3"); + System.setProperty("otel.service.namespace", "namespace3"); + envCfg = OtelSdkConfigs.updateEnvCfg(); + Assert.assertEquals("service3", envCfg.get("name")); + Assert.assertEquals("namespace3", envCfg.get("system")); + + } +} diff --git a/config/src/test/resources/user-spec.properties b/config/src/test/resources/user-spec.properties new file mode 100644 index 00000000..f39e6ff8 --- /dev/null +++ b/config/src/test/resources/user-spec.properties @@ -0,0 +1,2 @@ +name=user-spec +system=system-spec diff --git a/config/src/test/resources/user-spec2.properties b/config/src/test/resources/user-spec2.properties new file mode 100644 index 00000000..07de5a04 --- /dev/null +++ b/config/src/test/resources/user-spec2.properties @@ -0,0 +1,2 @@ +name=user-spec2 +system=system-spec2 diff --git a/core/src/main/java/com/megaease/easeagent/core/Bootstrap.java b/core/src/main/java/com/megaease/easeagent/core/Bootstrap.java index bce58089..74dcbb9b 100644 --- a/core/src/main/java/com/megaease/easeagent/core/Bootstrap.java +++ b/core/src/main/java/com/megaease/easeagent/core/Bootstrap.java @@ -37,6 +37,7 @@ import com.megaease.easeagent.plugin.bridge.AgentInfo; import com.megaease.easeagent.plugin.bridge.EaseAgent; import com.megaease.easeagent.plugin.report.AgentReport; +import com.megaease.easeagent.plugin.utils.common.StringUtils; import com.megaease.easeagent.report.AgentReportAware; import com.megaease.easeagent.report.DefaultAgentReport; import lombok.SneakyThrows; @@ -47,7 +48,6 @@ import net.bytebuddy.dynamic.loading.ClassInjector; import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.utility.JavaModule; -import org.apache.commons.lang3.StringUtils; import javax.management.MBeanServer; import javax.management.ObjectName; @@ -64,9 +64,8 @@ public class Bootstrap { private static final Logger LOGGER = LoggerFactory.getLogger(Bootstrap.class); - private static final String AGENT_SERVER_PORT_KEY = "easeagent.server.port"; - private static final String AGENT_CONFIG_PATH = "easeagent.config.path"; - private static final String AGENT_SERVER_ENABLED_KEY = "easeagent.server.enabled"; + private static final String AGENT_SERVER_PORT_KEY = ConfigFactory.AGENT_SERVER_PORT; + private static final String AGENT_SERVER_ENABLED_KEY = ConfigFactory.AGENT_SERVER_ENABLED; private static final String AGENT_MIDDLEWARE_UPDATE = "easeagent.middleware.update"; @@ -91,7 +90,7 @@ public static void start(String args, Instrumentation inst, String javaAgentJarP } // initiate configuration - String configPath = System.getProperty(AGENT_CONFIG_PATH); + String configPath = ConfigFactory.getConfigPath(); if (StringUtils.isEmpty(configPath)) { configPath = args; } diff --git a/doc/user-manual.md b/doc/user-manual.md index 6248afdb..cb8c5b05 100644 --- a/doc/user-manual.md +++ b/doc/user-manual.md @@ -64,6 +64,13 @@ Global configuration include dedicated parameters for controlling metrics and tr Plugin level configuration provides more granular control and customizable configuration. +## Configuring priority +The agent can consume configuration from one or more of the following sources (ordered from highest to lowest priority): + +- system properties +- environment variables +- the configuration file + ### Getting the configuration file You may extract default configuration from the JAR file or create new properties from a blank file. ``` @@ -73,17 +80,32 @@ Run the user application with EaseAgent ``` $ export EASE_AGENT_PATH=[Replace with agent path] $ java "-javaagent:${EASE_AGENT_PATH}/easeagent.jar" -Deaseagent.config.path=${EASE_AGENT_PATH}/agent.properties -jar user-app.jar + +or + +$ export EASE_AGENT_PATH=[Replace with agent path] +$ export EASEAGENT_CONFIG_PATH=${EASE_AGENT_PATH}/agent.properties +$ java "-javaagent:${EASE_AGENT_PATH}/easeagent.jar" -jar user-app.jar ``` ### Global Configuration + +#### Agent Configuration + +| System property | Environment variable | Configuration File Key | Description | +|-------------------|------------------------|------------------------|-------------------------------| +| `easeagent.name` | `EASEAGENT_NAME` | `name` | Specify logical service name. | +| `easeagent.system` | `EASEAGENT_SYSTEM` | `system` | Specify logical service system. | + #### Internal HTTP Server EaseAgent opens port `9900` by default to receive configuration change notifications and Prometheus requests. -| Key | Default Value | Description | -| -------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `easeagent.server.enabled` | true | Enable Internal HTTP Server. `false` can disable it. EaseAgent will no longer accept any HTTP requests (`Prometheus`、`Health Check`、`Readiness Check`、`Agent Info`) when the Internal HTTP Server is disabled. User can add VM parameter:`-Deaseagent.server.enabled=[true or false]` to override. | -| `easeagent.server.port` | 9900 | Internal HTTP Server port. User can add VM parameter:`-Deaseagent.server.port=[new port]` to override. | +| System property | Environment variable | DefaultValue | Description | +|----------------------------|---------------------------|------| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `easeagent.server.enabled` | `EASEAGENT_SERVER_ENABLED` | true | Enable Internal HTTP Server. `false` can disable it. EaseAgent will no longer accept any HTTP requests (`Prometheus`、`Health Check`、`Readiness Check`、`Agent Info`) when the Internal HTTP Server is disabled. User can add VM parameter:`-Deaseagent.server.enabled=[true or false]` to override. | +| `easeagent.server.port` | `EASEAGENT_SERVER_PORT` | 9900 | Internal HTTP Server port. User can add VM parameter:`-Deaseagent.server.port=[new port]` to override. | + #### Output Data Server: Kafka and HTTP/Zipkin Server Tracing and metric data can be output to kafka server. @@ -372,6 +394,12 @@ After modification, User can run the application with EaseAgent. $ export EASE_AGENT_PATH=[Replace with agent path] $ java "-javaagent:${EASE_AGENT_PATH}/easeagent.jar -Deaseagent.log.conf=${EASE_AGENT_PATH}/easeagent-log4j2.xml" -jar user-app.jar ``` +or +``` +$ export EASE_AGENT_PATH=[Replace with agent path] +$ export EASEAGENT_LOG_CONF=/your/log4j2/config/filepath +$ java "-javaagent:${EASE_AGENT_PATH}/easeagent.jar -jar user-app.jar +``` ### MDC Easeagent automatically adds TraceId and SpanId to the MDC (Mapped Diagnostic Context) when creating a new Span. You can configure your slf4j or logback files by adding parameters to display these IDs, or retrieve them directly from the MDC in your code. diff --git a/loader/src/main/java/com/megaease/easeagent/Main.java b/loader/src/main/java/com/megaease/easeagent/Main.java index 319e7f90..915bfd4e 100644 --- a/loader/src/main/java/com/megaease/easeagent/Main.java +++ b/loader/src/main/java/com/megaease/easeagent/Main.java @@ -17,6 +17,7 @@ package com.megaease.easeagent; +import com.google.common.base.Strings; import com.google.common.collect.Lists; import lombok.SneakyThrows; import org.springframework.boot.loader.LaunchedURLClassLoader; @@ -48,6 +49,8 @@ public class Main { private static final String PLUGINS = "plugins/"; private static final String LOGGING_PROPERTY = "Logging-Property"; private static final String EASEAGENT_LOG_CONF = "easeagent.log.conf"; + private static final String EASEAGENT_LOG_CONF_ENV_KEY = "EASEAGENT_LOG_CONF"; + private static final String DEFAULT_AGENT_LOG_CONF = "easeagent-log4j2.xml"; private static ClassLoader loader; public static void premain(final String args, final Instrumentation inst) throws Exception { @@ -124,8 +127,9 @@ private static void switchLoggingProperty(ClassLoader loader, String hostKey, Ca t.setContextClassLoader(loader); + // get config from system properties final String host = System.getProperty(hostKey); - final String agent = System.getProperty(Main.EASEAGENT_LOG_CONF, "easeagent-log4j2.xml"); + final String agent = getLogConfigPath(); // Redirect config of host to agent System.setProperty(hostKey, agent); @@ -143,6 +147,20 @@ private static void switchLoggingProperty(ClassLoader loader, String hostKey, Ca } } + private static String getLogConfigPath() { + String logConfigPath = System.getProperty(EASEAGENT_LOG_CONF); + if (Strings.isNullOrEmpty(logConfigPath)) { + logConfigPath = System.getenv(EASEAGENT_LOG_CONF_ENV_KEY); + + } + // if not set, use default + if (Strings.isNullOrEmpty(logConfigPath)) { + logConfigPath = DEFAULT_AGENT_LOG_CONF; + + } + return logConfigPath; + } + private static ArrayList nestArchiveUrls(JarFileArchive archive, String prefix) throws IOException { ArrayList archives = Lists.newArrayList( archive.getNestedArchives(entry -> !entry.isDirectory() && entry.getName().startsWith(prefix), diff --git a/plugin-api/src/main/java/io/opentelemetry/sdk/resources/EaseAgentResource.java b/plugin-api/src/main/java/io/opentelemetry/sdk/resources/EaseAgentResource.java index e55bffde..19740ee1 100644 --- a/plugin-api/src/main/java/io/opentelemetry/sdk/resources/EaseAgentResource.java +++ b/plugin-api/src/main/java/io/opentelemetry/sdk/resources/EaseAgentResource.java @@ -6,12 +6,13 @@ import com.megaease.easeagent.plugin.api.otlp.common.SemanticKey; import com.megaease.easeagent.plugin.bridge.EaseAgent; import io.opentelemetry.api.common.Attributes; -import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME; -import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAMESPACE; import javax.annotation.Nullable; import java.util.List; +import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME; +import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAMESPACE; + public class EaseAgentResource extends Resource implements ConfigChangeListener { static volatile EaseAgentResource agentResource = null;