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
11 changes: 10 additions & 1 deletion config/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,19 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.19.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -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<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.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()) {
// 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
* <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 +86,41 @@ 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() {
}

/**
* 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
Expand All @@ -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());

Expand Down
Original file line number Diff line number Diff line change
@@ -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() {
}
}
123 changes: 123 additions & 0 deletions config/src/main/java/com/megaease/easeagent/config/OtelSdkConfigs.java
Original file line number Diff line number Diff line change
@@ -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.
* <p>
* {@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<String, String> SDK_ATTRIBUTES_TO_EASE_AGENT_PROPS =
ImmutableMap.<String, String>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<String, String> OTEL_SDK_PROPS_TO_EASE_AGENT_PROPS = new HashMap<>();

// OTEL_SERVICE_NAME=xxx
private static final Map<String, String> OTEL_SDK_ENV_VAR_TO_EASE_AGENT_PROPS = new HashMap<>();

static {
for (Map.Entry<String, String> 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<String, String> 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
* <p>
* java properties > environment variables > OTEL_RESOURCE_ATTRIBUTES
*/
static Map<String, String> updateEnvCfg() {
Map<String, String> envCfg = new TreeMap<>();

String configEnv = ConfigPropertiesUtils.getString(OTEL_RESOURCE_ATTRIBUTES_KEY);
if (StringUtils.isNotEmpty(configEnv)) {
Map<String, String> map = OTEL_RESOURCE_ATTRIBUTES_SPLITTER.split(configEnv);
if (!map.isEmpty()) {
for (Map.Entry<String, String> 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<String, String> 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<String, String> 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;
}
}
Loading
Loading