Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Compatible with opentelemetry-java env configuration. #318

Merged
merged 10 commits into from
Sep 18, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> subEnvKeys = new LinkedList<>();
private static final List<String> envKeys = new LinkedList<>();
private static final Map<String, String> AGENT_CONFIG_KEYS_TO_PROPS =
ImmutableMap.<String, String>builder()
.put("easeagent.config.path", AGENT_CONFIG_PATH)
observeralone marked this conversation as resolved.
Show resolved Hide resolved
.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<String, String> 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<String, String> 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
* <p>
* java properties > environment variables > env:EASEAGENT_ENV_CONFIG={} > default
*/
static Map<String, String> updateEnvCfg() {
Map<String, String> 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<String, Object> map = JsonUtil.toMap(configEnv);
Expand All @@ -77,12 +90,45 @@ static Map<String, String> updateEnvCfg() {
envCfg.putAll(strMap);
}

// override by environment variables, eg: export EASEAGENT_NAME=xxx
for (Map.Entry<String, String> 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<String, String> 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.
* <p>
* 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<String, String> envCfg = updateEnvCfg();
String configFile = envCfg.get(AGENT_CONFIG_PATH);
if (StringUtils.isEmpty(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
Expand All @@ -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());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,78 @@

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<SystemEnv> 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<SystemEnv> 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() throws URISyntaxException {
String userSpec = new File(this.getClass().getClassLoader().getResource("user-spec.properties").toURI()).getPath();

try (MockedStatic<SystemEnv> 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() throws URISyntaxException {
String userSpec = new File(this.getClass().getClassLoader().getResource("user-spec.properties").toURI()).getPath();
try (MockedStatic<SystemEnv> 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));

}
}
}
2 changes: 2 additions & 0 deletions config/src/test/resources/user-spec.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name=user-spec
system=system-spec
2 changes: 2 additions & 0 deletions config/src/test/resources/user-spec2.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name=user-spec2
system=system-spec2
16 changes: 3 additions & 13 deletions core/src/main/java/com/megaease/easeagent/core/Bootstrap.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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";

Expand All @@ -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);
observeralone marked this conversation as resolved.
Show resolved Hide resolved
wrapConfig(conf);

// loader check
Expand Down Expand Up @@ -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);
observeralone marked this conversation as resolved.
Show resolved Hide resolved

AgentHttpServer agentHttpServer = new AgentHttpServer(port);

Expand Down
4 changes: 4 additions & 0 deletions plugin-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<artifactId>plugin-api</artifactId>

<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
observeralone marked this conversation as resolved.
Show resolved Hide resolved
<dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Loading
Loading