Skip to content

Commit bfd7390

Browse files
Load OTel SDK config from environment variables and system properties.… (#1434)
1 parent 2b6625e commit bfd7390

File tree

4 files changed

+236
-51
lines changed

4 files changed

+236
-51
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.maven;
7+
8+
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
9+
import io.opentelemetry.sdk.resources.Resource;
10+
import java.lang.reflect.InvocationTargetException;
11+
import java.lang.reflect.Method;
12+
13+
/** Utility class to use the {@link AutoConfiguredOpenTelemetrySdk}. */
14+
public class AutoConfigureUtil2 {
15+
16+
private AutoConfigureUtil2() {}
17+
18+
/**
19+
* Returns the {@link Resource} that was autoconfigured.
20+
*
21+
* <p>Inspired by {@link
22+
* io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil#getConfig(AutoConfiguredOpenTelemetrySdk)}
23+
*/
24+
public static Resource getResource(
25+
AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) {
26+
try {
27+
Method method = AutoConfiguredOpenTelemetrySdk.class.getDeclaredMethod("getResource");
28+
method.setAccessible(true);
29+
return (Resource) method.invoke(autoConfiguredOpenTelemetrySdk);
30+
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
31+
throw new IllegalStateException(
32+
"Error calling getResource on AutoConfiguredOpenTelemetrySdk", e);
33+
}
34+
}
35+
}

maven-extension/src/main/java/io/opentelemetry/maven/OpenTelemetrySdkService.java

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,24 @@
55

66
package io.opentelemetry.maven;
77

8+
import com.google.common.annotations.VisibleForTesting;
89
import io.opentelemetry.api.OpenTelemetry;
910
import io.opentelemetry.api.trace.Tracer;
1011
import io.opentelemetry.context.propagation.ContextPropagators;
1112
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
1213
import io.opentelemetry.sdk.OpenTelemetrySdk;
1314
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
15+
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
16+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
17+
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
1418
import io.opentelemetry.sdk.common.CompletableResultCode;
19+
import io.opentelemetry.sdk.resources.Resource;
1520
import java.io.Closeable;
21+
import java.util.Collections;
1622
import java.util.HashMap;
17-
import java.util.Locale;
1823
import java.util.Map;
24+
import java.util.Optional;
1925
import java.util.concurrent.TimeUnit;
20-
import javax.annotation.Nullable;
2126
import javax.annotation.PreDestroy;
2227
import javax.inject.Named;
2328
import javax.inject.Singleton;
@@ -36,6 +41,10 @@ public final class OpenTelemetrySdkService implements Closeable {
3641

3742
private final OpenTelemetrySdk openTelemetrySdk;
3843

44+
@VisibleForTesting final Resource resource;
45+
46+
private final ConfigProperties configProperties;
47+
3948
private final Tracer tracer;
4049

4150
private final boolean mojosInstrumentationEnabled;
@@ -47,32 +56,68 @@ public OpenTelemetrySdkService() {
4756
"OpenTelemetry: Initialize OpenTelemetrySdkService v{}...",
4857
MavenOtelSemanticAttributes.TELEMETRY_DISTRO_VERSION_VALUE);
4958

50-
// Change default of "otel.[traces,metrics,logs].exporter" from "otlp" to "none"
51-
// The impacts are
52-
// * If no otel exporter settings are passed, then the Maven extension will not export
53-
// rather than exporting on OTLP GRPC to http://localhost:4317
54-
// * If OTEL_EXPORTER_OTLP_ENDPOINT is defined but OTEL_[TRACES,METRICS,LOGS]_EXPORTER,
55-
// is not, then don't export
56-
Map<String, String> properties = new HashMap<>();
57-
properties.put("otel.traces.exporter", "none");
58-
properties.put("otel.metrics.exporter", "none");
59-
properties.put("otel.logs.exporter", "none");
60-
6159
AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk =
6260
AutoConfiguredOpenTelemetrySdk.builder()
6361
.setServiceClassLoader(getClass().getClassLoader())
64-
.addPropertiesSupplier(() -> properties)
62+
.addPropertiesCustomizer(
63+
OpenTelemetrySdkService::requireExplicitConfigOfTheOtlpExporter)
6564
.disableShutdownHook()
6665
.build();
6766

6867
this.openTelemetrySdk = autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk();
68+
this.configProperties =
69+
Optional.ofNullable(AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk))
70+
.orElseGet(() -> DefaultConfigProperties.createFromMap(Collections.emptyMap()));
71+
72+
this.resource = AutoConfigureUtil2.getResource(autoConfiguredOpenTelemetrySdk);
73+
// Display resource attributes in debug logs for troubleshooting when traces are not found in
74+
// the observability backend, helping understand `service.name`, `service.namespace`, etc.
75+
logger.debug("OpenTelemetry: OpenTelemetrySdkService initialized, resource:{}", resource);
6976

70-
Boolean mojoSpansEnabled = getBooleanConfig("otel.instrumentation.maven.mojo.enabled");
71-
this.mojosInstrumentationEnabled = mojoSpansEnabled == null || mojoSpansEnabled;
77+
this.mojosInstrumentationEnabled =
78+
configProperties.getBoolean("otel.instrumentation.maven.mojo.enabled", true);
7279

7380
this.tracer = openTelemetrySdk.getTracer("io.opentelemetry.contrib.maven", VERSION);
7481
}
7582

83+
/**
84+
* The OTel SDK by default sends data to the OTLP gRPC endpoint localhost:4317 if no exporter and
85+
* no OTLP exporter endpoint are defined. This is not suited for a build tool for which we want
86+
* the OTel SDK to be disabled by default.
87+
*
88+
* <p>Change the OTel SDL behavior: if none of the exporter and the OTLP exporter endpoint are
89+
* defined, explicitly disable the exporter setting "{@code
90+
* otel.[traces,metrics,logs].exporter=none}"
91+
*
92+
* @return The properties to be returned by {@link
93+
* io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder#addPropertiesCustomizer(java.util.function.Function)}
94+
*/
95+
static Map<String, String> requireExplicitConfigOfTheOtlpExporter(
96+
ConfigProperties configProperties) {
97+
98+
Map<String, String> properties = new HashMap<>();
99+
if (configProperties.getString("otel.exporter.otlp.endpoint") != null) {
100+
logger.debug("OpenTelemetry: OTLP exporter endpoint is explicitly configured");
101+
return properties;
102+
}
103+
String[] signalTypes = {"traces", "metrics", "logs"};
104+
for (String signalType : signalTypes) {
105+
boolean isExporterImplicitlyConfiguredToOtlp =
106+
configProperties.getString("otel." + signalType + ".exporter") == null;
107+
boolean isOtlpExporterEndpointSpecified =
108+
configProperties.getString("otel.exporter.otlp." + signalType + ".endpoint") != null;
109+
110+
if (isExporterImplicitlyConfiguredToOtlp && !isOtlpExporterEndpointSpecified) {
111+
logger.debug(
112+
"OpenTelemetry: Disabling default OTLP exporter endpoint for signal {} exporter",
113+
signalType);
114+
properties.put("otel." + signalType + ".exporter", "none");
115+
}
116+
}
117+
118+
return properties;
119+
}
120+
76121
@PreDestroy
77122
@Override
78123
public synchronized void close() {
@@ -97,6 +142,10 @@ public Tracer getTracer() {
97142
return this.tracer;
98143
}
99144

145+
public ConfigProperties getConfigProperties() {
146+
return configProperties;
147+
}
148+
100149
/** Returns the {@link ContextPropagators} for this {@link OpenTelemetry}. */
101150
public ContextPropagators getPropagators() {
102151
return this.openTelemetrySdk.getPropagators();
@@ -105,17 +154,4 @@ public ContextPropagators getPropagators() {
105154
public boolean isMojosInstrumentationEnabled() {
106155
return mojosInstrumentationEnabled;
107156
}
108-
109-
@Nullable
110-
private static Boolean getBooleanConfig(String name) {
111-
String value = System.getProperty(name);
112-
if (value != null) {
113-
return Boolean.parseBoolean(value);
114-
}
115-
value = System.getenv(name.toUpperCase(Locale.ROOT).replace('.', '_'));
116-
if (value != null) {
117-
return Boolean.parseBoolean(value);
118-
}
119-
return null;
120-
}
121157
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.maven;
7+
8+
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
9+
import java.lang.reflect.Method;
10+
import org.junit.jupiter.api.Test;
11+
12+
class AutoConfigureUtil2Test {
13+
14+
/**
15+
* Verify the reflection call works with the current version of AutoConfiguredOpenTelemetrySdk.
16+
*
17+
* @throws NoSuchMethodException if the method does not exist
18+
*/
19+
@Test
20+
void test_getResource() throws NoSuchMethodException {
21+
Method method = AutoConfiguredOpenTelemetrySdk.class.getDeclaredMethod("getResource");
22+
method.setAccessible(true);
23+
}
24+
}

maven-extension/src/test/java/io/opentelemetry/maven/OpenTelemetrySdkServiceTest.java

Lines changed: 112 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,132 @@
55

66
package io.opentelemetry.maven;
77

8-
import org.junit.jupiter.api.Disabled;
8+
import static io.opentelemetry.api.common.AttributeKey.stringKey;
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
11+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
12+
import io.opentelemetry.sdk.resources.Resource;
13+
import org.junit.jupiter.api.AfterAll;
914
import org.junit.jupiter.api.Test;
1015

16+
/**
17+
* Note: if otel-java-contrib bumps to Java 11+, we could use junit-pioneer's
18+
* {@code @SetSystemProperty} and {@code @ClearSystemProperty} but no bump is planned for now.
19+
*/
1120
public class OpenTelemetrySdkServiceTest {
1221

13-
/** Verify default `service.name` */
22+
/** Verify default config */
1423
@Test
15-
@Disabled
1624
public void testDefaultConfiguration() {
17-
testConfiguration("maven");
25+
System.clearProperty("otel.exporter.otlp.endpoint");
26+
System.clearProperty("otel.service.name");
27+
System.clearProperty("otel.resource.attributes");
28+
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
29+
30+
Resource resource = openTelemetrySdkService.resource;
31+
assertThat(resource.getAttribute(stringKey("service.name"))).isEqualTo("maven");
32+
33+
ConfigProperties configProperties = openTelemetrySdkService.getConfigProperties();
34+
assertThat(configProperties.getString("otel.exporter.otlp.endpoint")).isNull();
35+
assertThat(configProperties.getString("otel.traces.exporter")).isEqualTo("none");
36+
assertThat(configProperties.getString("otel.metrics.exporter")).isEqualTo("none");
37+
assertThat(configProperties.getString("otel.logs.exporter")).isEqualTo("none");
38+
}
1839
}
1940

20-
/** Verify overwritten `service.name` */
41+
/** Verify overwritten `service.name`,`key1` and `key2` */
2142
@Test
22-
@Disabled
23-
public void testOverwrittenConfiguration() {
43+
public void testOverwrittenResourceAttributes() {
2444
System.setProperty("otel.service.name", "my-maven");
25-
try {
26-
testConfiguration("my-maven");
45+
System.setProperty("otel.resource.attributes", "key1=val1,key2=val2");
46+
47+
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
48+
49+
Resource resource = openTelemetrySdkService.resource;
50+
assertThat(resource.getAttribute(stringKey("service.name"))).isEqualTo("my-maven");
51+
assertThat(resource.getAttribute(stringKey("key1"))).isEqualTo("val1");
52+
assertThat(resource.getAttribute(stringKey("key2"))).isEqualTo("val2");
53+
2754
} finally {
2855
System.clearProperty("otel.service.name");
56+
System.clearProperty("otel.resource.attributes");
57+
}
58+
}
59+
60+
/** Verify defining `otel.exporter.otlp.endpoint` works */
61+
@Test
62+
public void testOverwrittenExporterConfiguration_1() {
63+
System.setProperty("otel.exporter.otlp.endpoint", "https://example.com:4317");
64+
65+
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
66+
67+
ConfigProperties configProperties = openTelemetrySdkService.getConfigProperties();
68+
assertThat(configProperties.getString("otel.exporter.otlp.endpoint"))
69+
.isEqualTo("https://example.com:4317");
70+
assertThat(configProperties.getString("otel.traces.exporter")).isNull();
71+
assertThat(configProperties.getString("otel.metrics.exporter")).isNull();
72+
assertThat(configProperties.getString("otel.logs.exporter")).isNull();
73+
74+
} finally {
75+
System.clearProperty("otel.exporter.otlp.endpoint");
76+
}
77+
}
78+
79+
/** Verify defining `otel.exporter.otlp.traces.endpoint` works */
80+
@Test
81+
public void testOverwrittenExporterConfiguration_2() {
82+
System.clearProperty("otel.exporter.otlp.endpoint");
83+
System.clearProperty("otel.traces.exporter");
84+
System.setProperty("otel.exporter.otlp.traces.endpoint", "https://example.com:4317/");
85+
86+
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
87+
88+
ConfigProperties configProperties = openTelemetrySdkService.getConfigProperties();
89+
assertThat(configProperties.getString("otel.exporter.otlp.endpoint")).isNull();
90+
assertThat(configProperties.getString("otel.exporter.otlp.traces.endpoint"))
91+
.isEqualTo("https://example.com:4317/");
92+
assertThat(configProperties.getString("otel.traces.exporter")).isNull();
93+
assertThat(configProperties.getString("otel.metrics.exporter")).isEqualTo("none");
94+
assertThat(configProperties.getString("otel.logs.exporter")).isEqualTo("none");
95+
96+
} finally {
97+
System.clearProperty("otel.exporter.otlp.endpoint");
98+
System.clearProperty("otel.traces.exporter");
99+
System.clearProperty("otel.exporter.otlp.traces.endpoint");
100+
}
101+
}
102+
103+
/** Verify defining `otel.exporter.otlp.traces.endpoint` and `otel.traces.exporter` works */
104+
@Test
105+
public void testOverwrittenExporterConfiguration_3() {
106+
System.clearProperty("otel.exporter.otlp.endpoint");
107+
System.setProperty("otel.traces.exporter", "otlp");
108+
System.setProperty("otel.exporter.otlp.traces.endpoint", "https://example.com:4317/");
109+
110+
try (OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService()) {
111+
112+
ConfigProperties configProperties = openTelemetrySdkService.getConfigProperties();
113+
assertThat(configProperties.getString("otel.exporter.otlp.endpoint")).isNull();
114+
assertThat(configProperties.getString("otel.exporter.otlp.traces.endpoint"))
115+
.isEqualTo("https://example.com:4317/");
116+
assertThat(configProperties.getString("otel.traces.exporter")).isEqualTo("otlp");
117+
assertThat(configProperties.getString("otel.metrics.exporter")).isEqualTo("none");
118+
assertThat(configProperties.getString("otel.logs.exporter")).isEqualTo("none");
119+
120+
} finally {
121+
System.clearProperty("otel.exporter.otlp.endpoint");
122+
System.clearProperty("otel.exporter.otlp.traces.endpoint");
123+
System.clearProperty("otel.exporter.otlp.traces.protocol");
29124
}
30125
}
31126

32-
void testConfiguration(String expectedServiceName) {
33-
// OpenTelemetrySdkService openTelemetrySdkService = new OpenTelemetrySdkService();
34-
// openTelemetrySdkService.initialize();
35-
// try {
36-
// Resource resource =
37-
// openTelemetrySdkService.autoConfiguredOpenTelemetrySdk.getResource();
38-
// assertThat(resource.getAttribute(ResourceAttributes.SERVICE_NAME))
39-
// .isEqualTo(expectedServiceName);
40-
// } finally {
41-
// openTelemetrySdkService.dispose();
42-
// GlobalOpenTelemetry.resetForTest();
43-
// GlobalEventEmitterProvider.resetForTest();
44-
// }
127+
@AfterAll
128+
static void afterAll() {
129+
System.clearProperty("otel.exporter.otlp.endpoint");
130+
System.clearProperty("otel.exporter.otlp.traces.endpoint");
131+
System.clearProperty("otel.exporter.otlp.traces.protocol");
132+
System.clearProperty("otel.resource.attributes");
133+
System.clearProperty("otel.service.name");
134+
System.clearProperty("otel.traces.exporter");
45135
}
46136
}

0 commit comments

Comments
 (0)