From 010bf099bfae1d118c4b5bdb10aa1e4b82f1bb53 Mon Sep 17 00:00:00 2001 From: enoch Date: Mon, 11 Sep 2023 18:42:32 +0800 Subject: [PATCH 01/10] feat: Compatible with opentelemetry-java env configuration. --- .../easeagent/config/ConfigFactory.java | 97 ++++++++++++----- .../easeagent/config/ConfigFactoryTest.java | 54 +++++++++- .../src/test/resources/user-spec.properties | 2 + .../src/test/resources/user-spec2.properties | 2 + .../megaease/easeagent/core/Bootstrap.java | 16 +-- plugin-api/pom.xml | 4 + .../sdk/resources/EaseAgentResource.java | 5 +- .../sdk/resources/OtelSdkConfigs.java | 102 ++++++++++++++++++ .../sdk/resources/OtelSdkConfigsTest.java | 45 ++++++++ 9 files changed, 284 insertions(+), 43 deletions(-) create mode 100644 config/src/test/resources/user-spec.properties create mode 100644 config/src/test/resources/user-spec2.properties create mode 100644 plugin-api/src/main/java/io/opentelemetry/sdk/resources/OtelSdkConfigs.java create mode 100644 plugin-api/src/test/java/io/opentelemetry/sdk/resources/OtelSdkConfigsTest.java 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 05fab1f78..b6a013894 100644 --- a/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java +++ b/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java @@ -17,54 +17,67 @@ package com.megaease.easeagent.config; +import com.google.common.base.CaseFormat; +import com.google.common.base.Strings; 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 io.opentelemetry.sdk.resources.OtelSdkConfigs; 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 = "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.config.path", AGENT_CONFIG_PATH) + .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()) { + // lower.hyphen -> UPPER_UNDERSCORE + AGENT_ENV_KEY_TO_PROPS.put( + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, entry.getKey().replace('.', '-')), + 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 +90,45 @@ 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() { } + /** + * load config from environment variables and java properties and default config file. + *

+ * user special config: + * -Deaseagent.config.path=/easeagent/agent.properties || export EASEAGENT_CONFIG_PATH=/easeagent/agent.properties + * or OTEL config format + * -Dotel.javaagent.configuration-file=/easeagent/agent.properties || export OTEL_JAVAAGENT_CONFIGURATION_FILE=/easeagent/agent.properties + */ + public static GlobalConfigs loadConfigs(ClassLoader loader) { + Map envCfg = updateEnvCfg(); + String configFile = envCfg.get(AGENT_CONFIG_PATH); + if (Strings.isNullOrEmpty(configFile)) { + envCfg = OtelSdkConfigs.updateEnvCfg(); + configFile = envCfg.get(AGENT_CONFIG_PATH); + } + return loadConfigs(configFile, loader); + } public static GlobalConfigs loadConfigs(String pathname, ClassLoader loader) { // load property configuration file if exist @@ -99,6 +145,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/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java b/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java index cee034acf..be292f19a 100644 --- a/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java +++ b/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java @@ -21,21 +21,67 @@ import com.megaease.easeagent.plugin.utils.SystemEnv; import org.junit.Test; +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")); + assertEquals("env-service", config.getString(AGENT_SERVICE)); + assertEquals("demo-system", config.getString(AGENT_SYSTEM)); + } + + @Test + public void test_loadConfigs() { + SystemEnv.set("EASEAGENT_NAME", "service1"); + SystemEnv.set("EASEAGENT_SYSTEM", "system1"); + Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); + assertEquals("service1", config.getString(AGENT_SERVICE)); + assertEquals("system1", config.getString(AGENT_SYSTEM)); + + // override by jvm properties + System.setProperty("easeagent.name", "service2"); + System.setProperty("easeagent.system", "system2"); + config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); + assertEquals("service2", config.getString(AGENT_SERVICE)); + assertEquals("system2", config.getString(AGENT_SYSTEM)); + } + + @Test + public void test_loadConfigsFromUserSpec() { + SystemEnv.set("EASEAGENT_CONFIG_PATH", "src/test/resources/user-spec.properties"); + Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); + assertEquals("user-spec", config.getString(AGENT_SERVICE)); + assertEquals("system-spec", config.getString(AGENT_SYSTEM)); + + // override by jvm properties + System.setProperty("easeagent.config.path", "src/test/resources/user-spec2.properties"); + config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); + assertEquals("user-spec2", config.getString(AGENT_SERVICE)); + assertEquals("system-spec2", config.getString(AGENT_SYSTEM)); + } + + @Test + public void test_loadConfigsFromOtelUserSpec() { + SystemEnv.set("OTEL_JAVAAGENT_CONFIGURATION_FILE", "src/test/resources/user-spec.properties"); + Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); + assertEquals("user-spec", config.getString(AGENT_SERVICE)); + assertEquals("system-spec", config.getString(AGENT_SYSTEM)); + + // override by jvm properties + System.setProperty("otel.javaagent.configuration-file", "src/test/resources/user-spec2.properties"); + config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); + assertEquals("user-spec2", config.getString(AGENT_SERVICE)); + assertEquals("system-spec2", config.getString(AGENT_SYSTEM)); } } diff --git a/config/src/test/resources/user-spec.properties b/config/src/test/resources/user-spec.properties new file mode 100644 index 000000000..f39e6ff84 --- /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 000000000..07de5a043 --- /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 bce58089c..21b34fd92 100644 --- a/core/src/main/java/com/megaease/easeagent/core/Bootstrap.java +++ b/core/src/main/java/com/megaease/easeagent/core/Bootstrap.java @@ -47,7 +47,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 +63,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"; @@ -90,16 +88,10 @@ public static void start(String args, Instrumentation inst, String javaAgentJarP LOGGER.debug("Injected class: {}", bootstrapClassSet); } - // initiate configuration - String configPath = System.getProperty(AGENT_CONFIG_PATH); - if (StringUtils.isEmpty(configPath)) { - configPath = args; - } - ClassLoader classLoader = Bootstrap.class.getClassLoader(); final AgentInfo agentInfo = AgentInfoFactory.loadAgentInfo(classLoader); EaseAgent.agentInfo = agentInfo; - final GlobalConfigs conf = ConfigFactory.loadConfigs(configPath, classLoader); + final GlobalConfigs conf = ConfigFactory.loadConfigs(classLoader); wrapConfig(conf); // loader check @@ -141,8 +133,6 @@ private static void initHttpServer(Configs conf) { if (port == null) { port = DEF_AGENT_SERVER_PORT; } - String portStr = System.getProperty(AGENT_SERVER_PORT_KEY, String.valueOf(port)); - port = Integer.parseInt(portStr); AgentHttpServer agentHttpServer = new AgentHttpServer(port); diff --git a/plugin-api/pom.xml b/plugin-api/pom.xml index bef7d611f..daafa50e4 100644 --- a/plugin-api/pom.xml +++ b/plugin-api/pom.xml @@ -29,6 +29,10 @@ plugin-api + + com.google.guava + guava + com.squareup javapoet 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 e55bffde5..19740ee1a 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; diff --git a/plugin-api/src/main/java/io/opentelemetry/sdk/resources/OtelSdkConfigs.java b/plugin-api/src/main/java/io/opentelemetry/sdk/resources/OtelSdkConfigs.java new file mode 100644 index 000000000..075b74845 --- /dev/null +++ b/plugin-api/src/main/java/io/opentelemetry/sdk/resources/OtelSdkConfigs.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023, Inspireso and/or its affiliates. All rights reserved. + */ + +package io.opentelemetry.sdk.resources; + +import com.google.common.base.CaseFormat; +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 { + static final String OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES"; + + 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("javaagent.configuration-file", "config.path") + .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()) { + // lower.hyphen -> UPPER_UNDERSCORE + OTEL_SDK_ENV_VAR_TO_EASE_AGENT_PROPS.put( + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, entry.getKey().replace('.', '-')), + entry.getValue() + ); + } + } + + /** + * update config value from environment variables and java properties + *

+ * java properties > environment variables > OTEL_RESOURCE_ATTRIBUTES + */ + public static Map updateEnvCfg() { + Map envCfg = new TreeMap<>(); + + String configEnv = SystemEnv.get(OTEL_RESOURCE_ATTRIBUTES); + 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/plugin-api/src/test/java/io/opentelemetry/sdk/resources/OtelSdkConfigsTest.java b/plugin-api/src/test/java/io/opentelemetry/sdk/resources/OtelSdkConfigsTest.java new file mode 100644 index 000000000..ed9d3c5fa --- /dev/null +++ b/plugin-api/src/test/java/io/opentelemetry/sdk/resources/OtelSdkConfigsTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, Inspireso and/or its affiliates. All rights reserved. + */ + +package io.opentelemetry.sdk.resources; + +import com.megaease.easeagent.plugin.api.config.AutoRefreshConfigSupplier; +import com.megaease.easeagent.plugin.tools.config.AutoRefreshConfigSupplierTest; +import com.megaease.easeagent.plugin.utils.SystemEnv; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Type; +import java.util.Map; + +import static io.opentelemetry.sdk.resources.OtelSdkConfigs.OTEL_RESOURCE_ATTRIBUTES; +import static org.junit.Assert.*; + +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")); + + } +} From dd876f386914dc935c299647f5f20ef92b701b04 Mon Sep 17 00:00:00 2001 From: enoch Date: Tue, 12 Sep 2023 16:22:52 +0800 Subject: [PATCH 02/10] fix: test SystemEnv use mock --- .../easeagent/config/ConfigFactoryTest.java | 86 +++++++++++-------- 1 file changed, 48 insertions(+), 38 deletions(-) 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 be292f19a..a4ef20c50 100644 --- a/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java +++ b/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java @@ -20,12 +20,18 @@ 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()); @@ -35,53 +41,57 @@ public void test_yaml() { @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(AGENT_SERVICE)); - assertEquals("demo-system", config.getString(AGENT_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() { - SystemEnv.set("EASEAGENT_NAME", "service1"); - SystemEnv.set("EASEAGENT_SYSTEM", "system1"); - Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); - assertEquals("service1", config.getString(AGENT_SERVICE)); - assertEquals("system1", config.getString(AGENT_SYSTEM)); - - // override by jvm properties - System.setProperty("easeagent.name", "service2"); - System.setProperty("easeagent.system", "system2"); - config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); - assertEquals("service2", config.getString(AGENT_SERVICE)); - assertEquals("system2", config.getString(AGENT_SYSTEM)); + 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(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(this.getClass().getClassLoader()); + assertEquals("service2", config.getString(AGENT_SERVICE)); + assertEquals("system2", config.getString(AGENT_SYSTEM)); + } + } @Test - public void test_loadConfigsFromUserSpec() { - SystemEnv.set("EASEAGENT_CONFIG_PATH", "src/test/resources/user-spec.properties"); - Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); - assertEquals("user-spec", config.getString(AGENT_SERVICE)); - assertEquals("system-spec", config.getString(AGENT_SYSTEM)); - - // override by jvm properties - System.setProperty("easeagent.config.path", "src/test/resources/user-spec2.properties"); - config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); - assertEquals("user-spec2", config.getString(AGENT_SERVICE)); - assertEquals("system-spec2", config.getString(AGENT_SYSTEM)); + 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); + Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); + assertEquals("user-spec", config.getString(AGENT_SERVICE)); + assertEquals("system-spec", config.getString(AGENT_SYSTEM)); + } } + @Test - public void test_loadConfigsFromOtelUserSpec() { - SystemEnv.set("OTEL_JAVAAGENT_CONFIGURATION_FILE", "src/test/resources/user-spec.properties"); - Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); - assertEquals("user-spec", config.getString(AGENT_SERVICE)); - assertEquals("system-spec", config.getString(AGENT_SYSTEM)); - - // override by jvm properties - System.setProperty("otel.javaagent.configuration-file", "src/test/resources/user-spec2.properties"); - config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); - assertEquals("user-spec2", config.getString(AGENT_SERVICE)); - assertEquals("system-spec2", config.getString(AGENT_SYSTEM)); + 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); + Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); + assertEquals("user-spec", config.getString(AGENT_SERVICE)); + assertEquals("system-spec", config.getString(AGENT_SYSTEM)); + + } } } From 6d5f7a1b55f85590beedc55803c52bb75c6971e6 Mon Sep 17 00:00:00 2001 From: enoch Date: Wed, 13 Sep 2023 11:28:35 +0800 Subject: [PATCH 03/10] Update config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java Co-authored-by: observeralone <954068039@qq.com> --- .../main/java/com/megaease/easeagent/config/ConfigFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b6a013894..a0bfa020d 100644 --- a/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java +++ b/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java @@ -123,7 +123,7 @@ private ConfigFactory() { public static GlobalConfigs loadConfigs(ClassLoader loader) { Map envCfg = updateEnvCfg(); String configFile = envCfg.get(AGENT_CONFIG_PATH); - if (Strings.isNullOrEmpty(configFile)) { + if (StringUtils.isEmpty(configFile)) { envCfg = OtelSdkConfigs.updateEnvCfg(); configFile = envCfg.get(AGENT_CONFIG_PATH); } From 2e94aadefe05cdd0f4017b06c963324364179817 Mon Sep 17 00:00:00 2001 From: enoch Date: Wed, 13 Sep 2023 15:04:07 +0800 Subject: [PATCH 04/10] refactor: Optimizing code for reading agent configuration path. add method ConfigFactory#getConfigPath for Bootstrap --- config/pom.xml | 5 ++- .../easeagent/config/ConfigFactory.java | 28 ++++++++------ .../easeagent/config}/OtelSdkConfigs.java | 38 ++++++++++++++++--- .../easeagent/config/ConfigFactoryTest.java | 16 ++++---- .../easeagent/config}/OtelSdkConfigsTest.java | 26 ++++++++----- .../megaease/easeagent/core/Bootstrap.java | 11 +++++- plugin-api/pom.xml | 4 -- 7 files changed, 87 insertions(+), 41 deletions(-) rename {plugin-api/src/main/java/io/opentelemetry/sdk/resources => config/src/main/java/com/megaease/easeagent/config}/OtelSdkConfigs.java (73%) rename {plugin-api/src/test/java/io/opentelemetry/sdk/resources => config/src/test/java/com/megaease/easeagent/config}/OtelSdkConfigsTest.java (59%) diff --git a/config/pom.xml b/config/pom.xml index 57d9b4152..3b9945e9d 100644 --- a/config/pom.xml +++ b/config/pom.xml @@ -53,10 +53,13 @@ ${project.version} test - org.yaml snakeyaml + + com.google.guava + guava + 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 a0bfa020d..b55f2a8c7 100644 --- a/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java +++ b/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java @@ -18,14 +18,12 @@ package com.megaease.easeagent.config; import com.google.common.base.CaseFormat; -import com.google.common.base.Strings; 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 io.opentelemetry.sdk.resources.OtelSdkConfigs; import java.io.File; import java.util.HashMap; @@ -37,7 +35,8 @@ public class ConfigFactory { private static final String CONFIG_PROP_FILE = "agent.properties"; private static final String CONFIG_YAML_FILE = "agent.yaml"; - public static final String AGENT_CONFIG_PATH = "config.path"; + public static final String AGENT_CONFIG_PATH_PROP_KEY = "easeagent.config.path"; + public static final String AGENT_CONFIG_PATH_ENV_KEY = "EASEAGENT_CONFIG_PATH"; public static final String AGENT_SERVICE = "name"; public static final String AGENT_SYSTEM = "system"; @@ -49,7 +48,6 @@ public class ConfigFactory { private static final Map AGENT_CONFIG_KEYS_TO_PROPS = ImmutableMap.builder() - .put("easeagent.config.path", AGENT_CONFIG_PATH) .put("easeagent.name", AGENT_SERVICE) .put("easeagent.system", AGENT_SYSTEM) .put("easeagent.server.port", AGENT_SERVER_PORT) @@ -113,21 +111,27 @@ private ConfigFactory() { } /** - * load config from environment variables and java properties and default config file. + * Get config file path from system properties or environment variables *

* user special config: * -Deaseagent.config.path=/easeagent/agent.properties || export EASEAGENT_CONFIG_PATH=/easeagent/agent.properties * or OTEL config format * -Dotel.javaagent.configuration-file=/easeagent/agent.properties || export OTEL_JAVAAGENT_CONFIGURATION_FILE=/easeagent/agent.properties */ - public static GlobalConfigs loadConfigs(ClassLoader loader) { - Map envCfg = updateEnvCfg(); - String configFile = envCfg.get(AGENT_CONFIG_PATH); - if (StringUtils.isEmpty(configFile)) { - envCfg = OtelSdkConfigs.updateEnvCfg(); - configFile = envCfg.get(AGENT_CONFIG_PATH); + public static String getConfigPath() { + // get config path from -Deaseagent.config.path=xxx + String path = System.getProperty(AGENT_CONFIG_PATH_PROP_KEY); + if (StringUtils.isEmpty(path)) { + // get config path from export EASEAGENT_CONFIG_PATH=xxx + path = SystemEnv.get(AGENT_CONFIG_PATH_ENV_KEY); } - return loadConfigs(configFile, loader); + + if (StringUtils.isEmpty(path)) { + // get config path from OTEL configuration + // 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) { diff --git a/plugin-api/src/main/java/io/opentelemetry/sdk/resources/OtelSdkConfigs.java b/config/src/main/java/com/megaease/easeagent/config/OtelSdkConfigs.java similarity index 73% rename from plugin-api/src/main/java/io/opentelemetry/sdk/resources/OtelSdkConfigs.java rename to config/src/main/java/com/megaease/easeagent/config/OtelSdkConfigs.java index 075b74845..5d5e36ec7 100644 --- a/plugin-api/src/main/java/io/opentelemetry/sdk/resources/OtelSdkConfigs.java +++ b/config/src/main/java/com/megaease/easeagent/config/OtelSdkConfigs.java @@ -1,8 +1,21 @@ /* - * Copyright (c) 2023, Inspireso and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 io.opentelemetry.sdk.resources; +package com.megaease.easeagent.config; import com.google.common.base.CaseFormat; import com.google.common.base.Splitter; @@ -21,7 +34,10 @@ * {@see https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#disabling-opentelemetrysdk} */ public class OtelSdkConfigs { - static final String OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES"; + private static final String OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES"; + + private static final String CONFIG_PATH_PROP_KEY = "otel.javaagent.configuration-file"; + private static final String CONFIG_PATH_ENV_KEY = "OTEL_JAVAAGENT_CONFIGURATION_FILE"; private static final Splitter.MapSplitter OTEL_RESOURCE_ATTRIBUTES_SPLITTER = Splitter.on(",") @@ -30,7 +46,6 @@ public class OtelSdkConfigs { private static final Map SDK_ATTRIBUTES_TO_EASE_AGENT_PROPS = ImmutableMap.builder() - .put("javaagent.configuration-file", "config.path") .put("sdk.disabled", "easeagent.server.enabled") .put("service.name", "name") //"easeagent.name" .put("service.namespace", "system") //"easeagent.system" @@ -60,12 +75,25 @@ public class OtelSdkConfigs { } } + /** + * Get config path from java properties or environment variables + */ + static String getConfigPath() { + String path = System.getProperty(CONFIG_PATH_PROP_KEY); + if (StringUtils.isEmpty(path)) { + path = SystemEnv.get(CONFIG_PATH_ENV_KEY); + } + + return path; + } + + /** * update config value from environment variables and java properties *

* java properties > environment variables > OTEL_RESOURCE_ATTRIBUTES */ - public static Map updateEnvCfg() { + static Map updateEnvCfg() { Map envCfg = new TreeMap<>(); String configEnv = SystemEnv.get(OTEL_RESOURCE_ATTRIBUTES); 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 a4ef20c50..14796e3ef 100644 --- a/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java +++ b/config/src/test/java/com/megaease/easeagent/config/ConfigFactoryTest.java @@ -57,13 +57,13 @@ public void test_loadConfigs() { mockSystemEnv.when(() -> SystemEnv.get("EASEAGENT_NAME")).thenReturn("service1"); mockSystemEnv.when(() -> SystemEnv.get("EASEAGENT_SYSTEM")).thenReturn("system1"); - Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); + 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(this.getClass().getClassLoader()); + config = ConfigFactory.loadConfigs(null, this.getClass().getClassLoader()); assertEquals("service2", config.getString(AGENT_SERVICE)); assertEquals("system2", config.getString(AGENT_SYSTEM)); } @@ -76,9 +76,8 @@ public void test_loadConfigsFromUserSpec() throws URISyntaxException { try (MockedStatic mockSystemEnv = Mockito.mockStatic(SystemEnv.class)) { mockSystemEnv.when(() -> SystemEnv.get("EASEAGENT_CONFIG_PATH")).thenReturn(userSpec); - Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); - assertEquals("user-spec", config.getString(AGENT_SERVICE)); - assertEquals("system-spec", config.getString(AGENT_SYSTEM)); + String path = ConfigFactory.getConfigPath(); + assertEquals(userSpec, path); } } @@ -86,12 +85,11 @@ public void test_loadConfigsFromUserSpec() throws URISyntaxException { @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); - Configs config = ConfigFactory.loadConfigs(this.getClass().getClassLoader()); - assertEquals("user-spec", config.getString(AGENT_SERVICE)); - assertEquals("system-spec", config.getString(AGENT_SYSTEM)); - + String path = ConfigFactory.getConfigPath(); + assertEquals(userSpec, path); } } } diff --git a/plugin-api/src/test/java/io/opentelemetry/sdk/resources/OtelSdkConfigsTest.java b/config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java similarity index 59% rename from plugin-api/src/test/java/io/opentelemetry/sdk/resources/OtelSdkConfigsTest.java rename to config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java index ed9d3c5fa..4b0eb78da 100644 --- a/plugin-api/src/test/java/io/opentelemetry/sdk/resources/OtelSdkConfigsTest.java +++ b/config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java @@ -1,28 +1,36 @@ /* - * Copyright (c) 2023, Inspireso and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 io.opentelemetry.sdk.resources; +package com.megaease.easeagent.config; -import com.megaease.easeagent.plugin.api.config.AutoRefreshConfigSupplier; -import com.megaease.easeagent.plugin.tools.config.AutoRefreshConfigSupplierTest; import com.megaease.easeagent.plugin.utils.SystemEnv; import org.junit.Assert; import org.junit.Test; -import java.lang.reflect.Type; import java.util.Map; -import static io.opentelemetry.sdk.resources.OtelSdkConfigs.OTEL_RESOURCE_ATTRIBUTES; -import static org.junit.Assert.*; 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); + 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")); 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 21b34fd92..74dcbb9b1 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; @@ -88,10 +89,16 @@ public static void start(String args, Instrumentation inst, String javaAgentJarP LOGGER.debug("Injected class: {}", bootstrapClassSet); } + // initiate configuration + String configPath = ConfigFactory.getConfigPath(); + if (StringUtils.isEmpty(configPath)) { + configPath = args; + } + ClassLoader classLoader = Bootstrap.class.getClassLoader(); final AgentInfo agentInfo = AgentInfoFactory.loadAgentInfo(classLoader); EaseAgent.agentInfo = agentInfo; - final GlobalConfigs conf = ConfigFactory.loadConfigs(classLoader); + final GlobalConfigs conf = ConfigFactory.loadConfigs(configPath, classLoader); wrapConfig(conf); // loader check @@ -133,6 +140,8 @@ private static void initHttpServer(Configs conf) { if (port == null) { port = DEF_AGENT_SERVER_PORT; } + String portStr = System.getProperty(AGENT_SERVER_PORT_KEY, String.valueOf(port)); + port = Integer.parseInt(portStr); AgentHttpServer agentHttpServer = new AgentHttpServer(port); diff --git a/plugin-api/pom.xml b/plugin-api/pom.xml index daafa50e4..bef7d611f 100644 --- a/plugin-api/pom.xml +++ b/plugin-api/pom.xml @@ -29,10 +29,6 @@ plugin-api - - com.google.guava - guava - com.squareup javapoet From abd4bd79bf43677613baeda0b897904861a12f58 Mon Sep 17 00:00:00 2001 From: enoch Date: Wed, 13 Sep 2023 17:15:10 +0800 Subject: [PATCH 05/10] refactor: Optimizing code for get config from system properties or environment variables. --- .../easeagent/config/ConfigFactory.java | 20 ++---- .../config/ConfigPropertiesUtils.java | 65 +++++++++++++++++++ .../easeagent/config/OtelSdkConfigs.java | 21 ++---- .../easeagent/config/OtelSdkConfigsTest.java | 4 +- 4 files changed, 78 insertions(+), 32 deletions(-) create mode 100644 config/src/main/java/com/megaease/easeagent/config/ConfigPropertiesUtils.java 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 b55f2a8c7..171c90610 100644 --- a/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java +++ b/config/src/main/java/com/megaease/easeagent/config/ConfigFactory.java @@ -17,7 +17,6 @@ package com.megaease.easeagent.config; -import com.google.common.base.CaseFormat; import com.megaease.easeagent.log4j2.Logger; import com.megaease.easeagent.log4j2.LoggerFactory; import com.megaease.easeagent.plugin.utils.ImmutableMap; @@ -36,7 +35,6 @@ public class ConfigFactory { private static final String CONFIG_YAML_FILE = "agent.yaml"; public static final String AGENT_CONFIG_PATH_PROP_KEY = "easeagent.config.path"; - public static final String AGENT_CONFIG_PATH_ENV_KEY = "EASEAGENT_CONFIG_PATH"; public static final String AGENT_SERVICE = "name"; public static final String AGENT_SYSTEM = "system"; @@ -60,9 +58,9 @@ public class ConfigFactory { static { for (Map.Entry entry : AGENT_CONFIG_KEYS_TO_PROPS.entrySet()) { - // lower.hyphen -> UPPER_UNDERSCORE + // dot.case -> UPPER_UNDERSCORE AGENT_ENV_KEY_TO_PROPS.put( - CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, entry.getKey().replace('.', '-')), + ConfigPropertiesUtils.toEnvVarName(entry.getKey()), entry.getValue() ); } @@ -112,22 +110,12 @@ private ConfigFactory() { /** * Get config file path from system properties or environment variables - *

- * user special config: - * -Deaseagent.config.path=/easeagent/agent.properties || export EASEAGENT_CONFIG_PATH=/easeagent/agent.properties - * or OTEL config format - * -Dotel.javaagent.configuration-file=/easeagent/agent.properties || export OTEL_JAVAAGENT_CONFIGURATION_FILE=/easeagent/agent.properties */ public static String getConfigPath() { - // get config path from -Deaseagent.config.path=xxx - String path = System.getProperty(AGENT_CONFIG_PATH_PROP_KEY); - if (StringUtils.isEmpty(path)) { - // get config path from export EASEAGENT_CONFIG_PATH=xxx - path = SystemEnv.get(AGENT_CONFIG_PATH_ENV_KEY); - } + // 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)) { - // get config path from OTEL configuration // eg: -Dotel.javaagent.configuration-file=/easeagent/agent.properties || export OTEL_JAVAAGENT_CONFIGURATION_FILE=/easeagent/agent.properties path = OtelSdkConfigs.getConfigPath(); } 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 000000000..b9b79a11b --- /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 index 5d5e36ec7..d5b484169 100644 --- a/config/src/main/java/com/megaease/easeagent/config/OtelSdkConfigs.java +++ b/config/src/main/java/com/megaease/easeagent/config/OtelSdkConfigs.java @@ -1,12 +1,12 @@ /* - * Copyright (c) 2021, MegaEase + * 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 + * 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, @@ -17,7 +17,6 @@ package com.megaease.easeagent.config; -import com.google.common.base.CaseFormat; import com.google.common.base.Splitter; import com.megaease.easeagent.plugin.utils.ImmutableMap; import com.megaease.easeagent.plugin.utils.SystemEnv; @@ -34,10 +33,9 @@ * {@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 = "OTEL_RESOURCE_ATTRIBUTES"; + 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 String CONFIG_PATH_ENV_KEY = "OTEL_JAVAAGENT_CONFIGURATION_FILE"; private static final Splitter.MapSplitter OTEL_RESOURCE_ATTRIBUTES_SPLITTER = Splitter.on(",") @@ -67,9 +65,9 @@ public class OtelSdkConfigs { } for (Map.Entry entry : OTEL_SDK_PROPS_TO_EASE_AGENT_PROPS.entrySet()) { - // lower.hyphen -> UPPER_UNDERSCORE + // dot.case -> UPPER_UNDERSCORE OTEL_SDK_ENV_VAR_TO_EASE_AGENT_PROPS.put( - CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, entry.getKey().replace('.', '-')), + ConfigPropertiesUtils.toEnvVarName(entry.getKey()), entry.getValue() ); } @@ -79,12 +77,7 @@ public class OtelSdkConfigs { * Get config path from java properties or environment variables */ static String getConfigPath() { - String path = System.getProperty(CONFIG_PATH_PROP_KEY); - if (StringUtils.isEmpty(path)) { - path = SystemEnv.get(CONFIG_PATH_ENV_KEY); - } - - return path; + return ConfigPropertiesUtils.getString(CONFIG_PATH_PROP_KEY); } @@ -96,7 +89,7 @@ static String getConfigPath() { static Map updateEnvCfg() { Map envCfg = new TreeMap<>(); - String configEnv = SystemEnv.get(OTEL_RESOURCE_ATTRIBUTES); + String configEnv = ConfigPropertiesUtils.getString(OTEL_RESOURCE_ATTRIBUTES_KEY); if (StringUtils.isNotEmpty(configEnv)) { Map map = OTEL_RESOURCE_ATTRIBUTES_SPLITTER.split(configEnv); if (!map.isEmpty()) { diff --git a/config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java b/config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java index 4b0eb78da..3a6f82016 100644 --- a/config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java +++ b/config/src/test/java/com/megaease/easeagent/config/OtelSdkConfigsTest.java @@ -1,12 +1,12 @@ /* - * Copyright (c) 2021, MegaEase + * 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 + * 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, From 7c2cb021c45f271d8815017b85878de7ee0468a4 Mon Sep 17 00:00:00 2001 From: enoch Date: Wed, 13 Sep 2023 18:03:23 +0800 Subject: [PATCH 06/10] test: Tests for ConfigPropertiesUtils --- config/pom.xml | 6 ++ .../config/ConfigPropertiesUtilsTest.java | 95 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 config/src/test/java/com/megaease/easeagent/config/ConfigPropertiesUtilsTest.java diff --git a/config/pom.xml b/config/pom.xml index 3b9945e9d..c66a64c70 100644 --- a/config/pom.xml +++ b/config/pom.xml @@ -61,5 +61,11 @@ com.google.guava guava + + com.github.stefanbirkner + system-rules + 1.19.0 + test + 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 000000000..0799d409b --- /dev/null +++ b/config/src/test/java/com/megaease/easeagent/config/ConfigPropertiesUtilsTest.java @@ -0,0 +1,95 @@ +/* + * 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.Assert; +import org.junit.Rule; +import org.junit.Test; +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(); + + @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)); + } +} From 082d65dbec97186925d688e84dff3cdd2b79b274 Mon Sep 17 00:00:00 2001 From: enoch Date: Wed, 13 Sep 2023 18:42:17 +0800 Subject: [PATCH 07/10] docs: Add configuring priority --- doc/user-manual.md | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/doc/user-manual.md b/doc/user-manual.md index 6248afdb6..2a28f6c02 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. From 7743f8dbdedeb2b484e3d23a02a55c1c81e9a329 Mon Sep 17 00:00:00 2001 From: enoch Date: Wed, 13 Sep 2023 23:16:51 +0800 Subject: [PATCH 08/10] fix: com.github.stefanbirkner:system-rule test does not work with Java 16 --- .../easeagent/config/ConfigPropertiesUtilsTest.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/config/src/test/java/com/megaease/easeagent/config/ConfigPropertiesUtilsTest.java b/config/src/test/java/com/megaease/easeagent/config/ConfigPropertiesUtilsTest.java index 0799d409b..89bb555c6 100644 --- a/config/src/test/java/com/megaease/easeagent/config/ConfigPropertiesUtilsTest.java +++ b/config/src/test/java/com/megaease/easeagent/config/ConfigPropertiesUtilsTest.java @@ -17,9 +17,7 @@ package com.megaease.easeagent.config; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.contrib.java.lang.system.RestoreSystemProperties; @@ -33,6 +31,15 @@ public class ConfigPropertiesUtilsTest { 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"); From dd0af31ca2f8f9848ba91a46f36f21a1fbae1f59 Mon Sep 17 00:00:00 2001 From: enoch Date: Fri, 15 Sep 2023 14:46:55 +0800 Subject: [PATCH 09/10] feat: support for get "easeagent.log.conf" from environment variable "EASEAGENT_LOG_CONF" --- .../java/com/megaease/easeagent/Main.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/loader/src/main/java/com/megaease/easeagent/Main.java b/loader/src/main/java/com/megaease/easeagent/Main.java index 319e7f901..915bfd4ed 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), From f1003908744724a632d3ab84a1a06f3d12c07d3d Mon Sep 17 00:00:00 2001 From: enoch Date: Fri, 15 Sep 2023 15:17:53 +0800 Subject: [PATCH 10/10] docs: support for get "easeagent.log.conf" from environment variable "EASEAGENT_LOG_CONF" --- doc/user-manual.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/user-manual.md b/doc/user-manual.md index 2a28f6c02..cb8c5b057 100644 --- a/doc/user-manual.md +++ b/doc/user-manual.md @@ -394,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.