Skip to content

Commit

Permalink
Split OpenTelemetry auto-configuration
Browse files Browse the repository at this point in the history
The OpenTelemetry bean is now configured in the
OpenTelemetryAutoConfiguration. This method also applies
SdkLoggerProvider and SdkMeterProvider.

Additionally, the OpenTelemetry Resource is now a bean. Resource
attributes can now be configured through properties

The resourceAttributes in OtlpProperties have been deprecated in favor
of the new one in OpenTelemetryProperties.

Closes spring-projectsgh-36544
Closes spring-projectsgh-36545
  • Loading branch information
mhalbritter committed Jul 25, 2023
1 parent 346ebbc commit 6d14596
Show file tree
Hide file tree
Showing 15 changed files with 413 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,6 +24,7 @@
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.ConditionalOnEnabledMetricsExport;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
Expand All @@ -36,6 +37,7 @@
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to OTLP.
*
* @author Eddú Meléndez
* @author Moritz Halbritter
* @since 3.0.0
*/
@AutoConfiguration(
Expand All @@ -44,19 +46,23 @@
@ConditionalOnBean(Clock.class)
@ConditionalOnClass(OtlpMeterRegistry.class)
@ConditionalOnEnabledMetricsExport("otlp")
@EnableConfigurationProperties(OtlpProperties.class)
@EnableConfigurationProperties({ OtlpProperties.class, OpenTelemetryProperties.class })
public class OtlpMetricsExportAutoConfiguration {

private final OtlpProperties properties;

public OtlpMetricsExportAutoConfiguration(OtlpProperties properties) {
private final OpenTelemetryProperties openTelemetryProperties;

public OtlpMetricsExportAutoConfiguration(OtlpProperties properties,
OpenTelemetryProperties openTelemetryProperties) {
this.properties = properties;
this.openTelemetryProperties = openTelemetryProperties;
}

@Bean
@ConditionalOnMissingBean
public OtlpConfig otlpConfig() {
return new OtlpPropertiesConfigAdapter(this.properties);
return new OtlpPropertiesConfigAdapter(this.properties, this.openTelemetryProperties);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;

/**
* {@link ConfigurationProperties @ConfigurationProperties} for configuring OTLP metrics
Expand Down Expand Up @@ -77,6 +78,7 @@ public void setAggregationTemporality(AggregationTemporality aggregationTemporal
this.aggregationTemporality = aggregationTemporality;
}

@DeprecatedConfigurationProperty(replacement = "management.opentelemetry.resource-attributes")
public Map<String, String> getResourceAttributes() {
return this.resourceAttributes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,23 @@
import io.micrometer.registry.otlp.OtlpConfig;

import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties;
import org.springframework.util.CollectionUtils;

/**
* Adapter to convert {@link OtlpProperties} to an {@link OtlpConfig}.
*
* @author Eddú Meléndez
* @author Jonatan Ivanov
* @author Moritz Halbritter
*/
class OtlpPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<OtlpProperties> implements OtlpConfig {

OtlpPropertiesConfigAdapter(OtlpProperties properties) {
private final OpenTelemetryProperties openTelemetryProperties;

OtlpPropertiesConfigAdapter(OtlpProperties properties, OpenTelemetryProperties openTelemetryProperties) {
super(properties);
this.openTelemetryProperties = openTelemetryProperties;
}

@Override
Expand All @@ -53,6 +59,9 @@ public AggregationTemporality aggregationTemporality() {

@Override
public Map<String, String> resourceAttributes() {
if (!CollectionUtils.isEmpty(this.openTelemetryProperties.getResourceAttributes())) {
return this.openTelemetryProperties.getResourceAttributes();
}
return get(OtlpProperties::getResourceAttributes, OtlpConfig.super::resourceAttributes);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

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

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.OpenTelemetrySdkBuilder;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

/**
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry.
*
* @author Moritz Halbritter
* @since 3.2.0
*/
@AutoConfiguration
@ConditionalOnClass(OpenTelemetrySdk.class)
@EnableConfigurationProperties(OpenTelemetryProperties.class)
public class OpenTelemetryInfrastructureAutoConfiguration {

/**
* Default value for application name if {@code spring.application.name} is not set.
*/
private static final String DEFAULT_APPLICATION_NAME = "application";

@Bean
@ConditionalOnMissingBean(OpenTelemetry.class)
OpenTelemetrySdk openTelemetry(ObjectProvider<SdkTracerProvider> tracerProvider,
ObjectProvider<ContextPropagators> propagators, ObjectProvider<SdkLoggerProvider> loggerProvider,
ObjectProvider<SdkMeterProvider> meterProvider) {
OpenTelemetrySdkBuilder builder = OpenTelemetrySdk.builder();
tracerProvider.ifAvailable(builder::setTracerProvider);
propagators.ifAvailable(builder::setPropagators);
loggerProvider.ifAvailable(builder::setLoggerProvider);
meterProvider.ifAvailable(builder::setMeterProvider);
return builder.build();
}

@Bean
@ConditionalOnMissingBean
Resource openTelemetryResource(Environment environment, OpenTelemetryProperties properties) {
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
return Resource.getDefault()
.merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName)))
.merge(properties.toResource());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

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

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.resources.ResourceBuilder;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* Configuration properties for OpenTelemetry.
*
* @author Moritz Halbritter
* @since 3.2.0
*/
@ConfigurationProperties(prefix = "management.opentelemetry")
public class OpenTelemetryProperties {

/**
* Resource attributes.
*/
private Map<String, String> resourceAttributes = new HashMap<>();

public Map<String, String> getResourceAttributes() {
return this.resourceAttributes;
}

public void setResourceAttributes(Map<String, String> resourceAttributes) {
this.resourceAttributes = resourceAttributes;
}

Resource toResource() {
ResourceBuilder builder = Resource.builder();
for (Entry<String, String> entry : this.resourceAttributes.entrySet()) {
builder.put(entry.getKey(), entry.getValue());
}
return builder.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Auto-configuration for OpenTelemetry.
*/
package org.springframework.boot.actuate.autoconfigure.opentelemetry;
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@
import io.micrometer.tracing.otel.bridge.Slf4JEventListener;
import io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.ContextStorage;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
Expand All @@ -51,7 +49,6 @@
import io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.SpringBootVersion;
Expand All @@ -63,10 +60,9 @@
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

/**
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry.
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry tracing.
*
* @author Moritz Halbritter
* @author Marcin Grzejszczak
Expand All @@ -78,11 +74,6 @@
@EnableConfigurationProperties(TracingProperties.class)
public class OpenTelemetryAutoConfiguration {

/**
* Default value for application name if {@code spring.application.name} is not set.
*/
private static final String DEFAULT_APPLICATION_NAME = "application";

private final TracingProperties tracingProperties;

OpenTelemetryAutoConfiguration(TracingProperties tracingProperties) {
Expand All @@ -91,22 +82,9 @@ public class OpenTelemetryAutoConfiguration {

@Bean
@ConditionalOnMissingBean
OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider, ContextPropagators contextPropagators) {
return OpenTelemetrySdk.builder()
.setTracerProvider(sdkTracerProvider)
.setPropagators(contextPropagators)
.build();
}

@Bean
@ConditionalOnMissingBean
SdkTracerProvider otelSdkTracerProvider(Environment environment, SpanProcessors spanProcessors, Sampler sampler,
SdkTracerProvider otelSdkTracerProvider(Resource resource, SpanProcessors spanProcessors, Sampler sampler,
ObjectProvider<SdkTracerProviderBuilderCustomizer> customizers) {
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
Resource springResource = Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName));
SdkTracerProviderBuilder builder = SdkTracerProvider.builder()
.setSampler(sampler)
.setResource(Resource.getDefault().merge(springResource));
SdkTracerProviderBuilder builder = SdkTracerProvider.builder().setSampler(sampler).setResource(resource);
spanProcessors.forEach(builder::addSpanProcessor);
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
return builder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ org.springframework.boot.actuate.autoconfigure.data.mongo.MongoReactiveHealthCon
org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.web.servlet.WebMvcObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryInfrastructureAutoConfiguration
org.springframework.boot.actuate.autoconfigure.quartz.QuartzEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.r2dbc.ConnectionFactoryHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.redis.RedisHealthContributorAutoConfiguration
Expand All @@ -112,4 +113,4 @@ org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesEndpoi
org.springframework.boot.actuate.autoconfigure.web.mappings.MappingsEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementContextAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration
Loading

0 comments on commit 6d14596

Please sign in to comment.