Skip to content

Commit

Permalink
Polish "Add support for OTel-specific environment variables"
Browse files Browse the repository at this point in the history
  • Loading branch information
mhalbritter committed Feb 28, 2025
1 parent bf015bf commit 8f4e051
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp;

import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;

Expand All @@ -27,6 +28,7 @@
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryResourceAttributes;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;

/**
* Adapter to convert {@link OtlpMetricsProperties} to an {@link OtlpConfig}.
Expand Down Expand Up @@ -80,15 +82,16 @@ public Map<String, String> resourceAttributes() {
.asMap();
attributes.computeIfAbsent("service.name", (key) -> getApplicationName());
attributes.computeIfAbsent("service.group", (key) -> getApplicationGroup());
return attributes;
return Collections.unmodifiableMap(attributes);
}

private String getApplicationName() {
return this.environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
}

private String getApplicationGroup() {
return this.environment.getProperty("spring.application.group");
String applicationGroup = this.environment.getProperty("spring.application.group");
return (StringUtils.hasLength(applicationGroup)) ? applicationGroup : null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;

/**
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry.
Expand Down Expand Up @@ -88,7 +89,8 @@ private String getApplicationName(Environment environment) {
}

private String getApplicationGroup(Environment environment) {
return environment.getProperty("spring.application.group");
String applicationGroup = environment.getProperty("spring.application.group");
return (StringUtils.hasLength(applicationGroup)) ? applicationGroup : null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,21 @@ public static String decode(String value) {
ByteArrayOutputStream bos = new ByteArrayOutputStream(bytes.length);
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
if (b == '%') {
int u = decodeHex(bytes, ++i);
int l = decodeHex(bytes, ++i);
if (u >= 0 && l >= 0) {
bos.write((u << 4) + l);
}
else {
throw new IllegalArgumentException(
"Failed to decode percent-encoded characters at index %d in the value: '%s'"
.formatted(i - 2, value));
}
if (b != '%') {
bos.write(b);
continue;
}
int u = decodeHex(bytes, i + 1);
int l = decodeHex(bytes, i + 2);
if (u >= 0 && l >= 0) {
bos.write((u << 4) + l);
}
else {
bos.write(b);
throw new IllegalArgumentException(
"Failed to decode percent-encoded characters at index %d in the value: '%s'".formatted(i,
value));
}
i += 2;
}
return bos.toString(StandardCharsets.UTF_8);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import io.opentelemetry.api.internal.PercentEscaper;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -36,19 +37,25 @@
*/
class OpenTelemetryResourceAttributesTests {

private static final Random random = new Random();
private static Random random;

private static final PercentEscaper escaper = PercentEscaper.create();

private final Map<String, String> environmentVariables = new LinkedHashMap<>();

private final Map<String, String> resourceAttributes = new LinkedHashMap<>();

@BeforeAll
static void beforeAll() {
long seed = new Random().nextLong();
System.out.println("Seed: " + seed);
random = new Random(seed);
}

@Test
void otelServiceNameShouldTakePrecedenceOverOtelResourceAttributes() {
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "service.name=ignored");
this.environmentVariables.put("OTEL_SERVICE_NAME", "otel-service");

OpenTelemetryResourceAttributes attributes = getAttributes();
assertThat(attributes.asMap()).hasSize(1).containsEntry("service.name", "otel-service");
}
Expand All @@ -57,7 +64,6 @@ void otelServiceNameShouldTakePrecedenceOverOtelResourceAttributes() {
void otelServiceNameWhenEmptyShouldTakePrecedenceOverOtelResourceAttributes() {
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "service.name=ignored");
this.environmentVariables.put("OTEL_SERVICE_NAME", "");

OpenTelemetryResourceAttributes attributes = getAttributes();
assertThat(attributes.asMap()).hasSize(1).containsEntry("service.name", "");
}
Expand All @@ -66,7 +72,6 @@ void otelServiceNameWhenEmptyShouldTakePrecedenceOverOtelResourceAttributes() {
void otelResourceAttributesShouldBeUsed() {
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES",
", ,,key1=value1,key2= value2, key3=value3,key4=,=value5,key6,=,key7=spring+boot,key8=ś");

OpenTelemetryResourceAttributes attributes = getAttributes();
assertThat(attributes.asMap()).hasSize(6)
.containsEntry("key1", "value1")
Expand All @@ -83,7 +88,6 @@ void resourceAttributesShouldBeMergedWithEnvironmentVariables() {
this.resourceAttributes.put("key2", "");
this.environmentVariables.put("OTEL_SERVICE_NAME", "custom-service");
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "key1=value1,key2=value2");

OpenTelemetryResourceAttributes attributes = getAttributes();
assertThat(attributes.asMap()).hasSize(4)
.containsEntry("service.name", "custom-service")
Expand All @@ -99,7 +103,6 @@ void resourceAttributesWithNullKeyOrValueShouldBeIgnored() {
this.resourceAttributes.put(null, "value");
this.environmentVariables.put("OTEL_SERVICE_NAME", "custom-service");
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "key1=value1,key2=value2");

OpenTelemetryResourceAttributes attributes = getAttributes();
assertThat(attributes.asMap()).hasSize(3)
.containsEntry("service.name", "custom-service")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,18 @@ Spring Boot's actuator module includes basic support for OpenTelemetry.

It provides a bean of type javadoc:io.opentelemetry.api.OpenTelemetry[], and if there are beans of type javadoc:io.opentelemetry.sdk.trace.SdkTracerProvider[], javadoc:io.opentelemetry.context.propagation.ContextPropagators[], javadoc:io.opentelemetry.sdk.logs.SdkLoggerProvider[] or javadoc:io.opentelemetry.sdk.metrics.SdkMeterProvider[] in the application context, they automatically get registered.
Additionally, it provides a javadoc:io.opentelemetry.sdk.resources.Resource[] bean.
The attributes of the auto-configured javadoc:io.opentelemetry.sdk.resources.Resource[] can be configured via the configprop:management.opentelemetry.resource-attributes[] configuration property. Auto-configured attributes will be merged with attributes from the `OTEL_RESOURCE_ATTRIBUTES` and `OTEL_SERVICE_NAME` environment variables, with attributes configured through the configuration property taking precedence over those from the environment variables.
The attributes of the auto-configured javadoc:io.opentelemetry.sdk.resources.Resource[] can be configured via the configprop:management.opentelemetry.resource-attributes[] configuration property.
Auto-configured attributes will be merged with attributes from the `OTEL_RESOURCE_ATTRIBUTES` and `OTEL_SERVICE_NAME` environment variables, with attributes configured through the configuration property taking precedence over those from the environment variables.


If you have defined your own javadoc:io.opentelemetry.sdk.resources.Resource[] bean, this will no longer be the case.

NOTE: Spring Boot does not provide auto-configuration for OpenTelemetry metrics or logging.
OpenTelemetry tracing is only auto-configured when used together with xref:actuator/tracing.adoc[Micrometer Tracing].

NOTE: The `OTEL_RESOURCE_ATTRIBUTES` environment variable consist of a list of key-value pairs. For example: `key1=value1,key2=value2,key3=spring%20boot`. All attribute values are treated as strings, and any characters outside the baggage-octet range must be **percent-encoded**.
NOTE: The `OTEL_RESOURCE_ATTRIBUTES` environment variable consist of a list of key-value pairs.
For example: `key1=value1,key2=value2,key3=spring%20boot`.
All attribute values are treated as strings, and any characters outside the baggage-octet range must be **percent-encoded**.


The next sections will provide more details about logging, metrics and traces.
Expand Down

0 comments on commit 8f4e051

Please sign in to comment.