Skip to content

Commit

Permalink
GlobalOpenTelemetry trigger of autoconfiguration is opt-in (open-tele…
Browse files Browse the repository at this point in the history
…metry#5010)

* Do not initialize AutoConfiguredOpenTelemetrySdk in OpenTelemetry.get

* GlobalOpenTelemetry triggers autoconfigure based on env var / system property
  • Loading branch information
jack-berg authored and dmarkwat committed Dec 30, 2022
1 parent 9ae93ee commit 25c1b30
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 44 deletions.
5 changes: 5 additions & 0 deletions api/all/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ dependencies {
testImplementation("edu.berkeley.cs.jqf:jqf-fuzz")
testImplementation("com.google.guava:guava-testlib")
}

tasks.test {
// Configure environment variable for ConfigUtilTest
environment("CONFIG_KEY", "environment")
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.api;

import io.opentelemetry.api.internal.ConfigUtil;
import io.opentelemetry.api.internal.GuardedBy;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterBuilder;
Expand Down Expand Up @@ -44,6 +45,9 @@
@SuppressWarnings("StaticAssignmentOfThrowable")
public final class GlobalOpenTelemetry {

private static final String GLOBAL_AUTOCONFIGURE_ENABLED_PROPERTY =
"otel.java.global-autoconfigure.enabled";

private static final Logger logger = Logger.getLogger(GlobalOpenTelemetry.class.getName());

private static final Object mutex = new Object();
Expand Down Expand Up @@ -219,15 +223,29 @@ private static OpenTelemetry maybeAutoConfigureAndSetGlobal() {
return null;
}

// If autoconfigure module is present but global autoconfigure disabled log a warning and return
boolean globalAutoconfigureEnabled =
Boolean.parseBoolean(ConfigUtil.getString(GLOBAL_AUTOCONFIGURE_ENABLED_PROPERTY));
if (!globalAutoconfigureEnabled) {
logger.log(
Level.INFO,
"AutoConfiguredOpenTelemetrySdk found on classpath but automatic configuration is disabled."
+ " To enable, run your JVM with -D"
+ GLOBAL_AUTOCONFIGURE_ENABLED_PROPERTY
+ "=true");
return null;
}

try {
Method initialize = openTelemetrySdkAutoConfiguration.getMethod("initialize");
Object autoConfiguredSdk = initialize.invoke(null);
Method getOpenTelemetrySdk =
openTelemetrySdkAutoConfiguration.getMethod("getOpenTelemetrySdk");
return (OpenTelemetry) getOpenTelemetrySdk.invoke(autoConfiguredSdk);
return new ObfuscatedOpenTelemetry(
(OpenTelemetry) getOpenTelemetrySdk.invoke(autoConfiguredSdk));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new IllegalStateException(
"OpenTelemetrySdkAutoConfiguration detected on classpath "
"AutoConfiguredOpenTelemetrySdk detected on classpath "
+ "but could not invoke initialize method. This is a bug in OpenTelemetry.",
e);
} catch (InvocationTargetException t) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.api.internal;

import java.util.Locale;
import java.util.Map;
import javax.annotation.Nullable;

/**
* Configuration utilities.
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
public final class ConfigUtil {

private ConfigUtil() {}

/**
* Return the system property or environment variable for the {@code key}.
*
* <p>Normalize the {@code key} using {@link #normalizePropertyKey(String)}. Match to system
* property keys also normalized with {@link #normalizePropertyKey(String)}. Match to environment
* variable keys normalized with {@link #normalizeEnvironmentVariableKey(String)}. System
* properties take priority over environment variables.
*
* @param key the property key
* @return the system property if not null, or the environment variable if not null, or null
*/
@Nullable
public static String getString(String key) {
String normalizedKey = normalizePropertyKey(key);
String systemProperty =
System.getProperties().entrySet().stream()
.filter(entry -> normalizedKey.equals(normalizePropertyKey(entry.getKey().toString())))
.map(entry -> entry.getValue().toString())
.findFirst()
.orElse(null);
if (systemProperty != null) {
return systemProperty;
}
return System.getenv().entrySet().stream()
.filter(entry -> normalizedKey.equals(normalizeEnvironmentVariableKey(entry.getKey())))
.map(Map.Entry::getValue)
.findFirst()
.orElse(null);
}

/**
* Normalize an environment variable key by converting to lower case and replacing "_" with ".".
*/
public static String normalizeEnvironmentVariableKey(String key) {
return key.toLowerCase(Locale.ROOT).replace("_", ".");
}

/** Normalize a property key by converting to lower case and replacing "-" with ".". */
public static String normalizePropertyKey(String key) {
return key.toLowerCase(Locale.ROOT).replace("-", ".");
}

/** Returns defaultValue if value is null, otherwise value. This is an internal method. */
public static <T> T defaultIfNull(@Nullable T value, T defaultValue) {
return value == null ? defaultValue : value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.api.internal;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.junitpioneer.jupiter.SetSystemProperty;

/** Relies on environment configuration in {@code ./api/all/build.gradle.kts}. */
class ConfigUtilTest {

@Test
@SetSystemProperty(key = "config.key", value = "system")
void getString_SystemPropertyPriority() {
assertThat(ConfigUtil.getString("config.key")).isEqualTo("system");
assertThat(ConfigUtil.getString("config-key")).isEqualTo("system");
assertThat(ConfigUtil.getString("other.config.key")).isEqualTo(null);
}

@Test
@SetSystemProperty(key = "CONFIG-KEY", value = "system")
void getString_SystemPropertyNormalized() {
assertThat(ConfigUtil.getString("config.key")).isEqualTo("system");
assertThat(ConfigUtil.getString("config-key")).isEqualTo("system");
assertThat(ConfigUtil.getString("other.config.key")).isEqualTo(null);
}

@Test
void getString_EnvironmentVariable() {
assertThat(ConfigUtil.getString("config.key")).isEqualTo("environment");
assertThat(ConfigUtil.getString("other.config.key")).isEqualTo(null);
}

@Test
void normalizeEnvironmentVariable() {
assertThat(ConfigUtil.normalizeEnvironmentVariableKey("CONFIG_KEY")).isEqualTo("config.key");
assertThat(ConfigUtil.normalizeEnvironmentVariableKey("config_key")).isEqualTo("config.key");
assertThat(ConfigUtil.normalizeEnvironmentVariableKey("config-key")).isEqualTo("config-key");
assertThat(ConfigUtil.normalizeEnvironmentVariableKey("configkey")).isEqualTo("configkey");
}

@Test
void normalizePropertyKey() {
assertThat(ConfigUtil.normalizePropertyKey("CONFIG_KEY")).isEqualTo("config_key");
assertThat(ConfigUtil.normalizePropertyKey("CONFIG.KEY")).isEqualTo("config.key");
assertThat(ConfigUtil.normalizePropertyKey("config-key")).isEqualTo("config.key");
assertThat(ConfigUtil.normalizePropertyKey("configkey")).isEqualTo("configkey");
}

@Test
void defaultIfnull() {
assertThat(ConfigUtil.defaultIfNull("val1", "val2")).isEqualTo("val1");
assertThat(ConfigUtil.defaultIfNull(null, "val2")).isEqualTo("val2");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

package io.opentelemetry.sdk.autoconfigure.spi;

import static io.opentelemetry.sdk.autoconfigure.spi.ConfigUtil.defaultIfNull;
import static io.opentelemetry.api.internal.ConfigUtil.defaultIfNull;

import java.time.Duration;
import java.util.List;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining;

import io.opentelemetry.api.internal.ConfigUtil;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import java.time.Duration;
Expand All @@ -18,7 +19,6 @@
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
Expand All @@ -43,7 +43,7 @@ public final class DefaultConfigProperties implements ConfigProperties {
* and the {@code defaultProperties}.
*
* <p>Environment variables take priority over {@code defaultProperties}. System properties take
* priority over system properties.
* priority over environment variables.
*/
public static DefaultConfigProperties create(Map<String, String> defaultProperties) {
return new DefaultConfigProperties(System.getProperties(), System.getenv(), defaultProperties);
Expand All @@ -62,11 +62,13 @@ private DefaultConfigProperties(
Map<String, String> environmentVariables,
Map<String, String> defaultProperties) {
Map<String, String> config = new HashMap<>();
defaultProperties.forEach((name, value) -> config.put(normalize(name), value));
defaultProperties.forEach(
(name, value) -> config.put(ConfigUtil.normalizePropertyKey(name), value));
environmentVariables.forEach(
(name, value) -> config.put(name.toLowerCase(Locale.ROOT).replace('_', '.'), value));
(name, value) -> config.put(ConfigUtil.normalizeEnvironmentVariableKey(name), value));
systemProperties.forEach(
(key, value) -> config.put(normalize(key.toString()), value.toString()));
(key, value) ->
config.put(ConfigUtil.normalizePropertyKey(key.toString()), value.toString()));

this.config = config;
}
Expand All @@ -75,21 +77,21 @@ private DefaultConfigProperties(
DefaultConfigProperties previousProperties, Map<String, String> overrides) {
// previousProperties are already normalized, they can be copied as they are
Map<String, String> config = new HashMap<>(previousProperties.config);
overrides.forEach((name, value) -> config.put(normalize(name), value));
overrides.forEach((name, value) -> config.put(ConfigUtil.normalizePropertyKey(name), value));

this.config = config;
}

@Override
@Nullable
public String getString(String name) {
return config.get(normalize(name));
return config.get(ConfigUtil.normalizePropertyKey(name));
}

@Override
@Nullable
public Boolean getBoolean(String name) {
String value = config.get(normalize(name));
String value = config.get(ConfigUtil.normalizePropertyKey(name));
if (value == null || value.isEmpty()) {
return null;
}
Expand All @@ -100,7 +102,7 @@ public Boolean getBoolean(String name) {
@Nullable
@SuppressWarnings("UnusedException")
public Integer getInt(String name) {
String value = config.get(normalize(name));
String value = config.get(ConfigUtil.normalizePropertyKey(name));
if (value == null || value.isEmpty()) {
return null;
}
Expand All @@ -115,7 +117,7 @@ public Integer getInt(String name) {
@Nullable
@SuppressWarnings("UnusedException")
public Long getLong(String name) {
String value = config.get(normalize(name));
String value = config.get(ConfigUtil.normalizePropertyKey(name));
if (value == null || value.isEmpty()) {
return null;
}
Expand All @@ -130,7 +132,7 @@ public Long getLong(String name) {
@Nullable
@SuppressWarnings("UnusedException")
public Double getDouble(String name) {
String value = config.get(normalize(name));
String value = config.get(ConfigUtil.normalizePropertyKey(name));
if (value == null || value.isEmpty()) {
return null;
}
Expand All @@ -145,7 +147,7 @@ public Double getDouble(String name) {
@Nullable
@SuppressWarnings("UnusedException")
public Duration getDuration(String name) {
String value = config.get(normalize(name));
String value = config.get(ConfigUtil.normalizePropertyKey(name));
if (value == null || value.isEmpty()) {
return null;
}
Expand Down Expand Up @@ -174,7 +176,7 @@ public Duration getDuration(String name) {

@Override
public List<String> getList(String name) {
String value = config.get(normalize(name));
String value = config.get(ConfigUtil.normalizePropertyKey(name));
if (value == null) {
return Collections.emptyList();
}
Expand All @@ -188,7 +190,7 @@ public List<String> getList(String name) {
* @throws ConfigurationException if {@code name} contains duplicate entries
*/
public static Set<String> getSet(ConfigProperties config, String name) {
List<String> list = config.getList(normalize(name));
List<String> list = config.getList(ConfigUtil.normalizePropertyKey(name));
Set<String> set = new HashSet<>(list);
if (set.size() != list.size()) {
String duplicates =
Expand All @@ -206,7 +208,7 @@ public static Set<String> getSet(ConfigProperties config, String name) {

@Override
public Map<String, String> getMap(String name) {
return getList(normalize(name)).stream()
return getList(ConfigUtil.normalizePropertyKey(name)).stream()
.map(keyValuePair -> filterBlanksAndNulls(keyValuePair.split("=", 2)))
.map(
splitKeyValuePairs -> {
Expand Down Expand Up @@ -281,8 +283,4 @@ private static String getUnitString(String rawValue) {
// Pull everything after the last digit.
return rawValue.substring(lastDigitIndex + 1);
}

private static String normalize(String propertyName) {
return propertyName.toLowerCase(Locale.ROOT).replace('-', '.');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ void invalidSampler() {
@Test
@SetSystemProperty(key = "otel.traces.sampler", value = "traceidratio")
@SetSystemProperty(key = "otel.traces.sampler.arg", value = "bar")
@SetSystemProperty(key = "otel.java.global-autoconfigure.enabled", value = "true")
@SuppressLogger(GlobalOpenTelemetry.class)
void globalOpenTelemetryWhenError() {
assertThat(GlobalOpenTelemetry.get())
Expand Down
Loading

0 comments on commit 25c1b30

Please sign in to comment.