Merge pull request #44499 from thecooldrop

* pr/44499:
  Polish "Add support for OpenTelemetry's service.namespace"
  Add support for OpenTelemetry's service.namespace

Closes gh-44499
This commit is contained in:
Moritz Halbritter 2025-03-06 10:01:03 +01:00
commit fef5bb5f85
3 changed files with 74 additions and 9 deletions

View File

@ -86,7 +86,7 @@ public final class OpenTelemetryResourceAttributes {
* <p>
* Additionally, {@code spring.application.name} or {@code unknown_service} will be
* used as the default for {@code service.name}, and {@code spring.application.group}
* will serve as the default for {@code service.group}.
* will serve as the default for {@code service.group} and {@code service.namespace}.
* @param consumer the {@link BiConsumer} to apply
*/
public void applyTo(BiConsumer<String, String> consumer) {
@ -97,8 +97,9 @@ public final class OpenTelemetryResourceAttributes {
attributes.put(name, value);
}
});
attributes.computeIfAbsent("service.name", (k) -> getApplicationName());
attributes.computeIfAbsent("service.group", (k) -> getApplicationGroup());
attributes.computeIfAbsent("service.name", (key) -> getApplicationName());
attributes.computeIfAbsent("service.group", (key) -> getApplicationGroup());
attributes.computeIfAbsent("service.namespace", (key) -> getServiceNamespace());
attributes.forEach(consumer);
}
@ -106,11 +107,21 @@ public final class OpenTelemetryResourceAttributes {
return this.environment.getProperty("spring.application.name", DEFAULT_SERVICE_NAME);
}
/**
* Returns the application group.
* @return the application group
* @deprecated since 3.5.0 for removal in 3.7.0
*/
@Deprecated(since = "3.5.0", forRemoval = true)
private String getApplicationGroup() {
String applicationGroup = this.environment.getProperty("spring.application.group");
return (StringUtils.hasLength(applicationGroup)) ? applicationGroup : null;
}
private String getServiceNamespace() {
return this.environment.getProperty("spring.application.group");
}
/**
* Parses resource attributes from the {@link System#getenv()}. This method fetches
* attributes defined in the {@code OTEL_RESOURCE_ATTRIBUTES} and

View File

@ -106,6 +106,23 @@ class OpenTelemetryAutoConfigurationTests {
});
}
@Test
void shouldApplyServiceNamespaceIfApplicationGroupIsSet() {
this.runner.withPropertyValues("spring.application.group=my-group").run((context) -> {
Resource resource = context.getBean(Resource.class);
assertThat(resource.getAttributes().asMap()).containsEntry(AttributeKey.stringKey("service.namespace"),
"my-group");
});
}
@Test
void shouldNotApplyServiceNamespaceIfApplicationGroupIsNotSet() {
this.runner.run(((context) -> {
Resource resource = context.getBean(Resource.class);
assertThat(resource.getAttributes().asMap()).doesNotContainKey(AttributeKey.stringKey("service.namespace"));
}));
}
@Test
void shouldFallbackToDefaultApplicationNameIfSpringApplicationNameIsNotSet() {
this.runner.run((context) -> {
@ -156,7 +173,7 @@ class OpenTelemetryAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
private static final class UserConfiguration {
static class UserConfiguration {
@Bean
OpenTelemetry customOpenTelemetry() {

View File

@ -156,9 +156,10 @@ class OpenTelemetryResourceAttributesTests {
@Test
void springApplicationGroupNameShouldBeUsedAsDefaultServiceGroup() {
this.environment.setProperty("spring.application.group", "spring-boot");
assertThat(getAttributes()).hasSize(2)
assertThat(getAttributes()).hasSize(3)
.containsEntry("service.name", "unknown_service")
.containsEntry("service.group", "spring-boot");
.containsEntry("service.group", "spring-boot")
.containsEntry("service.namespace", "spring-boot");
}
@Test
@ -167,6 +168,11 @@ class OpenTelemetryResourceAttributesTests {
assertThat(getAttributes()).hasSize(1).containsEntry("service.name", "spring-boot-app");
}
@Test
void serviceNamespaceShouldNotBePresentByDefault() {
assertThat(getAttributes()).hasSize(1).doesNotContainKey("service.namespace");
}
@Test
void resourceAttributesShouldTakePrecedenceOverSpringApplicationName() {
this.resourceAttributes.put("service.name", "spring-boot");
@ -192,18 +198,49 @@ class OpenTelemetryResourceAttributesTests {
void resourceAttributesShouldTakePrecedenceOverSpringApplicationGroupName() {
this.resourceAttributes.put("service.group", "spring-boot-app");
this.environment.setProperty("spring.application.group", "spring-boot");
assertThat(getAttributes()).hasSize(2)
assertThat(getAttributes()).hasSize(3)
.containsEntry("service.name", "unknown_service")
.containsEntry("service.group", "spring-boot-app");
}
@Test
void resourceAttributesShouldTakePrecedenceOverApplicationGroupNameForPopulatingServiceNamespace() {
this.resourceAttributes.put("service.namespace", "spring-boot-app");
this.environment.setProperty("spring.application.group", "overriden");
assertThat(getAttributes()).hasSize(3)
.containsEntry("service.name", "unknown_service")
.containsEntry("service.group", "overriden")
.containsEntry("service.namespace", "spring-boot-app");
}
@Test
void otelResourceAttributesShouldTakePrecedenceOverSpringApplicationGroupName() {
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "service.group=spring-boot");
this.environment.setProperty("spring.application.group", "spring-boot-app");
assertThat(getAttributes()).hasSize(2)
assertThat(getAttributes()).hasSize(3)
.containsEntry("service.name", "unknown_service")
.containsEntry("service.group", "spring-boot");
.containsEntry("service.group", "spring-boot")
.containsEntry("service.namespace", "spring-boot-app");
}
@Test
void otelResourceAttributesShouldTakePrecedenceOverSpringApplicationGroupNameForServiceNamespace() {
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "service.namespace=spring-boot");
this.environment.setProperty("spring.application.group", "overriden");
assertThat(getAttributes()).hasSize(3)
.containsEntry("service.group", "overriden")
.containsEntry("service.namespace", "spring-boot");
}
@Test
void shouldUseServiceGroupForServiceNamespaceIfServiceGroupIsSet() {
this.environment.setProperty("spring.application.group", "alpha");
assertThat(getAttributes()).containsEntry("service.namespace", "alpha");
}
@Test
void shouldNotSetServiceNamespaceIfServiceGroupIsNotSet() {
assertThat(getAttributes()).doesNotContainKey("service.namespace");
}
private Map<String, String> getAttributes() {