Skip to content

Commit 92998b6

Browse files
[Maven-Extension] Use Auto Configure Otel SDK Builder (#132)
* Use Auto Configuration Otel SDK Builder * Cleanup * Cleanup * set default otel exporter to "none" rather than "otlp" if no otlp endpoint is defined * Bump dependency * Cleanup * Cleanup * fix bug, use uppercase for env vars * Rely on the OkHttp impl of gRPC bundled with otel SDK 1.9 * Rollback renaming to ease PR review * Rollback change to ease PR review * formatting * Simplify configuration logic: default `-Dotel.traces.exporter` / `OTEL_TRACES_EXPORTER` to `none * spotless glitch * Code cleanup
1 parent 42f5f33 commit 92998b6

File tree

5 files changed

+95
-155
lines changed

5 files changed

+95
-155
lines changed

maven-extension/README.md

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ Add the Maven OpenTelemetry Extension to `${maven.home}/lib/ext` or to the class
1818
```
1919
mvn dependency:copy -Dartifact=io.opentelemetry.contrib:opentelemetry-maven-extension:1.7.0-alpha
2020
21-
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
21+
export OTEL_TRACES_EXPORTER="otlp"
22+
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel.example.com:4317"
2223
2324
mvn -Dmaven.ext.class.path=target/dependency/opentelemetry-maven-extension-1.7.0-alpha.jar verify
2425
```
@@ -44,25 +45,32 @@ Add the Maven OpenTelemetry Extension in the `pom.xml` file:
4445
```
4546

4647
```
47-
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
48+
export OTEL_TRACES_EXPORTER="otlp"
49+
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel.example.com:4317"
4850
4951
mvn verify
5052
```
5153

5254
## Configuration
5355

56+
❕ The setting `-Dotel.traces.exporter` / `OTEL_TRACES_EXPORTER` MUST be defined for the Maven OpenTelemetry Extension to export traces.
57+
58+
Without this setting, the traces won't be exported and the OpenTelemetry Maven Extension will behave as a NoOp extension. `otlp` is currently the only supported exporter.
59+
5460
The Maven OpenTelemetry Extension supports a subset of the [OpenTelemetry auto configuration environment variables and JVM system properties](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure).
5561

56-
| System property | Environment variable | Description |
57-
|------------------------------|-----------------------------|---------------------------------------------------------------------------|
58-
| otel.exporter.otlp.endpoint | OTEL_EXPORTER_OTLP_ENDPOINT | The OTLP traces and metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. Example `http://localhost:4317`. |
59-
| otel.exporter.otlp.headers | OTEL_EXPORTER_OTLP_HEADERS | Key-value pairs separated by commas to pass as request headers on OTLP trace and metrics requests. |
60-
| otel.exporter.otlp.timeout | OTEL_EXPORTER_OTLP_TIMEOUT | The maximum waiting time, in milliseconds, allowed to send each OTLP trace and metric batch. Default is `10000`. |
61-
| otel.resource.attributes | OTEL_RESOURCE_ATTRIBUTES | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
62-
| otel.instrumentation.maven.mojo.enabled | OTEL_INSTRUMENTATION_MAVEN_MOJO_ENABLED | Whether to create spans for mojo goal executions, `true` or `false`. Can be configured to reduce the number of spans created for large builds. Default value: `true` |
62+
63+
| System property | Environment variable | Default value | Description |
64+
|------------------------------|-----------------------------|-------------------------|---------------------------------------------------------------------------|
65+
| otel.traces.exporter | OTEL_TRACES_EXPORTER | `none` | Select the OpenTelemetry exporter for tracing, the currently only supported values are `none` and `otlp`. `none` makes the instrumentation NoOp |
66+
| otel.exporter.otlp.endpoint | OTEL_EXPORTER_OTLP_ENDPOINT | `http://localhost:4317` | The OTLP traces and metrics endpoint to connect to. Must be a URL with a scheme of either `http` or `https` based on the use of TLS. |
67+
| otel.exporter.otlp.headers | OTEL_EXPORTER_OTLP_HEADERS | | Key-value pairs separated by commas to pass as request headers on OTLP trace and metrics requests. |
68+
| otel.exporter.otlp.timeout | OTEL_EXPORTER_OTLP_TIMEOUT | `10000` | The maximum waiting time, in milliseconds, allowed to send each OTLP trace and metric batch. |
69+
| otel.resource.attributes | OTEL_RESOURCE_ATTRIBUTES | | Specify resource attributes in the following format: key1=val1,key2=val2,key3=val3 |
70+
| otel.instrumentation.maven.mojo.enabled | OTEL_INSTRUMENTATION_MAVEN_MOJO_ENABLED | `true` | Whether to create spans for mojo goal executions, `true` or `false`. Can be configured to reduce the number of spans created for large builds. |
6371

6472

65-
ℹ️ The `service.name` is set by default to `maven`, it can be overwritten specifying resource attributes.
73+
ℹ️ The `service.name` is set to `maven` and the `service.version` to the version of the Maven runtime in use.
6674

6775

6876
## Examples

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

Lines changed: 46 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
import io.opentelemetry.context.propagation.ContextPropagators;
1111
import io.opentelemetry.maven.semconv.MavenOtelSemanticAttributes;
1212
import io.opentelemetry.sdk.OpenTelemetrySdk;
13-
import io.opentelemetry.sdk.autoconfigure.OpenTelemetrySdkAutoConfiguration;
13+
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
14+
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
1415
import io.opentelemetry.sdk.common.CompletableResultCode;
16+
import io.opentelemetry.sdk.resources.Resource;
1517
import io.opentelemetry.sdk.trace.export.SpanExporter;
1618
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
17-
import java.util.Map;
19+
import java.util.Collections;
1820
import java.util.concurrent.TimeUnit;
1921
import org.apache.maven.rtinfo.RuntimeInformation;
2022
import org.codehaus.plexus.component.annotations.Component;
@@ -25,16 +27,7 @@
2527
import org.slf4j.Logger;
2628
import org.slf4j.LoggerFactory;
2729

28-
/**
29-
* Service to configure the {@link OpenTelemetry} instance.
30-
*
31-
* <p>Rely on the OpenTelemetry SDK AutoConfiguration extension. Parameters are passed as system
32-
* properties.
33-
*
34-
* <p>TODO: verify how we could use a composite {@link
35-
* io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties} combining the config passed by JVM
36-
* system properties and environment variables with overrides injected by the Otel Maven Extension
37-
*/
30+
/** Service to configure the {@link OpenTelemetry} instance. */
3831
@Component(role = OpenTelemetrySdkService.class, hint = "opentelemetry-service")
3932
public final class OpenTelemetrySdkService implements Initializable, Disposable {
4033

@@ -89,60 +82,49 @@ public synchronized void dispose() {
8982
@Override
9083
public void initialize() throws InitializationException {
9184
logger.debug("OpenTelemetry: initialize OpenTelemetrySdkService...");
92-
if (StringUtils.isBlank(
93-
OtelUtils.getSystemPropertyOrEnvironmentVariable(
94-
"otel.exporter.otlp.endpoint", "OTEL_EXPORTER_OTLP_ENDPOINT", null))) {
85+
AutoConfiguredOpenTelemetrySdkBuilder autoConfiguredSdkBuilder =
86+
AutoConfiguredOpenTelemetrySdk.builder();
87+
88+
// SDK CONFIGURATION PROPERTIES
89+
autoConfiguredSdkBuilder.addPropertiesSupplier(
90+
() -> {
91+
// Change default of "otel.traces.exporter" from "otlp" to "none"
92+
// The impacts are
93+
// * If no otel exporter settings are passed, then the Maven extension will not export
94+
// rather than exporting on OTLP GRPC to http://localhost:4317
95+
// * If OTEL_EXPORTER_OTLP_ENDPOINT is defined but OTEL_TRACES_EXPORTER is not, then don't
96+
// export
97+
return Collections.singletonMap("otel.traces.exporter", "none");
98+
});
99+
100+
// SDK RESOURCE
101+
// Don't use the `io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider` framework because we
102+
// need to get the `RuntimeInformation` component injected by Plexus
103+
autoConfiguredSdkBuilder.addResourceCustomizer(
104+
(resource, configProperties) ->
105+
Resource.builder()
106+
.putAll(resource)
107+
.put(
108+
ResourceAttributes.SERVICE_NAME, MavenOtelSemanticAttributes.SERVICE_NAME_VALUE)
109+
.put(ResourceAttributes.SERVICE_VERSION, runtimeInformation.getMavenVersion())
110+
.build());
111+
112+
// BUILD SDK
113+
AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk =
114+
autoConfiguredSdkBuilder.build();
115+
if (logger.isDebugEnabled()) {
95116
logger.debug(
96-
"OpenTelemetry: No -Dotel.exporter.otlp.endpoint property or OTEL_EXPORTER_OTLP_ENDPOINT "
97-
+ "environment variable found, use a NOOP OpenTelemetry SDK");
98-
} else {
99-
{
100-
// Don't use a {@code io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider} to inject
101-
// Maven runtime attributes due to a classloading issue when loading the Maven OpenTelemetry
102-
// extension as a pom.xml {@code <extension>}.
103-
String initialCommaSeparatedAttributes =
104-
OtelUtils.getSystemPropertyOrEnvironmentVariable(
105-
"otel.resource.attributes", "OTEL_RESOURCE_ATTRIBUTES", "");
106-
Map<String, String> attributes =
107-
OtelUtils.getCommaSeparatedMap(initialCommaSeparatedAttributes);
108-
109-
// service.name
110-
String serviceName =
111-
OtelUtils.getSystemPropertyOrEnvironmentVariable(
112-
"otel.service.name", "OTEL_SERVICE_NAME", null);
113-
114-
if (!attributes.containsKey(ResourceAttributes.SERVICE_NAME.getKey())
115-
&& StringUtils.isBlank(serviceName)) {
116-
// service.name is not defined in passed configuration, we define it
117-
attributes.put(
118-
ResourceAttributes.SERVICE_NAME.getKey(),
119-
MavenOtelSemanticAttributes.ServiceNameValues.SERVICE_NAME_VALUE);
120-
}
121-
122-
// service.version
123-
final String mavenVersion = this.runtimeInformation.getMavenVersion();
124-
if (!attributes.containsKey(ResourceAttributes.SERVICE_VERSION.getKey())) {
125-
attributes.put(ResourceAttributes.SERVICE_VERSION.getKey(), mavenVersion);
126-
}
127-
128-
String newCommaSeparatedAttributes = OtelUtils.getCommaSeparatedString(attributes);
129-
logger.debug(
130-
"OpenTelemetry: Initial resource attributes: {}", initialCommaSeparatedAttributes);
131-
logger.debug("OpenTelemetry: Use resource attributes: {}", newCommaSeparatedAttributes);
132-
System.setProperty("otel.resource.attributes", newCommaSeparatedAttributes);
133-
}
134-
135-
this.openTelemetrySdk = OpenTelemetrySdkAutoConfiguration.initialize(false);
136-
this.openTelemetry = this.openTelemetrySdk;
117+
"OpenTelemetry: OpenTelemetry SDK initialized with "
118+
+ OtelUtils.prettyPrintSdkConfiguration(autoConfiguredOpenTelemetrySdk));
137119
}
138-
139-
String mojosInstrumentationEnabledAsString =
140-
System.getProperty(
141-
"otel.instrumentation.maven.mojo.enabled",
142-
System.getenv("OTEL_INSTRUMENTATION_MAVEN_MOJO_ENABLED"));
143-
this.mojosInstrumentationEnabled =
144-
Boolean.parseBoolean(
145-
StringUtils.defaultIfBlank(mojosInstrumentationEnabledAsString, "true"));
120+
this.openTelemetrySdk = autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk();
121+
this.openTelemetry = this.openTelemetrySdk;
122+
123+
Boolean mojoSpansEnabled =
124+
autoConfiguredOpenTelemetrySdk
125+
.getConfig()
126+
.getBoolean("otel.instrumentation.maven.mojo.enabled");
127+
this.mojosInstrumentationEnabled = mojoSpansEnabled == null ? true : mojoSpansEnabled;
146128

147129
this.tracer = this.openTelemetry.getTracer("io.opentelemetry.contrib.maven");
148130
}

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

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,64 +5,46 @@
55

66
package io.opentelemetry.maven;
77

8-
import java.util.AbstractMap;
8+
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
9+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
10+
import io.opentelemetry.sdk.resources.Resource;
911
import java.util.Arrays;
10-
import java.util.HashMap;
1112
import java.util.LinkedHashMap;
1213
import java.util.List;
1314
import java.util.Map;
1415
import java.util.stream.Collectors;
15-
import javax.annotation.CheckForNull;
16-
import javax.annotation.Nullable;
1716

1817
final class OtelUtils {
18+
protected static String prettyPrintSdkConfiguration(
19+
AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) {
20+
List<String> configAttributeNames =
21+
Arrays.asList(
22+
"otel.traces.exporter",
23+
"otel.metrics.exporter",
24+
"otel.exporter.otlp.endpoint",
25+
"otel.exporter.otlp.traces.endpoint",
26+
"otel.exporter.otlp.metrics.endpoint",
27+
"otel.exporter.jaeger.endpoint",
28+
"otel.exporter.prometheus.port",
29+
"otel.resource.attributes",
30+
"otel.service.name");
1931

20-
public static String getCommaSeparatedString(Map<String, String> keyValuePairs) {
21-
return keyValuePairs.entrySet().stream()
22-
.map(keyValuePair -> keyValuePair.getKey() + "=" + keyValuePair.getValue())
23-
.collect(Collectors.joining(","));
24-
}
25-
26-
public static Map<String, String> getCommaSeparatedMap(String commaSeparatedKeyValuePairs) {
27-
if (StringUtils.isBlank(commaSeparatedKeyValuePairs)) {
28-
return new HashMap<>();
32+
ConfigProperties sdkConfig = autoConfiguredOpenTelemetrySdk.getConfig();
33+
Map<String, String> configurationAttributes = new LinkedHashMap<>();
34+
for (String attributeName : configAttributeNames) {
35+
final String attributeValue = sdkConfig.getString(attributeName);
36+
if (attributeValue != null) {
37+
configurationAttributes.put(attributeName, attributeValue);
38+
}
2939
}
30-
return filterBlanksAndNulls(commaSeparatedKeyValuePairs.split(",")).stream()
31-
.map(keyValuePair -> filterBlanksAndNulls(keyValuePair.split("=", 2)))
32-
.map(
33-
splitKeyValuePairs -> {
34-
if (splitKeyValuePairs.size() != 2) {
35-
throw new RuntimeException(
36-
"Invalid key-value pair: " + commaSeparatedKeyValuePairs);
37-
}
38-
return new AbstractMap.SimpleImmutableEntry<>(
39-
splitKeyValuePairs.get(0), splitKeyValuePairs.get(1));
40-
})
41-
// If duplicate keys, prioritize later ones similar to duplicate system properties on a
42-
// Java command line.
43-
.collect(
44-
Collectors.toMap(
45-
Map.Entry::getKey, Map.Entry::getValue, (first, next) -> next, LinkedHashMap::new));
46-
}
4740

48-
private static List<String> filterBlanksAndNulls(String[] values) {
49-
return Arrays.stream(values)
50-
.map(String::trim)
51-
.filter(s -> !s.isEmpty())
52-
.collect(Collectors.toList());
53-
}
41+
Resource sdkResource = autoConfiguredOpenTelemetrySdk.getResource();
5442

55-
@CheckForNull
56-
public static String getSystemPropertyOrEnvironmentVariable(
57-
String systemPropertyName, String environmentVariableName, @Nullable String defaultValue) {
58-
String systemProperty = System.getProperty(systemPropertyName);
59-
if (StringUtils.isNotBlank(systemProperty)) {
60-
return systemProperty;
61-
}
62-
String environmentVariable = System.getenv(environmentVariableName);
63-
if (StringUtils.isNotBlank(environmentVariable)) {
64-
return environmentVariable;
65-
}
66-
return defaultValue;
43+
return "Configuration: "
44+
+ configurationAttributes.entrySet().stream()
45+
.map(entry -> entry.getKey() + "=" + entry.getValue())
46+
.collect(Collectors.joining(", "))
47+
+ ", Resource: "
48+
+ sdkResource.getAttributes();
6749
}
6850
}

maven-extension/src/main/java/io/opentelemetry/maven/semconv/MavenOtelSemanticAttributes.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,5 @@ public class MavenOtelSemanticAttributes {
3030
public static final AttributeKey<String> MAVEN_EXECUTION_LIFECYCLE_PHASE =
3131
stringKey("maven.execution.lifecyclePhase");
3232

33-
public static final class ServiceNameValues {
34-
public static final String SERVICE_NAME_VALUE = "maven";
35-
36-
private ServiceNameValues() {}
37-
}
33+
public static final String SERVICE_NAME_VALUE = "maven";
3834
}

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

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)