Skip to content

Commit 362cfb4

Browse files
committed
Merge pull request spring-projects#44494 from nosan
* pr/44494: Polish "Refine the handling of OpenTelemetry resource attributes" Refine the handling of OpenTelemetry resource attributes Closes spring-projectsgh-44494
2 parents 83f678a + 272939e commit 362cfb4

File tree

4 files changed

+147
-102
lines changed

4 files changed

+147
-102
lines changed

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

+5-21
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp;
1818

1919
import java.util.Collections;
20+
import java.util.LinkedHashMap;
2021
import java.util.Map;
2122
import java.util.concurrent.TimeUnit;
2223

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

3333
/**
3434
* Adapter to convert {@link OtlpMetricsProperties} to an {@link OtlpConfig}.
@@ -40,11 +40,6 @@
4040
class OtlpMetricsPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<OtlpMetricsProperties>
4141
implements OtlpConfig {
4242

43-
/**
44-
* Default value for application name if {@code spring.application.name} is not set.
45-
*/
46-
private static final String DEFAULT_APPLICATION_NAME = "unknown_service";
47-
4843
private final OpenTelemetryProperties openTelemetryProperties;
4944

5045
private final OtlpMetricsConnectionDetails connectionDetails;
@@ -77,21 +72,10 @@ public AggregationTemporality aggregationTemporality() {
7772

7873
@Override
7974
public Map<String, String> resourceAttributes() {
80-
Map<String, String> attributes = new OpenTelemetryResourceAttributes(
81-
this.openTelemetryProperties.getResourceAttributes())
82-
.asMap();
83-
attributes.computeIfAbsent("service.name", (key) -> getApplicationName());
84-
attributes.computeIfAbsent("service.group", (key) -> getApplicationGroup());
85-
return Collections.unmodifiableMap(attributes);
86-
}
87-
88-
private String getApplicationName() {
89-
return this.environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
90-
}
91-
92-
private String getApplicationGroup() {
93-
String applicationGroup = this.environment.getProperty("spring.application.group");
94-
return (StringUtils.hasLength(applicationGroup)) ? applicationGroup : null;
75+
Map<String, String> resourceAttributes = new LinkedHashMap<>();
76+
new OpenTelemetryResourceAttributes(this.environment, this.openTelemetryProperties.getResourceAttributes())
77+
.applyTo(resourceAttributes::put);
78+
return Collections.unmodifiableMap(resourceAttributes);
9579
}
9680

9781
@Override

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

+1-22
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.opentelemetry;
1818

19-
import java.util.Map;
20-
2119
import io.opentelemetry.api.OpenTelemetry;
2220
import io.opentelemetry.context.propagation.ContextPropagators;
2321
import io.opentelemetry.sdk.OpenTelemetrySdk;
@@ -36,7 +34,6 @@
3634
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3735
import org.springframework.context.annotation.Bean;
3836
import org.springframework.core.env.Environment;
39-
import org.springframework.util.StringUtils;
4037

4138
/**
4239
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry.
@@ -49,11 +46,6 @@
4946
@EnableConfigurationProperties(OpenTelemetryProperties.class)
5047
public class OpenTelemetryAutoConfiguration {
5148

52-
/**
53-
* Default value for application name if {@code spring.application.name} is not set.
54-
*/
55-
private static final String DEFAULT_APPLICATION_NAME = "unknown_service";
56-
5749
@Bean
5850
@ConditionalOnMissingBean(OpenTelemetry.class)
5951
OpenTelemetrySdk openTelemetry(ObjectProvider<SdkTracerProvider> tracerProvider,
@@ -76,21 +68,8 @@ Resource openTelemetryResource(Environment environment, OpenTelemetryProperties
7668

7769
private Resource toResource(Environment environment, OpenTelemetryProperties properties) {
7870
ResourceBuilder builder = Resource.builder();
79-
Map<String, String> attributes = new OpenTelemetryResourceAttributes(properties.getResourceAttributes())
80-
.asMap();
81-
attributes.computeIfAbsent("service.name", (key) -> getApplicationName(environment));
82-
attributes.computeIfAbsent("service.group", (key) -> getApplicationGroup(environment));
83-
attributes.forEach(builder::put);
71+
new OpenTelemetryResourceAttributes(environment, properties.getResourceAttributes()).applyTo(builder::put);
8472
return builder.build();
8573
}
8674

87-
private String getApplicationName(Environment environment) {
88-
return environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
89-
}
90-
91-
private String getApplicationGroup(Environment environment) {
92-
String applicationGroup = environment.getProperty("spring.application.group");
93-
return (StringUtils.hasLength(applicationGroup)) ? applicationGroup : null;
94-
}
95-
9675
}

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

+44-16
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,19 @@
2121
import java.util.Collections;
2222
import java.util.LinkedHashMap;
2323
import java.util.Map;
24+
import java.util.function.BiConsumer;
2425
import java.util.function.Function;
2526

27+
import org.springframework.core.env.Environment;
28+
import org.springframework.util.Assert;
2629
import org.springframework.util.StringUtils;
2730

2831
/**
29-
* OpenTelemetryResourceAttributes retrieves information from the
32+
* {@link OpenTelemetryResourceAttributes} retrieves information from the
3033
* {@code OTEL_RESOURCE_ATTRIBUTES} and {@code OTEL_SERVICE_NAME} environment variables
31-
* and merges it with the resource attributes provided by the user.
32-
* <p>
33-
* <b>User-provided resource attributes take precedence.</b>
34+
* and merges it with the resource attributes provided by the user. User-provided resource
35+
* attributes take precedence. Additionally, {@code spring.application.*} related
36+
* properties can be applied as defaults.
3437
* <p>
3538
* <a href= "https://opentelemetry.io/docs/specs/otel/resource/sdk/">OpenTelemetry
3639
* Resource Specification</a>
@@ -40,47 +43,72 @@
4043
*/
4144
public final class OpenTelemetryResourceAttributes {
4245

46+
/**
47+
* Default value for service name if {@code service.name} is not set.
48+
*/
49+
private static final String DEFAULT_SERVICE_NAME = "unknown_service";
50+
51+
private final Environment environment;
52+
4353
private final Map<String, String> resourceAttributes;
4454

4555
private final Function<String, String> getEnv;
4656

4757
/**
4858
* Creates a new instance of {@link OpenTelemetryResourceAttributes}.
59+
* @param environment the environment
4960
* @param resourceAttributes user provided resource attributes to be used
5061
*/
51-
public OpenTelemetryResourceAttributes(Map<String, String> resourceAttributes) {
52-
this(resourceAttributes, null);
62+
public OpenTelemetryResourceAttributes(Environment environment, Map<String, String> resourceAttributes) {
63+
this(environment, resourceAttributes, null);
5364
}
5465

5566
/**
5667
* Creates a new {@link OpenTelemetryResourceAttributes} instance.
68+
* @param environment the environment
5769
* @param resourceAttributes user provided resource attributes to be used
5870
* @param getEnv a function to retrieve environment variables by name
5971
*/
60-
OpenTelemetryResourceAttributes(Map<String, String> resourceAttributes, Function<String, String> getEnv) {
72+
OpenTelemetryResourceAttributes(Environment environment, Map<String, String> resourceAttributes,
73+
Function<String, String> getEnv) {
74+
Assert.notNull(environment, "'environment' must not be null");
75+
this.environment = environment;
6176
this.resourceAttributes = (resourceAttributes != null) ? resourceAttributes : Collections.emptyMap();
6277
this.getEnv = (getEnv != null) ? getEnv : System::getenv;
6378
}
6479

6580
/**
66-
* Returns resource attributes by combining attributes from environment variables and
67-
* user-defined resource attributes. The final resource contains all attributes from
68-
* both sources.
81+
* Applies resource attributes to the provided BiConsumer after being combined from
82+
* environment variables and user-defined resource attributes.
6983
* <p>
7084
* If a key exists in both environment variables and user-defined resources, the value
7185
* from the user-defined resource takes precedence, even if it is empty.
7286
* <p>
73-
* <b>Null keys and values are ignored.</b>
74-
* @return the resource attributes
87+
* Additionally, {@code spring.application.name} or {@code unknown_service} will be
88+
* used as the default for {@code service.name}, and {@code spring.application.group}
89+
* will serve as the default for {@code service.group}.
90+
* @param consumer the {@link BiConsumer} to apply
7591
*/
76-
public Map<String, String> asMap() {
92+
public void applyTo(BiConsumer<String, String> consumer) {
93+
Assert.notNull(consumer, "'consumer' must not be null");
7794
Map<String, String> attributes = getResourceAttributesFromEnv();
7895
this.resourceAttributes.forEach((name, value) -> {
79-
if (name != null && value != null) {
96+
if (StringUtils.hasLength(name) && value != null) {
8097
attributes.put(name, value);
8198
}
8299
});
83-
return attributes;
100+
attributes.computeIfAbsent("service.name", (k) -> getApplicationName());
101+
attributes.computeIfAbsent("service.group", (k) -> getApplicationGroup());
102+
attributes.forEach(consumer);
103+
}
104+
105+
private String getApplicationName() {
106+
return this.environment.getProperty("spring.application.name", DEFAULT_SERVICE_NAME);
107+
}
108+
109+
private String getApplicationGroup() {
110+
String applicationGroup = this.environment.getProperty("spring.application.group");
111+
return (StringUtils.hasLength(applicationGroup)) ? applicationGroup : null;
84112
}
85113

86114
/**
@@ -122,7 +150,7 @@ private String getEnv(String name) {
122150
* @param value value to decode
123151
* @return the decoded string
124152
*/
125-
public static String decode(String value) {
153+
private static String decode(String value) {
126154
if (value.indexOf('%') < 0) {
127155
return value;
128156
}

0 commit comments

Comments
 (0)