Load OTel SDK config from environment variables and system properties.… (#1434)
This commit is contained in:
parent
2b6625ef8a
commit
bfd739042d
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/** Utility class to use the {@link AutoConfiguredOpenTelemetrySdk}. */
|
||||
public class AutoConfigureUtil2 {
|
||||
|
||||
private AutoConfigureUtil2() {}
|
||||
|
||||
/**
|
||||
* Returns the {@link Resource} that was autoconfigured.
|
||||
*
|
||||
* <p>Inspired by {@link
|
||||
* io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil#getConfig(AutoConfiguredOpenTelemetrySdk)}
|
||||
*/
|
||||
public static Resource getResource(
|
||||
AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) {
|
||||
try {
|
||||
Method method = AutoConfiguredOpenTelemetrySdk.class.getDeclaredMethod("getResource");
|
||||
method.setAccessible(true);
|
||||
return (Resource) method.invoke(autoConfiguredOpenTelemetrySdk);
|
||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||
throw new IllegalStateException(
|
||||
"Error calling getResource on AutoConfiguredOpenTelemetrySdk", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,19 +5,24 @@
|
|||
|
||||
package io.opentelemetry.maven;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.context.propagation.ContextPropagators;
|
||||
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.io.Closeable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
@ -36,6 +41,10 @@ public final class OpenTelemetrySdkService implements Closeable {
|
|||
|
||||
private final OpenTelemetrySdk openTelemetrySdk;
|
||||
|
||||
@VisibleForTesting final Resource resource;
|
||||
|
||||
private final ConfigProperties configProperties;
|
||||
|
||||
private final Tracer tracer;
|
||||
|
||||
private final boolean mojosInstrumentationEnabled;
|
||||
|
@ -47,32 +56,68 @@ public final class OpenTelemetrySdkService implements Closeable {
|
|||
"OpenTelemetry: Initialize OpenTelemetrySdkService v{}...",
|
||||
MavenOtelSemanticAttributes.TELEMETRY_DISTRO_VERSION_VALUE);
|
||||
|
||||
// Change default of "otel.[traces,metrics,logs].exporter" from "otlp" to "none"
|
||||
// The impacts are
|
||||
// * If no otel exporter settings are passed, then the Maven extension will not export
|
||||
// rather than exporting on OTLP GRPC to http://localhost:4317
|
||||
// * If OTEL_EXPORTER_OTLP_ENDPOINT is defined but OTEL_[TRACES,METRICS,LOGS]_EXPORTER,
|
||||
// is not, then don't export
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("otel.traces.exporter", "none");
|
||||
properties.put("otel.metrics.exporter", "none");
|
||||
properties.put("otel.logs.exporter", "none");
|
||||
|
||||
AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk =
|
||||
AutoConfiguredOpenTelemetrySdk.builder()
|
||||
.setServiceClassLoader(getClass().getClassLoader())
|
||||
.addPropertiesSupplier(() -> properties)
|
||||
.addPropertiesCustomizer(
|
||||
OpenTelemetrySdkService::requireExplicitConfigOfTheOtlpExporter)
|
||||
.disableShutdownHook()
|
||||
.build();
|
||||
|
||||
this.openTelemetrySdk = autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk();
|
||||
this.configProperties =
|
||||
Optional.ofNullable(AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk))
|
||||
.orElseGet(() -> DefaultConfigProperties.createFromMap(Collections.emptyMap()));
|
||||
|
||||
Boolean mojoSpansEnabled = getBooleanConfig("otel.instrumentation.maven.mojo.enabled");
|
||||
this.mojosInstrumentationEnabled = mojoSpansEnabled == null || mojoSpansEnabled;
|
||||
this.resource = AutoConfigureUtil2.getResource(autoConfiguredOpenTelemetrySdk);
|
||||
// Display resource attributes in debug logs for troubleshooting when traces are not found in
|
||||
// the observability backend, helping understand `service.name`, `service.namespace`, etc.
|
||||
logger.debug("OpenTelemetry: OpenTelemetrySdkService initialized, resource:{}", resource);
|
||||
|
||||
this.mojosInstrumentationEnabled =
|
||||
configProperties.getBoolean("otel.instrumentation.maven.mojo.enabled", true);
|
||||
|
||||
this.tracer = openTelemetrySdk.getTracer("io.opentelemetry.contrib.maven", VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* The OTel SDK by default sends data to the OTLP gRPC endpoint localhost:4317 if no exporter and
|
||||
* no OTLP exporter endpoint are defined. This is not suited for a build tool for which we want
|
||||
* the OTel SDK to be disabled by default.
|
||||
*
|
||||
* <p>Change the OTel SDL behavior: if none of the exporter and the OTLP exporter endpoint are
|
||||
* defined, explicitly disable the exporter setting "{@code
|
||||
* otel.[traces,metrics,logs].exporter=none}"
|
||||
*
|
||||
* @return The properties to be returned by {@link
|
||||
* io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder#addPropertiesCustomizer(java.util.function.Function)}
|
||||
*/
|
||||
static Map<String, String> requireExplicitConfigOfTheOtlpExporter(
|
||||
ConfigProperties configProperties) {
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
if (configProperties.getString("otel.exporter.otlp.endpoint") != null) {
|
||||
logger.debug("OpenTelemetry: OTLP exporter endpoint is explicitly configured");
|
||||
return properties;
|
||||
}
|
||||
String[] signalTypes = {"traces", "metrics", "logs"};
|
||||
for (String signalType : signalTypes) {
|
||||
boolean isExporterImplicitlyConfiguredToOtlp =
|
||||
configProperties.getString("otel." + signalType + ".exporter") == null;
|
||||
boolean isOtlpExporterEndpointSpecified =
|
||||
configProperties.getString("otel.exporter.otlp." + signalType + ".endpoint") != null;
|
||||
|
||||
if (isExporterImplicitlyConfiguredToOtlp && !isOtlpExporterEndpointSpecified) {
|
||||
logger.debug(
|
||||
"OpenTelemetry: Disabling default OTLP exporter endpoint for signal {} exporter",
|
||||
signalType);
|
||||
properties.put("otel." + signalType + ".exporter", "none");
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
|
@ -97,6 +142,10 @@ public final class OpenTelemetrySdkService implements Closeable {
|
|||
return this.tracer;
|
||||
}
|
||||
|
||||
public ConfigProperties getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
/** Returns the {@link ContextPropagators} for this {@link OpenTelemetry}. */
|
||||
public ContextPropagators getPropagators() {
|
||||
return this.openTelemetrySdk.getPropagators();
|
||||
|
@ -105,17 +154,4 @@ public final class OpenTelemetrySdkService implements Closeable {
|
|||
public boolean isMojosInstrumentationEnabled() {
|
||||
return mojosInstrumentationEnabled;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Boolean getBooleanConfig(String name) {
|
||||
String value = System.getProperty(name);
|
||||
if (value != null) {
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
value = System.getenv(name.toUpperCase(Locale.ROOT).replace('.', '_'));
|
||||
if (value != null) {
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.maven;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||
import java.lang.reflect.Method;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AutoConfigureUtil2Test {
|
||||
|
||||
/**
|
||||
* Verify the reflection call works with the current version of AutoConfiguredOpenTelemetrySdk.
|
||||
*
|
||||
* @throws NoSuchMethodException if the method does not exist
|
||||
*/
|
||||
@Test
|
||||
void test_getResource() throws NoSuchMethodException {
|
||||
Method method = AutoConfiguredOpenTelemetrySdk.class.getDeclaredMethod("getResource");
|
||||
method.setAccessible(true);
|
||||
}
|
||||
}
|
|
@ -5,42 +5,132 @@
|
|||
|
||||
package io.opentelemetry.maven;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Note: if otel-java-contrib bumps to Java 11+, we could use junit-pioneer's
|
||||
* {@code @SetSystemProperty} and {@code @ClearSystemProperty} but no bump is planned for now.
|
||||
*/
|
||||
public class OpenTelemetrySdkServiceTest {
|
||||
|
||||
/** Verify default `service.name` */
|
||||
/** Verify default config */
|
||||
@Test
|
||||
@Disabled
|
||||
public void testDefaultConfiguration() {
|
||||
testConfiguration("maven");
|
||||
}
|
||||
System.clearProperty("otel.exporter.otlp.endpoint");
|
||||
System.clearProperty("otel.service.name");
|
||||
System.clearProperty("otel.resource.attributes");
|
||||
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
|
||||
|
||||
/** Verify overwritten `service.name` */
|
||||
@Test
|
||||
@Disabled
|
||||
public void testOverwrittenConfiguration() {
|
||||
System.setProperty("otel.service.name", "my-maven");
|
||||
try {
|
||||
testConfiguration("my-maven");
|
||||
} finally {
|
||||
System.clearProperty("otel.service.name");
|
||||
Resource resource = openTelemetrySdkService.resource;
|
||||
assertThat(resource.getAttribute(stringKey("service.name"))).isEqualTo("maven");
|
||||
|
||||
ConfigProperties configProperties = openTelemetrySdkService.getConfigProperties();
|
||||
assertThat(configProperties.getString("otel.exporter.otlp.endpoint")).isNull();
|
||||
assertThat(configProperties.getString("otel.traces.exporter")).isEqualTo("none");
|
||||
assertThat(configProperties.getString("otel.metrics.exporter")).isEqualTo("none");
|
||||
assertThat(configProperties.getString("otel.logs.exporter")).isEqualTo("none");
|
||||
}
|
||||
}
|
||||
|
||||
void testConfiguration(String expectedServiceName) {
|
||||
// OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService();
|
||||
// openTelemetrySdkService.initialize();
|
||||
// try {
|
||||
// Resource resource =
|
||||
// openTelemetrySdkService.autoConfiguredOpenTelemetrySdk.getResource();
|
||||
// assertThat(resource.getAttribute(ResourceAttributes.SERVICE_NAME))
|
||||
// .isEqualTo(expectedServiceName);
|
||||
// } finally {
|
||||
// openTelemetrySdkService.dispose();
|
||||
// GlobalOpenTelemetry.resetForTest();
|
||||
// GlobalEventEmitterProvider.resetForTest();
|
||||
// }
|
||||
/** Verify overwritten `service.name`,`key1` and `key2` */
|
||||
@Test
|
||||
public void testOverwrittenResourceAttributes() {
|
||||
System.setProperty("otel.service.name", "my-maven");
|
||||
System.setProperty("otel.resource.attributes", "key1=val1,key2=val2");
|
||||
|
||||
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
|
||||
|
||||
Resource resource = openTelemetrySdkService.resource;
|
||||
assertThat(resource.getAttribute(stringKey("service.name"))).isEqualTo("my-maven");
|
||||
assertThat(resource.getAttribute(stringKey("key1"))).isEqualTo("val1");
|
||||
assertThat(resource.getAttribute(stringKey("key2"))).isEqualTo("val2");
|
||||
|
||||
} finally {
|
||||
System.clearProperty("otel.service.name");
|
||||
System.clearProperty("otel.resource.attributes");
|
||||
}
|
||||
}
|
||||
|
||||
/** Verify defining `otel.exporter.otlp.endpoint` works */
|
||||
@Test
|
||||
public void testOverwrittenExporterConfiguration_1() {
|
||||
System.setProperty("otel.exporter.otlp.endpoint", "https://example.com:4317");
|
||||
|
||||
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
|
||||
|
||||
ConfigProperties configProperties = openTelemetrySdkService.getConfigProperties();
|
||||
assertThat(configProperties.getString("otel.exporter.otlp.endpoint"))
|
||||
.isEqualTo("https://example.com:4317");
|
||||
assertThat(configProperties.getString("otel.traces.exporter")).isNull();
|
||||
assertThat(configProperties.getString("otel.metrics.exporter")).isNull();
|
||||
assertThat(configProperties.getString("otel.logs.exporter")).isNull();
|
||||
|
||||
} finally {
|
||||
System.clearProperty("otel.exporter.otlp.endpoint");
|
||||
}
|
||||
}
|
||||
|
||||
/** Verify defining `otel.exporter.otlp.traces.endpoint` works */
|
||||
@Test
|
||||
public void testOverwrittenExporterConfiguration_2() {
|
||||
System.clearProperty("otel.exporter.otlp.endpoint");
|
||||
System.clearProperty("otel.traces.exporter");
|
||||
System.setProperty("otel.exporter.otlp.traces.endpoint", "https://example.com:4317/");
|
||||
|
||||
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
|
||||
|
||||
ConfigProperties configProperties = openTelemetrySdkService.getConfigProperties();
|
||||
assertThat(configProperties.getString("otel.exporter.otlp.endpoint")).isNull();
|
||||
assertThat(configProperties.getString("otel.exporter.otlp.traces.endpoint"))
|
||||
.isEqualTo("https://example.com:4317/");
|
||||
assertThat(configProperties.getString("otel.traces.exporter")).isNull();
|
||||
assertThat(configProperties.getString("otel.metrics.exporter")).isEqualTo("none");
|
||||
assertThat(configProperties.getString("otel.logs.exporter")).isEqualTo("none");
|
||||
|
||||
} finally {
|
||||
System.clearProperty("otel.exporter.otlp.endpoint");
|
||||
System.clearProperty("otel.traces.exporter");
|
||||
System.clearProperty("otel.exporter.otlp.traces.endpoint");
|
||||
}
|
||||
}
|
||||
|
||||
/** Verify defining `otel.exporter.otlp.traces.endpoint` and `otel.traces.exporter` works */
|
||||
@Test
|
||||
public void testOverwrittenExporterConfiguration_3() {
|
||||
System.clearProperty("otel.exporter.otlp.endpoint");
|
||||
System.setProperty("otel.traces.exporter", "otlp");
|
||||
System.setProperty("otel.exporter.otlp.traces.endpoint", "https://example.com:4317/");
|
||||
|
||||
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
|
||||
|
||||
ConfigProperties configProperties = openTelemetrySdkService.getConfigProperties();
|
||||
assertThat(configProperties.getString("otel.exporter.otlp.endpoint")).isNull();
|
||||
assertThat(configProperties.getString("otel.exporter.otlp.traces.endpoint"))
|
||||
.isEqualTo("https://example.com:4317/");
|
||||
assertThat(configProperties.getString("otel.traces.exporter")).isEqualTo("otlp");
|
||||
assertThat(configProperties.getString("otel.metrics.exporter")).isEqualTo("none");
|
||||
assertThat(configProperties.getString("otel.logs.exporter")).isEqualTo("none");
|
||||
|
||||
} finally {
|
||||
System.clearProperty("otel.exporter.otlp.endpoint");
|
||||
System.clearProperty("otel.exporter.otlp.traces.endpoint");
|
||||
System.clearProperty("otel.exporter.otlp.traces.protocol");
|
||||
}
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() {
|
||||
System.clearProperty("otel.exporter.otlp.endpoint");
|
||||
System.clearProperty("otel.exporter.otlp.traces.endpoint");
|
||||
System.clearProperty("otel.exporter.otlp.traces.protocol");
|
||||
System.clearProperty("otel.resource.attributes");
|
||||
System.clearProperty("otel.service.name");
|
||||
System.clearProperty("otel.traces.exporter");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue