Skip to content

Commit c5f677e

Browse files
authored
Spring Boot Starter service-name is constant (#5359)
* Spring Boot Starter service-name is constant Pattern-based resource configuration * Add ResourceProvider beans for spring with ConfigProperties
1 parent b85696b commit c5f677e

File tree

12 files changed

+469
-2
lines changed

12 files changed

+469
-2
lines changed

instrumentation/spring/spring-boot-autoconfigure/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,26 @@ If an exporter is present in the classpath during runtime and a spring bean of t
392392

393393
<!-- Slf4j Log Correlation otel.springboot.loggers.slf4j.enabled true org.slf4j.MDC -->
394394

395+
##### Resource Properties
396+
397+
| Feature | Property | Default Value |
398+
|----------|--------------------------------------------------|------------------------|
399+
| Resource | otel.springboot.resource.enabled | `true` |
400+
| | otel.springboot.resource.attributes.service.name | `unknown_service:java` |
401+
| | otel.springboot.resource.attributes | `empty map` |
402+
403+
`unknown_service:java` will be used as the service-name if no value has been specified to the
404+
property `spring.application.name` or `otel.springboot.resource.attributes.service.name` (which has
405+
the highest priority)
406+
407+
`otel.springboot.resource.attributes` supports a pattern-based resource configuration in the
408+
application.properties like this:
409+
410+
```
411+
otel.springboot.resource.attributes.environment=dev
412+
otel.springboot.resource.attributes.xyz=foo
413+
```
414+
395415
##### Exporter Properties
396416

397417
| Feature | Property | Default Value |

instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts

+4
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ dependencies {
2222
compileOnly("org.springframework.boot:spring-boot-starter-web:${versions["org.springframework.boot"]}")
2323
compileOnly("org.springframework.boot:spring-boot-starter-webflux:${versions["org.springframework.boot"]}")
2424

25+
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
2526
compileOnly("io.opentelemetry:opentelemetry-extension-annotations")
2627
compileOnly("io.opentelemetry:opentelemetry-extension-trace-propagators")
2728
compileOnly("io.opentelemetry:opentelemetry-extension-aws")
29+
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-resources")
2830
compileOnly("io.opentelemetry:opentelemetry-exporter-logging")
2931
compileOnly("io.opentelemetry:opentelemetry-exporter-jaeger")
3032
compileOnly("io.opentelemetry:opentelemetry-exporter-otlp")
@@ -40,6 +42,8 @@ dependencies {
4042
testImplementation(project(":testing-common"))
4143
testImplementation("io.opentelemetry:opentelemetry-sdk")
4244
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
45+
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-resources")
46+
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
4347
testImplementation("io.opentelemetry:opentelemetry-extension-annotations")
4448
testImplementation("io.opentelemetry:opentelemetry-extension-trace-propagators")
4549
testImplementation("io.opentelemetry:opentelemetry-extension-aws")

instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
import io.opentelemetry.api.OpenTelemetry;
99
import io.opentelemetry.api.trace.TracerProvider;
1010
import io.opentelemetry.context.propagation.ContextPropagators;
11+
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringResourceConfigProperties;
1112
import io.opentelemetry.sdk.OpenTelemetrySdk;
13+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
14+
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
15+
import io.opentelemetry.sdk.resources.Resource;
1216
import io.opentelemetry.sdk.trace.SdkTracerProvider;
1317
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
1418
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
@@ -21,6 +25,8 @@
2125
import org.springframework.boot.context.properties.EnableConfigurationProperties;
2226
import org.springframework.context.annotation.Bean;
2327
import org.springframework.context.annotation.Configuration;
28+
import org.springframework.core.env.Environment;
29+
import org.springframework.expression.spel.standard.SpelExpressionParser;
2430

2531
/**
2632
* Create {@link io.opentelemetry.api.trace.Tracer} bean if bean is missing.
@@ -41,18 +47,33 @@ public static class OpenTelemetryBeanConfig {
4147
@ConditionalOnMissingBean
4248
public SdkTracerProvider sdkTracerProvider(
4349
SamplerProperties samplerProperties,
44-
ObjectProvider<List<SpanExporter>> spanExportersProvider) {
50+
ObjectProvider<List<SpanExporter>> spanExportersProvider,
51+
Resource otelResource) {
4552
SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder();
4653

4754
spanExportersProvider.getIfAvailable(Collections::emptyList).stream()
4855
.map(spanExporter -> BatchSpanProcessor.builder(spanExporter).build())
4956
.forEach(tracerProviderBuilder::addSpanProcessor);
5057

5158
return tracerProviderBuilder
59+
.setResource(otelResource)
5260
.setSampler(Sampler.traceIdRatioBased(samplerProperties.getProbability()))
5361
.build();
5462
}
5563

64+
@Bean
65+
@ConditionalOnMissingBean
66+
public Resource otelResource(
67+
Environment env, ObjectProvider<List<ResourceProvider>> resourceProviders) {
68+
ConfigProperties config = new SpringResourceConfigProperties(env, new SpelExpressionParser());
69+
Resource resource = Resource.getDefault();
70+
for (ResourceProvider resourceProvider :
71+
resourceProviders.getIfAvailable(Collections::emptyList)) {
72+
resource = resource.merge(resourceProvider.createResource(config));
73+
}
74+
return resource;
75+
}
76+
5677
@Bean
5778
public OpenTelemetry openTelemetry(
5879
ObjectProvider<ContextPropagators> propagatorsProvider, SdkTracerProvider tracerProvider) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
7+
8+
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
9+
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
10+
import io.opentelemetry.sdk.extension.resources.ContainerResource;
11+
import io.opentelemetry.sdk.extension.resources.ContainerResourceProvider;
12+
import io.opentelemetry.sdk.extension.resources.HostResource;
13+
import io.opentelemetry.sdk.extension.resources.HostResourceProvider;
14+
import io.opentelemetry.sdk.extension.resources.OsResource;
15+
import io.opentelemetry.sdk.extension.resources.OsResourceProvider;
16+
import io.opentelemetry.sdk.extension.resources.ProcessResource;
17+
import io.opentelemetry.sdk.extension.resources.ProcessResourceProvider;
18+
import io.opentelemetry.sdk.extension.resources.ProcessRuntimeResource;
19+
import io.opentelemetry.sdk.extension.resources.ProcessRuntimeResourceProvider;
20+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
23+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
27+
@Configuration
28+
@EnableConfigurationProperties(OtelResourceProperties.class)
29+
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
30+
@ConditionalOnProperty(prefix = "otel.springboot.resource", name = "enabled", matchIfMissing = true)
31+
public class OtelResourceAutoConfiguration {
32+
33+
@Bean
34+
public ResourceProvider otelResourceProvider(OtelResourceProperties otelResourceProperties) {
35+
return new SpringResourceProvider(otelResourceProperties);
36+
}
37+
38+
@Bean
39+
@ConditionalOnClass(OsResource.class)
40+
public ResourceProvider otelOsResourceProvider() {
41+
return new OsResourceProvider();
42+
}
43+
44+
@Bean
45+
@ConditionalOnClass(ProcessResource.class)
46+
public ResourceProvider otelProcessResourceProvider() {
47+
return new ProcessResourceProvider();
48+
}
49+
50+
@Bean
51+
@ConditionalOnClass(ProcessRuntimeResource.class)
52+
public ResourceProvider otelProcessRuntimeResourceProvider() {
53+
return new ProcessRuntimeResourceProvider();
54+
}
55+
56+
@Bean
57+
@ConditionalOnClass(HostResource.class)
58+
public ResourceProvider otelHostResourceProvider() {
59+
return new HostResourceProvider();
60+
}
61+
62+
@Bean
63+
@ConditionalOnClass(ContainerResource.class)
64+
public ResourceProvider otelContainerResourceProvider() {
65+
return new ContainerResourceProvider();
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
7+
8+
import java.util.Collections;
9+
import java.util.Map;
10+
import org.springframework.boot.context.properties.ConfigurationProperties;
11+
12+
@ConfigurationProperties(prefix = "otel.springboot.resource")
13+
public class OtelResourceProperties {
14+
private Map<String, String> attributes = Collections.emptyMap();
15+
16+
public Map<String, String> getAttributes() {
17+
return attributes;
18+
}
19+
20+
public void setAttributes(Map<String, String> attributes) {
21+
this.attributes = attributes;
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
7+
8+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
9+
import java.time.Duration;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.Objects;
13+
import javax.annotation.Nullable;
14+
import org.springframework.core.env.Environment;
15+
import org.springframework.expression.ExpressionParser;
16+
17+
public class SpringResourceConfigProperties implements ConfigProperties {
18+
private final Environment environment;
19+
20+
private final ExpressionParser parser;
21+
22+
public SpringResourceConfigProperties(Environment environment, ExpressionParser parser) {
23+
this.environment = environment;
24+
this.parser = parser;
25+
}
26+
27+
@Nullable
28+
@Override
29+
public String getString(String name) {
30+
return environment.getProperty(name, String.class);
31+
}
32+
33+
@Nullable
34+
@Override
35+
public Boolean getBoolean(String name) {
36+
return environment.getProperty(name, Boolean.class);
37+
}
38+
39+
@Nullable
40+
@Override
41+
public Integer getInt(String name) {
42+
return environment.getProperty(name, Integer.class);
43+
}
44+
45+
@Nullable
46+
@Override
47+
public Long getLong(String name) {
48+
return environment.getProperty(name, Long.class);
49+
}
50+
51+
@Nullable
52+
@Override
53+
public Double getDouble(String name) {
54+
return environment.getProperty(name, Double.class);
55+
}
56+
57+
@Nullable
58+
@Override
59+
public Duration getDuration(String name) {
60+
return environment.getProperty(name, Duration.class);
61+
}
62+
63+
@SuppressWarnings("unchecked")
64+
@Override
65+
public List<String> getList(String name) {
66+
return (List<String>) environment.getProperty(name, List.class);
67+
}
68+
69+
@SuppressWarnings("unchecked")
70+
@Override
71+
public Map<String, String> getMap(String name) {
72+
String value = environment.getProperty(name);
73+
return (Map<String, String>) parser.parseExpression(Objects.requireNonNull(value)).getValue();
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
7+
8+
import io.opentelemetry.api.common.Attributes;
9+
import io.opentelemetry.api.common.AttributesBuilder;
10+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
11+
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
12+
import io.opentelemetry.sdk.resources.Resource;
13+
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
14+
import java.util.Map;
15+
16+
public class SpringResourceProvider implements ResourceProvider {
17+
18+
private final OtelResourceProperties otelResourceProperties;
19+
20+
public SpringResourceProvider(OtelResourceProperties otelResourceProperties) {
21+
this.otelResourceProperties = otelResourceProperties;
22+
}
23+
24+
@Override
25+
public Resource createResource(ConfigProperties configProperties) {
26+
String applicationName = configProperties.getString("spring.application.name");
27+
Map<String, String> attributes = otelResourceProperties.getAttributes();
28+
AttributesBuilder attributesBuilder = Attributes.builder();
29+
attributes.forEach(attributesBuilder::put);
30+
return defaultResource(applicationName).merge(Resource.create(attributesBuilder.build()));
31+
}
32+
33+
private static Resource defaultResource(String applicationName) {
34+
if (applicationName == null) {
35+
return Resource.getDefault();
36+
}
37+
return Resource.getDefault()
38+
.merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName)));
39+
}
40+
}

instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfigura
88
io.opentelemetry.instrumentation.spring.autoconfigure.httpclients.resttemplate.RestTemplateAutoConfiguration,\
99
io.opentelemetry.instrumentation.spring.autoconfigure.httpclients.webclient.WebClientAutoConfiguration,\
1010
io.opentelemetry.instrumentation.spring.autoconfigure.webmvc.WebMvcFilterAutoConfiguration,\
11-
io.opentelemetry.instrumentation.spring.autoconfigure.aspects.TraceAspectAutoConfiguration
11+
io.opentelemetry.instrumentation.spring.autoconfigure.aspects.TraceAspectAutoConfiguration,\
12+
io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration

0 commit comments

Comments
 (0)