Skip to content

Commit 8f4e051

Browse files
committed
Polish "Add support for OTel-specific environment variables"
See gh-44394
1 parent bf015bf commit 8f4e051

File tree

5 files changed

+34
-23
lines changed

5 files changed

+34
-23
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesConfigAdapter.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

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

19+
import java.util.Collections;
1920
import java.util.Map;
2021
import java.util.concurrent.TimeUnit;
2122

@@ -27,6 +28,7 @@
2728
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties;
2829
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryResourceAttributes;
2930
import org.springframework.core.env.Environment;
31+
import org.springframework.util.StringUtils;
3032

3133
/**
3234
* Adapter to convert {@link OtlpMetricsProperties} to an {@link OtlpConfig}.
@@ -80,15 +82,16 @@ public Map<String, String> resourceAttributes() {
8082
.asMap();
8183
attributes.computeIfAbsent("service.name", (key) -> getApplicationName());
8284
attributes.computeIfAbsent("service.group", (key) -> getApplicationGroup());
83-
return attributes;
85+
return Collections.unmodifiableMap(attributes);
8486
}
8587

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

9092
private String getApplicationGroup() {
91-
return this.environment.getProperty("spring.application.group");
93+
String applicationGroup = this.environment.getProperty("spring.application.group");
94+
return (StringUtils.hasLength(applicationGroup)) ? applicationGroup : null;
9295
}
9396

9497
@Override

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/opentelemetry/OpenTelemetryAutoConfiguration.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3737
import org.springframework.context.annotation.Bean;
3838
import org.springframework.core.env.Environment;
39+
import org.springframework.util.StringUtils;
3940

4041
/**
4142
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry.
@@ -88,7 +89,8 @@ private String getApplicationName(Environment environment) {
8889
}
8990

9091
private String getApplicationGroup(Environment environment) {
91-
return environment.getProperty("spring.application.group");
92+
String applicationGroup = environment.getProperty("spring.application.group");
93+
return (StringUtils.hasLength(applicationGroup)) ? applicationGroup : null;
9294
}
9395

9496
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/opentelemetry/OpenTelemetryResourceAttributes.java

+12-12
Original file line numberDiff line numberDiff line change
@@ -130,21 +130,21 @@ public static String decode(String value) {
130130
ByteArrayOutputStream bos = new ByteArrayOutputStream(bytes.length);
131131
for (int i = 0; i < bytes.length; i++) {
132132
byte b = bytes[i];
133-
if (b == '%') {
134-
int u = decodeHex(bytes, ++i);
135-
int l = decodeHex(bytes, ++i);
136-
if (u >= 0 && l >= 0) {
137-
bos.write((u << 4) + l);
138-
}
139-
else {
140-
throw new IllegalArgumentException(
141-
"Failed to decode percent-encoded characters at index %d in the value: '%s'"
142-
.formatted(i - 2, value));
143-
}
133+
if (b != '%') {
134+
bos.write(b);
135+
continue;
136+
}
137+
int u = decodeHex(bytes, i + 1);
138+
int l = decodeHex(bytes, i + 2);
139+
if (u >= 0 && l >= 0) {
140+
bos.write((u << 4) + l);
144141
}
145142
else {
146-
bos.write(b);
143+
throw new IllegalArgumentException(
144+
"Failed to decode percent-encoded characters at index %d in the value: '%s'".formatted(i,
145+
value));
147146
}
147+
i += 2;
148148
}
149149
return bos.toString(StandardCharsets.UTF_8);
150150
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/opentelemetry/OpenTelemetryResourceAttributesTests.java

+9-6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import io.opentelemetry.api.internal.PercentEscaper;
2626
import org.assertj.core.api.InstanceOfAssertFactories;
27+
import org.junit.jupiter.api.BeforeAll;
2728
import org.junit.jupiter.api.Test;
2829

2930
import static org.assertj.core.api.Assertions.assertThat;
@@ -36,19 +37,25 @@
3637
*/
3738
class OpenTelemetryResourceAttributesTests {
3839

39-
private static final Random random = new Random();
40+
private static Random random;
4041

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

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

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

48+
@BeforeAll
49+
static void beforeAll() {
50+
long seed = new Random().nextLong();
51+
System.out.println("Seed: " + seed);
52+
random = new Random(seed);
53+
}
54+
4755
@Test
4856
void otelServiceNameShouldTakePrecedenceOverOtelResourceAttributes() {
4957
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "service.name=ignored");
5058
this.environmentVariables.put("OTEL_SERVICE_NAME", "otel-service");
51-
5259
OpenTelemetryResourceAttributes attributes = getAttributes();
5360
assertThat(attributes.asMap()).hasSize(1).containsEntry("service.name", "otel-service");
5461
}
@@ -57,7 +64,6 @@ void otelServiceNameShouldTakePrecedenceOverOtelResourceAttributes() {
5764
void otelServiceNameWhenEmptyShouldTakePrecedenceOverOtelResourceAttributes() {
5865
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "service.name=ignored");
5966
this.environmentVariables.put("OTEL_SERVICE_NAME", "");
60-
6167
OpenTelemetryResourceAttributes attributes = getAttributes();
6268
assertThat(attributes.asMap()).hasSize(1).containsEntry("service.name", "");
6369
}
@@ -66,7 +72,6 @@ void otelServiceNameWhenEmptyShouldTakePrecedenceOverOtelResourceAttributes() {
6672
void otelResourceAttributesShouldBeUsed() {
6773
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES",
6874
", ,,key1=value1,key2= value2, key3=value3,key4=,=value5,key6,=,key7=spring+boot,key8=ś");
69-
7075
OpenTelemetryResourceAttributes attributes = getAttributes();
7176
assertThat(attributes.asMap()).hasSize(6)
7277
.containsEntry("key1", "value1")
@@ -83,7 +88,6 @@ void resourceAttributesShouldBeMergedWithEnvironmentVariables() {
8388
this.resourceAttributes.put("key2", "");
8489
this.environmentVariables.put("OTEL_SERVICE_NAME", "custom-service");
8590
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "key1=value1,key2=value2");
86-
8791
OpenTelemetryResourceAttributes attributes = getAttributes();
8892
assertThat(attributes.asMap()).hasSize(4)
8993
.containsEntry("service.name", "custom-service")
@@ -99,7 +103,6 @@ void resourceAttributesWithNullKeyOrValueShouldBeIgnored() {
99103
this.resourceAttributes.put(null, "value");
100104
this.environmentVariables.put("OTEL_SERVICE_NAME", "custom-service");
101105
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "key1=value1,key2=value2");
102-
103106
OpenTelemetryResourceAttributes attributes = getAttributes();
104107
assertThat(attributes.asMap()).hasSize(3)
105108
.containsEntry("service.name", "custom-service")

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/observability.adoc

+5-2
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,18 @@ Spring Boot's actuator module includes basic support for OpenTelemetry.
9595

9696
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.
9797
Additionally, it provides a javadoc:io.opentelemetry.sdk.resources.Resource[] bean.
98-
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.
98+
The attributes of the auto-configured javadoc:io.opentelemetry.sdk.resources.Resource[] can be configured via the configprop:management.opentelemetry.resource-attributes[] configuration property.
99+
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.
99100

100101

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

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

106-
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**.
107+
NOTE: The `OTEL_RESOURCE_ATTRIBUTES` environment variable consist of a list of key-value pairs.
108+
For example: `key1=value1,key2=value2,key3=spring%20boot`.
109+
All attribute values are treated as strings, and any characters outside the baggage-octet range must be **percent-encoded**.
107110

108111

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

0 commit comments

Comments
 (0)