From 0f643911976e6508e7f27046d429d67fcf20363e Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 19 Jan 2024 19:38:22 +0100 Subject: [PATCH 1/9] re-use sdk logic for configuring otlp exporters --- .../OpenTelemetryAutoConfiguration.java | 18 ++- .../otlp/OtlpExporterProperties.java | 3 + .../exporters/otlp/OtlpExporterUtil.java | 119 ------------------ .../OtlpLoggerExporterAutoConfiguration.java | 29 +---- .../OtlpMetricExporterAutoConfiguration.java | 28 +---- .../OtlpSpanExporterAutoConfiguration.java | 36 +----- .../SpringResourceConfigProperties.java | 102 +++++++++++++-- .../MetricExporterAutoConfigurationTest.java | 2 + .../SpanExporterAutoConfigurationTest.java | 2 + ...OtlpSpanExporterAutoConfigurationTest.java | 57 +++++---- .../SpringResourceConfigPropertiesTest.java | 4 +- 11 files changed, 167 insertions(+), 233 deletions(-) delete mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterUtil.java diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java index 2b79292d8ae4..8160f46f64cf 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java @@ -8,6 +8,7 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpExporterProperties; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLoggerExporterAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpMetricExporterAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration; @@ -55,7 +56,11 @@ *

Updates the sampler probability for the configured {@link TracerProvider}. */ @Configuration -@EnableConfigurationProperties({MetricExportProperties.class, SamplerProperties.class}) +@EnableConfigurationProperties({ + MetricExportProperties.class, + SamplerProperties.class, + OtlpExporterProperties.class +}) public class OpenTelemetryAutoConfiguration { public OpenTelemetryAutoConfiguration() {} @@ -91,6 +96,14 @@ static class Span {} static class Metric {} } + @Bean + @ConditionalOnMissingBean + ConfigProperties configProperties( + Environment env, OtlpExporterProperties otlpExporterProperties) { + return new SpringResourceConfigProperties( + env, new SpelExpressionParser(), otlpExporterProperties); + } + @Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance @ConditionalOnMissingBean public SdkTracerProvider sdkTracerProvider( @@ -156,8 +169,7 @@ private static PeriodicMetricReader createPeriodicMetricReader( @Bean @ConditionalOnMissingBean public Resource otelResource( - Environment env, ObjectProvider> resourceProviders) { - ConfigProperties config = new SpringResourceConfigProperties(env, new SpelExpressionParser()); + ConfigProperties config, ObjectProvider> resourceProviders) { Resource resource = Resource.getDefault(); for (ResourceProvider resourceProvider : resourceProviders.getIfAvailable(Collections::emptyList)) { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java index e4f678213d6a..9136713cb09d 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java @@ -20,6 +20,9 @@ *

Get Exporter Endpoint * *

Get max wait time for Collector to process Span Batches + * + *

Note that this class mostly exists to support auto-completion in IDEs. The actual properties + * are read using the {@link io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties} */ @ConfigurationProperties(prefix = "otel.exporter.otlp") public final class OtlpExporterProperties { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterUtil.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterUtil.java deleted file mode 100644 index 151862501bc8..000000000000 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterUtil.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp; - -import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil; -import java.time.Duration; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Function; -import java.util.function.Supplier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class OtlpExporterUtil { - private OtlpExporterUtil() {} - - private static final Logger logger = LoggerFactory.getLogger(OtlpExporterUtil.class); - - static E applySignalProperties( - String dataType, - OtlpExporterProperties properties, - OtlpExporterProperties.SignalProperties signalProperties, - Supplier newGrpcBuilder, - Supplier newHttpBuilder, - BiConsumer setGrpcEndpoint, - BiConsumer setHttpEndpoint, - BiConsumer> addGrpcHeader, - BiConsumer> addHttpHeader, - BiConsumer setGrpcTimeout, - BiConsumer setHttpTimeout, - Function buildGrpcExporter, - Function buildHttpExporter) { - - String protocol = signalProperties.getProtocol(); - if (protocol == null) { - protocol = properties.getProtocol(); - } - - G grpcBuilder = newGrpcBuilder.get(); - H httpBuilder = newHttpBuilder.get(); - - boolean isHttpProtobuf = !"grpc".equals(protocol); - - if (protocol != null - && !OtlpConfigUtil.PROTOCOL_GRPC.equals(protocol) - && !OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF.equals(protocol)) { - logger.warn( - "Unknown OTLP protocol '" - + protocol - + "', using '" - + OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF - + "'."); - } - - String endpoint = signalProperties.getEndpoint(); - if (endpoint == null) { - endpoint = properties.getEndpoint(); - if (endpoint != null && isHttpProtobuf) { - if (!endpoint.endsWith("/")) { - endpoint += "/"; - } - endpoint += signalPath(dataType); - } - } - - if (endpoint != null) { - if (isHttpProtobuf) { - setHttpEndpoint.accept(httpBuilder, endpoint); - } else { - setGrpcEndpoint.accept(grpcBuilder, endpoint); - } - } - - Map headers = signalProperties.getHeaders(); - if (headers.isEmpty()) { - headers = properties.getHeaders(); - } - for (Map.Entry entry : headers.entrySet()) { - if (isHttpProtobuf) { - addHttpHeader.accept(httpBuilder, entry); - } else { - addGrpcHeader.accept(grpcBuilder, entry); - } - } - - Duration timeout = signalProperties.getTimeout(); - if (timeout == null) { - timeout = properties.getTimeout(); - } - if (timeout != null) { - if (isHttpProtobuf) { - setHttpTimeout.accept(httpBuilder, timeout); - } else { - setGrpcTimeout.accept(grpcBuilder, timeout); - } - } - - return isHttpProtobuf - ? buildHttpExporter.apply(httpBuilder) - : buildGrpcExporter.apply(grpcBuilder); - } - - private static String signalPath(String dataType) { - switch (dataType) { - case OtlpConfigUtil.DATA_TYPE_METRICS: - return "v1/metrics"; - case OtlpConfigUtil.DATA_TYPE_TRACES: - return "v1/traces"; - case OtlpConfigUtil.DATA_TYPE_LOGS: - return "v1/logs"; - default: - throw new IllegalArgumentException( - "Cannot determine signal path for unrecognized data type: " + dataType); - } - } -} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLoggerExporterAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLoggerExporterAutoConfiguration.java index 99a50d675ebf..c2b55ea2148a 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLoggerExporterAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLoggerExporterAutoConfiguration.java @@ -6,49 +6,28 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp; import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; -import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder; -import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil; +import io.opentelemetry.exporter.otlp.internal.OtlpLogRecordExporterProvider; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; -import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.logs.export.LogRecordExporter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; 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.context.annotation.Condition; import org.springframework.context.annotation.Conditional; @AutoConfigureBefore(OpenTelemetryAutoConfiguration.class) -@EnableConfigurationProperties(OtlpExporterProperties.class) @Conditional(OtlpLoggerExporterAutoConfiguration.CustomCondition.class) @ConditionalOnClass(OtlpGrpcLogRecordExporter.class) public class OtlpLoggerExporterAutoConfiguration { @Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance @ConditionalOnMissingBean({OtlpGrpcLogRecordExporter.class, OtlpHttpLogRecordExporter.class}) - public LogRecordExporter otelOtlpLogRecordExporter(OtlpExporterProperties properties) { - - return OtlpExporterUtil.applySignalProperties( - OtlpConfigUtil.DATA_TYPE_LOGS, - properties, - properties.getLogs(), - OtlpGrpcLogRecordExporter::builder, - OtlpHttpLogRecordExporter::builder, - OtlpGrpcLogRecordExporterBuilder::setEndpoint, - OtlpHttpLogRecordExporterBuilder::setEndpoint, - (builder, entry) -> { - builder.addHeader(entry.getKey(), entry.getValue()); - }, - (builder, entry) -> { - builder.addHeader(entry.getKey(), entry.getValue()); - }, - OtlpGrpcLogRecordExporterBuilder::setTimeout, - OtlpHttpLogRecordExporterBuilder::setTimeout, - OtlpGrpcLogRecordExporterBuilder::build, - OtlpHttpLogRecordExporterBuilder::build); + public LogRecordExporter otelOtlpLogRecordExporter(ConfigProperties configProperties) { + return new OtlpLogRecordExporterProvider().createExporter(configProperties); } static final class CustomCondition implements Condition { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfiguration.java index 3450b4051fa0..2ada08d5c387 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfiguration.java @@ -6,17 +6,15 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; -import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder; -import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil; +import io.opentelemetry.exporter.otlp.internal.OtlpMetricExporterProvider; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; -import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.metrics.export.MetricExporter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; 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.context.annotation.Condition; import org.springframework.context.annotation.Conditional; @@ -24,32 +22,14 @@ @Configuration @AutoConfigureBefore(OpenTelemetryAutoConfiguration.class) -@EnableConfigurationProperties(OtlpExporterProperties.class) @Conditional(OtlpMetricExporterAutoConfiguration.CustomCondition.class) @ConditionalOnClass(OtlpGrpcMetricExporter.class) public class OtlpMetricExporterAutoConfiguration { @Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance @ConditionalOnMissingBean({OtlpGrpcMetricExporter.class, OtlpHttpMetricExporter.class}) - public MetricExporter otelOtlpMetricExporter(OtlpExporterProperties properties) { - return OtlpExporterUtil.applySignalProperties( - OtlpConfigUtil.DATA_TYPE_METRICS, - properties, - properties.getLogs(), - OtlpGrpcMetricExporter::builder, - OtlpHttpMetricExporter::builder, - OtlpGrpcMetricExporterBuilder::setEndpoint, - OtlpHttpMetricExporterBuilder::setEndpoint, - (builder, entry) -> { - builder.addHeader(entry.getKey(), entry.getValue()); - }, - (builder, entry) -> { - builder.addHeader(entry.getKey(), entry.getValue()); - }, - OtlpGrpcMetricExporterBuilder::setTimeout, - OtlpHttpMetricExporterBuilder::setTimeout, - OtlpGrpcMetricExporterBuilder::build, - OtlpHttpMetricExporterBuilder::build); + public MetricExporter otelOtlpMetricExporter(ConfigProperties configProperties) { + return new OtlpMetricExporterProvider().createExporter(configProperties); } static final class CustomCondition implements Condition { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfiguration.java index f4b35980b74a..ab254433c034 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfiguration.java @@ -6,17 +6,15 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; -import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder; -import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil; +import io.opentelemetry.exporter.otlp.internal.OtlpSpanExporterProvider; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; -import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.trace.export.SpanExporter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; 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.context.annotation.Condition; import org.springframework.context.annotation.Conditional; @@ -29,40 +27,14 @@ */ @Configuration @AutoConfigureBefore(OpenTelemetryAutoConfiguration.class) -@EnableConfigurationProperties(OtlpExporterProperties.class) @Conditional(OtlpSpanExporterAutoConfiguration.CustomCondition.class) @ConditionalOnClass(OtlpGrpcSpanExporter.class) public class OtlpSpanExporterAutoConfiguration { - @Bean - @ConditionalOnMissingBean({OtlpHttpSpanExporterBuilder.class}) - public OtlpHttpSpanExporterBuilder otelOtlpHttpSpanExporterBuilder() { - // used for testing only - the builder is final - return OtlpHttpSpanExporter.builder(); - } - @Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance @ConditionalOnMissingBean({OtlpGrpcSpanExporter.class, OtlpHttpSpanExporter.class}) - public SpanExporter otelOtlpSpanExporter( - OtlpExporterProperties properties, OtlpHttpSpanExporterBuilder otlpHttpSpanExporterBuilder) { - return OtlpExporterUtil.applySignalProperties( - OtlpConfigUtil.DATA_TYPE_TRACES, - properties, - properties.getLogs(), - OtlpGrpcSpanExporter::builder, - () -> otlpHttpSpanExporterBuilder, - OtlpGrpcSpanExporterBuilder::setEndpoint, - OtlpHttpSpanExporterBuilder::setEndpoint, - (builder, entry) -> { - builder.addHeader(entry.getKey(), entry.getValue()); - }, - (builder, entry) -> { - builder.addHeader(entry.getKey(), entry.getValue()); - }, - OtlpGrpcSpanExporterBuilder::setTimeout, - OtlpHttpSpanExporterBuilder::setTimeout, - OtlpGrpcSpanExporterBuilder::build, - OtlpHttpSpanExporterBuilder::build); + public SpanExporter otelOtlpSpanExporter(ConfigProperties configProperties) { + return new OtlpSpanExporterProvider().createExporter(configProperties); } static final class CustomCondition implements Condition { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java index 4ed9190ac45c..b89e5ca1056d 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java @@ -5,11 +5,14 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.resources; +import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpExporterProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import java.time.Duration; +import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; +import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; import org.springframework.core.env.Environment; import org.springframework.expression.ExpressionParser; @@ -18,10 +21,15 @@ public class SpringResourceConfigProperties implements ConfigProperties { private final Environment environment; private final ExpressionParser parser; + private final OtlpExporterProperties otlpExporterProperties; - public SpringResourceConfigProperties(Environment environment, ExpressionParser parser) { + public SpringResourceConfigProperties( + Environment environment, + ExpressionParser parser, + OtlpExporterProperties otlpExporterProperties) { this.environment = environment; this.parser = parser; + this.otlpExporterProperties = otlpExporterProperties; } @Nullable @@ -54,22 +62,100 @@ public Double getDouble(String name) { return environment.getProperty(name, Double.class); } + @SuppressWarnings("unchecked") + @Override + public List getList(String name) { + return (List) environment.getProperty(name, List.class); + } + @Nullable @Override public Duration getDuration(String name) { - return environment.getProperty(name, Duration.class); + String value = getString(name); + if (value == null || value.isEmpty()) { + return null; + } + String unitString = getUnitString(value); + // TODO: Environment variables have unknown encoding. `trim()` may cut codepoints oddly + // but likely we'll fail for malformed unit string either way. + String numberString = value.substring(0, value.length() - unitString.length()); + try { + long rawNumber = Long.parseLong(numberString.trim()); + TimeUnit unit = getDurationUnit(unitString.trim()); + return Duration.ofMillis(TimeUnit.MILLISECONDS.convert(rawNumber, unit)); + } catch (NumberFormatException ex) { + throw new ConfigurationException( + "Invalid duration property " + + name + + "=" + + value + + ". Expected number, found: " + + numberString, + ex); + } catch (ConfigurationException ex) { + throw new ConfigurationException( + "Invalid duration property " + name + "=" + value + ". " + ex.getMessage()); + } } - @SuppressWarnings("unchecked") - @Override - public List getList(String name) { - return (List) environment.getProperty(name, List.class); + /** Returns the TimeUnit associated with a unit string. Defaults to milliseconds. */ + private static TimeUnit getDurationUnit(String unitString) { + switch (unitString) { + case "": // Fallthrough expected + case "ms": + return TimeUnit.MILLISECONDS; + case "s": + return TimeUnit.SECONDS; + case "m": + return TimeUnit.MINUTES; + case "h": + return TimeUnit.HOURS; + case "d": + return TimeUnit.DAYS; + default: + throw new ConfigurationException("Invalid duration string, found: " + unitString); + } + } + + /** + * Fragments the 'units' portion of a config value from the 'value' portion. + * + *

E.g. "1ms" would return the string "ms". + */ + private static String getUnitString(String rawValue) { + int lastDigitIndex = rawValue.length() - 1; + while (lastDigitIndex >= 0) { + char c = rawValue.charAt(lastDigitIndex); + if (Character.isDigit(c)) { + break; + } + lastDigitIndex -= 1; + } + // Pull everything after the last digit. + return rawValue.substring(lastDigitIndex + 1); } @SuppressWarnings("unchecked") @Override public Map getMap(String name) { + // maps from config properties are not supported by Environment, so we have to fake it + switch (name) { + case "otel.exporter.otlp.headers": + return otlpExporterProperties.getHeaders(); + case "otel.exporter.otlp.logs.headers": + return otlpExporterProperties.getLogs().getHeaders(); + case "otel.exporter.otlp.metrics.headers": + return otlpExporterProperties.getMetrics().getHeaders(); + case "otel.exporter.otlp.traces.headers": + return otlpExporterProperties.getTraces().getHeaders(); + default: + break; + } + String value = environment.getProperty(name); - return (Map) parser.parseExpression(Objects.requireNonNull(value)).getValue(); + if (value == null) { + return Collections.emptyMap(); + } + return (Map) parser.parseExpression(value).getValue(); } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/MetricExporterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/MetricExporterAutoConfigurationTest.java index fb53294240f5..88519549b725 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/MetricExporterAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/MetricExporterAutoConfigurationTest.java @@ -9,6 +9,7 @@ import io.opentelemetry.exporter.logging.LoggingMetricExporter; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; +import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingMetricExporterAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpMetricExporterAutoConfiguration; import org.junit.jupiter.api.Test; @@ -21,6 +22,7 @@ class MetricExporterAutoConfigurationTest { new ApplicationContextRunner() .withConfiguration( AutoConfigurations.of( + OpenTelemetryAutoConfiguration.class, OtlpMetricExporterAutoConfiguration.class, LoggingMetricExporterAutoConfiguration.class)); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/SpanExporterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/SpanExporterAutoConfigurationTest.java index 558fe147088f..084694823be3 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/SpanExporterAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/SpanExporterAutoConfigurationTest.java @@ -9,6 +9,7 @@ import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingSpanExporterAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration; import org.junit.jupiter.api.Test; @@ -21,6 +22,7 @@ class SpanExporterAutoConfigurationTest { new ApplicationContextRunner() .withConfiguration( AutoConfigurations.of( + OpenTelemetryAutoConfiguration.class, OtlpSpanExporterAutoConfiguration.class, LoggingSpanExporterAutoConfiguration.class)); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfigurationTest.java index f0f934e10f8b..5329fb8d054d 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfigurationTest.java @@ -9,11 +9,11 @@ import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; -import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.util.stream.Collectors; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -23,14 +23,20 @@ /** Spring Boot auto configuration test for {@link OtlpSpanExporterAutoConfiguration}. */ class OtlpSpanExporterAutoConfigurationTest { - private final OtlpHttpSpanExporterBuilder otlpHttpSpanExporterBuilder = - Mockito.mock(OtlpHttpSpanExporterBuilder.class); + private final OtlpExporterProperties otlpExporterProperties = + Mockito.mock(OtlpExporterProperties.class); + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration( AutoConfigurations.of( OpenTelemetryAutoConfiguration.class, OtlpSpanExporterAutoConfiguration.class)); + @AfterEach + void tearDown() { + Mockito.verifyNoMoreInteractions(otlpExporterProperties); + } + @Test @DisplayName("when exporters are ENABLED should initialize OtlpHttpSpanExporter bean") void otlpEnabled() { @@ -40,8 +46,6 @@ void otlpEnabled() { context -> assertThat(context.getBean("otelOtlpSpanExporter", OtlpHttpSpanExporter.class)) .isNotNull()); - - Mockito.verifyNoMoreInteractions(otlpHttpSpanExporterBuilder); } @Test @@ -89,7 +93,7 @@ void exporterPresentByDefault() { @DisplayName("use http/protobuf when protocol set") void useHttp() { this.contextRunner - .withBean(OtlpHttpSpanExporterBuilder.class, () -> otlpHttpSpanExporterBuilder) + // .withBean(OtlpExporterProperties.class, () -> otlpExporterProperties) .withPropertyValues( "otel.exporter.otlp.enabled=true", "otel.exporter.otlp.protocol=http/protobuf", @@ -97,31 +101,42 @@ void useHttp() { "otel.exporter.otlp.headers.x=1", "otel.exporter.otlp.headers.y=2", "otel.exporter.otlp.timeout=1s") - .run(context -> {}); - - Mockito.verify(otlpHttpSpanExporterBuilder).build(); - Mockito.verify(otlpHttpSpanExporterBuilder).setEndpoint("http://localhost:4317/v1/traces"); - Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("x", "1"); - Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("y", "2"); - Mockito.verify(otlpHttpSpanExporterBuilder).setTimeout(java.time.Duration.ofSeconds(1)); - Mockito.verifyNoMoreInteractions(otlpHttpSpanExporterBuilder); + .run( + context -> + assertThat(context.getBean("otelOtlpSpanExporter", OtlpHttpSpanExporter.class)) + .hasFieldOrProperty("delegate") + .asString() + .contains("x=OBFUSCATED, y=OBFUSCATED")); + + // Mockito.verify(otlpHttpSpanExporterBuilder).build(); + // + // Mockito.verify(otlpHttpSpanExporterBuilder).setEndpoint("http://localhost:4317/v1/traces"); + // Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("x", "1"); + // Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("y", "2"); + // Mockito.verify(otlpHttpSpanExporterBuilder).setTimeout(java.time.Duration.ofSeconds(1)); + // Mockito.verifyNoMoreInteractions(otlpHttpSpanExporterBuilder); } @Test @DisplayName("use http/protobuf with environment variables for headers using the MapConverter") void useHttpWithEnv() { this.contextRunner - .withBean(OtlpHttpSpanExporterBuilder.class, () -> otlpHttpSpanExporterBuilder) + // .withBean(OtlpHttpSpanExporterBuilder.class, () -> otlpHttpSpanExporterBuilder) .withPropertyValues( "otel.exporter.otlp.enabled=true", "otel.exporter.otlp.protocol=http/protobuf") // are similar to environment variables in that they use the same converters .withSystemProperties("otel.exporter.otlp.headers=x=1,y=2") - .run(context -> {}); - - Mockito.verify(otlpHttpSpanExporterBuilder).build(); - Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("x", "1"); - Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("y", "2"); - Mockito.verifyNoMoreInteractions(otlpHttpSpanExporterBuilder); + .run( + context -> + assertThat(context.getBean("otelOtlpSpanExporter", OtlpHttpSpanExporter.class)) + .hasFieldOrProperty("delegate") + .asString() + .contains("x=OBFUSCATED, y=OBFUSCATED")); + + // Mockito.verify(otlpHttpSpanExporterBuilder).build(); + // Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("x", "1"); + // Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("y", "2"); + // Mockito.verifyNoMoreInteractions(otlpHttpSpanExporterBuilder); } @Test diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java index 93756ae1c4ed..d525c04932cf 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java @@ -8,6 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; +import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpExporterProperties; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -27,7 +28,8 @@ void shouldInitializeAttributesByMapInArow() { context -> { Environment env = context.getBean("environment", Environment.class); SpringResourceConfigProperties config = - new SpringResourceConfigProperties(env, new SpelExpressionParser()); + new SpringResourceConfigProperties( + env, new SpelExpressionParser(), new OtlpExporterProperties()); assertThat(config.getMap("otel.springboot.test.map")) .contains( From fe07f5be1f25da215328d98d7e6e9d5e129641b4 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 22 Jan 2024 11:44:02 +0100 Subject: [PATCH 2/9] re-use sdk logic for configuring otlp exporters --- .../SpringResourceConfigProperties.java | 72 +++---------------- ...lpMetricExporterAutoConfigurationTest.java | 10 ++- 2 files changed, 18 insertions(+), 64 deletions(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java index b89e5ca1056d..628deeb1cdeb 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java @@ -5,14 +5,14 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.resources; +import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpExporterProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; +import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import java.time.Duration; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; import org.springframework.core.env.Environment; import org.springframework.expression.ExpressionParser; @@ -35,7 +35,11 @@ public SpringResourceConfigProperties( @Nullable @Override public String getString(String name) { - return environment.getProperty(name, String.class); + String value = environment.getProperty(name, String.class); + if (value == null && name.equals("otel.exporter.otlp.protocol")) { + return OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF; + } + return value; } @Nullable @@ -72,67 +76,11 @@ public List getList(String name) { @Override public Duration getDuration(String name) { String value = getString(name); - if (value == null || value.isEmpty()) { + if (value == null) { return null; } - String unitString = getUnitString(value); - // TODO: Environment variables have unknown encoding. `trim()` may cut codepoints oddly - // but likely we'll fail for malformed unit string either way. - String numberString = value.substring(0, value.length() - unitString.length()); - try { - long rawNumber = Long.parseLong(numberString.trim()); - TimeUnit unit = getDurationUnit(unitString.trim()); - return Duration.ofMillis(TimeUnit.MILLISECONDS.convert(rawNumber, unit)); - } catch (NumberFormatException ex) { - throw new ConfigurationException( - "Invalid duration property " - + name - + "=" - + value - + ". Expected number, found: " - + numberString, - ex); - } catch (ConfigurationException ex) { - throw new ConfigurationException( - "Invalid duration property " + name + "=" + value + ". " + ex.getMessage()); - } - } - - /** Returns the TimeUnit associated with a unit string. Defaults to milliseconds. */ - private static TimeUnit getDurationUnit(String unitString) { - switch (unitString) { - case "": // Fallthrough expected - case "ms": - return TimeUnit.MILLISECONDS; - case "s": - return TimeUnit.SECONDS; - case "m": - return TimeUnit.MINUTES; - case "h": - return TimeUnit.HOURS; - case "d": - return TimeUnit.DAYS; - default: - throw new ConfigurationException("Invalid duration string, found: " + unitString); - } - } - - /** - * Fragments the 'units' portion of a config value from the 'value' portion. - * - *

E.g. "1ms" would return the string "ms". - */ - private static String getUnitString(String rawValue) { - int lastDigitIndex = rawValue.length() - 1; - while (lastDigitIndex >= 0) { - char c = rawValue.charAt(lastDigitIndex); - if (Character.isDigit(c)) { - break; - } - lastDigitIndex -= 1; - } - // Pull everything after the last digit. - return rawValue.substring(lastDigitIndex + 1); + return DefaultConfigProperties.createFromMap(Collections.singletonMap(name, value)) + .getDuration(name); } @SuppressWarnings("unchecked") diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfigurationTest.java index 106ccd4a493f..295714381f0f 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfigurationTest.java @@ -6,10 +6,12 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -51,8 +53,12 @@ void useHttpWhenAnUnknownProtocolIsSet() { .withPropertyValues("otel.exporter.otlp.protocol=unknown") .run( context -> - assertThat(context.getBean("otelOtlpMetricExporter", OtlpHttpMetricExporter.class)) - .isNotNull()); + assertThatThrownBy( + () -> + context.getBean("otelOtlpMetricExporter", OtlpHttpMetricExporter.class)) + .rootCause() + .isInstanceOf(ConfigurationException.class) + .hasMessage("Unsupported OTLP metrics protocol: unknown")); } @Test From 0a89d5bd8d61a4233d0fde58bd06d61ed017e3d6 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 22 Jan 2024 18:13:57 +0100 Subject: [PATCH 3/9] re-use sdk logic for configuring otlp exporters --- .../otlp/OtlpExporterPropertiesTest.java | 95 ++++++++++++++ .../OtlpLogExporterAutoConfigurationTest.java | 38 ------ ...lpMetricExporterAutoConfigurationTest.java | 38 ------ ...OtlpSpanExporterAutoConfigurationTest.java | 120 ------------------ 4 files changed, 95 insertions(+), 196 deletions(-) create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java new file mode 100644 index 000000000000..517ac0cd632e --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java @@ -0,0 +1,95 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import io.opentelemetry.instrumentation.spring.autoconfigure.MapConverterTestAutoConfiguration; +import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; +import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringResourceConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.util.Arrays; +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.core.env.Environment; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +class OtlpExporterPropertiesTest { + + private static final String[] HEADER_KEYS = { + "otel.exporter.otlp.traces.headers", + "otel.exporter.otlp.metrics.headers", + "otel.exporter.otlp.logs.headers", + "otel.exporter.otlp.headers", + }; + + private final ApplicationContextRunner contextRunner = + new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of( + OpenTelemetryAutoConfiguration.class, MapConverterTestAutoConfiguration.class)); + + public static Stream headerKeys() { + return Arrays.stream(HEADER_KEYS).map(Arguments::of); + } + + @Test + @DisplayName("test all property types") + void allTypes() { + this.contextRunner + .withPropertyValues( + "otel.exporter.otlp.enabled=true", + "otel.exporter.otlp.timeout=1s", + "otel.exporter.otlp.compression=gzip") + .run( + context -> { + ConfigProperties config = getConfig(context); + assertThat(config.getString("otel.exporter.otlp.compression")).isEqualTo("gzip"); + assertThat(config.getBoolean("otel.exporter.otlp.enabled")).isTrue(); + assertThat(config.getDuration("otel.exporter.otlp.timeout")) + .isEqualByComparingTo(java.time.Duration.ofSeconds(1)); + }); + } + + @ParameterizedTest + @MethodSource("headerKeys") + @DisplayName("should map headers from spring properties") + void mapFlatHeaders(String key) { + this.contextRunner + .withSystemProperties(key + "=a=1,b=2") + .run( + context -> + assertThat(getConfig(context).getMap(key)) + .containsExactly(entry("a", "1"), entry("b", "2"))); + } + + @ParameterizedTest + @MethodSource("headerKeys") + @DisplayName("should map headers from spring application.yaml") + void mapObjectHeaders(String key) { + this.contextRunner + .withPropertyValues(key + ".a=1", key + ".b=2") + .run( + context -> + assertThat(getConfig(context).getMap(key)) + .containsExactly(entry("a", "1"), entry("b", "2"))); + } + + private static ConfigProperties getConfig(AssertableApplicationContext context) { + return new SpringResourceConfigProperties( + context.getBean("environment", Environment.class), + new SpelExpressionParser(), + context.getBean(OtlpExporterProperties.class)); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogExporterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogExporterAutoConfigurationTest.java index 519c3cff167c..ecba9a72c4c4 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogExporterAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogExporterAutoConfigurationTest.java @@ -7,11 +7,8 @@ import static org.assertj.core.api.Assertions.assertThat; -import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; -import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; import io.opentelemetry.sdk.logs.export.LogRecordExporter; -import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -64,39 +61,4 @@ void otlpLogsDisabled() { .withPropertyValues("otel.logs.exporter=none") .run(context -> assertThat(context.containsBean("otelOtlpLogRecordExporter")).isFalse()); } - - @Test - void otlpHttpUsedByDefault() { - runner.run( - context -> - assertThat( - context.getBean("otelOtlpLogRecordExporter", OtlpHttpLogRecordExporter.class)) - .isNotNull()); - } - - @Test - @DisplayName("use grpc when protocol set") - void useGrpc() { - runner - .withPropertyValues("otel.exporter.otlp.protocol=grpc") - .run( - context -> - assertThat( - context.getBean( - "otelOtlpLogRecordExporter", OtlpGrpcLogRecordExporter.class)) - .isNotNull()); - } - - @Test - @DisplayName("use http when unknown protocol set") - void useHttpWhenAnUnknownProtocolIsSet() { - runner - .withPropertyValues("otel.exporter.otlp.protocol=unknown") - .run( - context -> - assertThat( - context.getBean( - "otelOtlpLogRecordExporter", OtlpHttpLogRecordExporter.class)) - .isNotNull()); - } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfigurationTest.java index 295714381f0f..b9a017d38613 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpMetricExporterAutoConfigurationTest.java @@ -6,13 +6,9 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; -import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; -import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -35,32 +31,6 @@ void otlpEnabled() { .isNotNull()); } - @Test - @DisplayName("use grpc when protocol set") - void useGrpc() { - runner - .withPropertyValues("otel.exporter.otlp.protocol=grpc") - .run( - context -> - assertThat(context.getBean("otelOtlpMetricExporter", OtlpGrpcMetricExporter.class)) - .isNotNull()); - } - - @Test - @DisplayName("use http when unknown protocol set") - void useHttpWhenAnUnknownProtocolIsSet() { - runner - .withPropertyValues("otel.exporter.otlp.protocol=unknown") - .run( - context -> - assertThatThrownBy( - () -> - context.getBean("otelOtlpMetricExporter", OtlpHttpMetricExporter.class)) - .rootCause() - .isInstanceOf(ConfigurationException.class) - .hasMessage("Unsupported OTLP metrics protocol: unknown")); - } - @Test void otlpMetricsEnabled() { runner @@ -91,12 +61,4 @@ void otlpMetricsDisabled() { .withPropertyValues("otel.metrics.exporter=none") .run(context -> assertThat(context.containsBean("otelOtlpMetricExporter")).isFalse()); } - - @Test - void otlpHttpUsedByDefault() { - runner.run( - context -> - assertThat(context.getBean("otelOtlpMetricExporter", OtlpHttpMetricExporter.class)) - .isNotNull()); - } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfigurationTest.java index 5329fb8d054d..c98d9817161d 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpSpanExporterAutoConfigurationTest.java @@ -7,36 +7,22 @@ import static org.assertj.core.api.Assertions.assertThat; -import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; -import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.util.stream.Collectors; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; /** Spring Boot auto configuration test for {@link OtlpSpanExporterAutoConfiguration}. */ class OtlpSpanExporterAutoConfigurationTest { - private final OtlpExporterProperties otlpExporterProperties = - Mockito.mock(OtlpExporterProperties.class); - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration( AutoConfigurations.of( OpenTelemetryAutoConfiguration.class, OtlpSpanExporterAutoConfiguration.class)); - @AfterEach - void tearDown() { - Mockito.verifyNoMoreInteractions(otlpExporterProperties); - } - @Test @DisplayName("when exporters are ENABLED should initialize OtlpHttpSpanExporter bean") void otlpEnabled() { @@ -72,110 +58,4 @@ void otlpTracesDisabledOld() { .withPropertyValues("otel.exporter.otlp.traces.enabled=false") .run(context -> assertThat(context.containsBean("otelOtlpSpanExporter")).isFalse()); } - - @Test - void otlpTracesDisabled() { - this.contextRunner - .withPropertyValues("otel.traces.exporter=none") - .run(context -> assertThat(context.containsBean("otelOtlpSpanExporter")).isFalse()); - } - - @Test - @DisplayName("when otlp enabled property is MISSING should initialize OtlpHttpSpanExporter bean") - void exporterPresentByDefault() { - this.contextRunner.run( - context -> - assertThat(context.getBean("otelOtlpSpanExporter", OtlpHttpSpanExporter.class)) - .isNotNull()); - } - - @Test - @DisplayName("use http/protobuf when protocol set") - void useHttp() { - this.contextRunner - // .withBean(OtlpExporterProperties.class, () -> otlpExporterProperties) - .withPropertyValues( - "otel.exporter.otlp.enabled=true", - "otel.exporter.otlp.protocol=http/protobuf", - "otel.exporter.otlp.endpoint=http://localhost:4317", - "otel.exporter.otlp.headers.x=1", - "otel.exporter.otlp.headers.y=2", - "otel.exporter.otlp.timeout=1s") - .run( - context -> - assertThat(context.getBean("otelOtlpSpanExporter", OtlpHttpSpanExporter.class)) - .hasFieldOrProperty("delegate") - .asString() - .contains("x=OBFUSCATED, y=OBFUSCATED")); - - // Mockito.verify(otlpHttpSpanExporterBuilder).build(); - // - // Mockito.verify(otlpHttpSpanExporterBuilder).setEndpoint("http://localhost:4317/v1/traces"); - // Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("x", "1"); - // Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("y", "2"); - // Mockito.verify(otlpHttpSpanExporterBuilder).setTimeout(java.time.Duration.ofSeconds(1)); - // Mockito.verifyNoMoreInteractions(otlpHttpSpanExporterBuilder); - } - - @Test - @DisplayName("use http/protobuf with environment variables for headers using the MapConverter") - void useHttpWithEnv() { - this.contextRunner - // .withBean(OtlpHttpSpanExporterBuilder.class, () -> otlpHttpSpanExporterBuilder) - .withPropertyValues( - "otel.exporter.otlp.enabled=true", "otel.exporter.otlp.protocol=http/protobuf") - // are similar to environment variables in that they use the same converters - .withSystemProperties("otel.exporter.otlp.headers=x=1,y=2") - .run( - context -> - assertThat(context.getBean("otelOtlpSpanExporter", OtlpHttpSpanExporter.class)) - .hasFieldOrProperty("delegate") - .asString() - .contains("x=OBFUSCATED, y=OBFUSCATED")); - - // Mockito.verify(otlpHttpSpanExporterBuilder).build(); - // Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("x", "1"); - // Mockito.verify(otlpHttpSpanExporterBuilder).addHeader("y", "2"); - // Mockito.verifyNoMoreInteractions(otlpHttpSpanExporterBuilder); - } - - @Test - @DisplayName("use grpc when protocol set") - void useGrpc() { - this.contextRunner - .withPropertyValues("otel.exporter.otlp.protocol=grpc") - .run( - context -> - assertThat(context.getBean(OtlpGrpcSpanExporter.class)) - .as("Should contain the gRPC span exporter when grpc is set") - .isNotNull()); - } - - @Test - @DisplayName("use http when unknown protocol set") - void useHttpWhenAnUnknownProtocolIsSet() { - this.contextRunner - .withPropertyValues("otel.exporter.otlp.protocol=unknown") - .run( - context -> - assertThat(context.getBean(OtlpHttpSpanExporter.class)) - .as("Should contain the http span exporter when an unknown is set") - .isNotNull()); - } - - @Test - @DisplayName("logging exporter can still be configured") - void loggingExporter() { - this.contextRunner - .withBean( - LoggingSpanExporter.class, - LoggingSpanExporter::create, - bd -> bd.setDestroyMethodName("")) - .run( - context -> - assertThat( - context.getBeanProvider(SpanExporter.class).stream() - .collect(Collectors.toList())) - .hasSize(2)); - } } From 7f10f7583886ae1673b952dbd6f22b4470d757ae Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 30 Jan 2024 13:35:18 +0100 Subject: [PATCH 4/9] rename class to align with SDK --- .../spring/autoconfigure/OpenTelemetryAutoConfiguration.java | 2 +- ...ation.java => OtlpLogRecordExporterAutoConfiguration.java} | 4 ++-- .../src/main/resources/META-INF/spring.factories | 2 +- ...ringframework.boot.autoconfigure.AutoConfiguration.imports | 2 +- .../exporters/otlp/OtlpLogExporterAutoConfigurationTest.java | 3 ++- 5 files changed, 7 insertions(+), 6 deletions(-) rename instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/{OtlpLoggerExporterAutoConfiguration.java => OtlpLogRecordExporterAutoConfiguration.java} (94%) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java index 8160f46f64cf..364573076ef4 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java @@ -9,7 +9,7 @@ import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpExporterProperties; -import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLoggerExporterAutoConfiguration; +import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLogRecordExporterAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpMetricExporterAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.MapConverter; diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLoggerExporterAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogRecordExporterAutoConfiguration.java similarity index 94% rename from instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLoggerExporterAutoConfiguration.java rename to instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogRecordExporterAutoConfiguration.java index c2b55ea2148a..5c65cd13593b 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLoggerExporterAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogRecordExporterAutoConfiguration.java @@ -20,9 +20,9 @@ import org.springframework.context.annotation.Conditional; @AutoConfigureBefore(OpenTelemetryAutoConfiguration.class) -@Conditional(OtlpLoggerExporterAutoConfiguration.CustomCondition.class) +@Conditional(OtlpLogRecordExporterAutoConfiguration.CustomCondition.class) @ConditionalOnClass(OtlpGrpcLogRecordExporter.class) -public class OtlpLoggerExporterAutoConfiguration { +public class OtlpLogRecordExporterAutoConfiguration { @Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance @ConditionalOnMissingBean({OtlpGrpcLogRecordExporter.class, OtlpHttpLogRecordExporter.class}) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 389172ec1bd7..0d6e9b094c9e 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -2,7 +2,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingMetricExporterAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingSpanExporterAutoConfiguration,\ -io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLoggerExporterAutoConfiguration,\ +io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLogRecordExporterAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpMetricExporterAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.exporters.zipkin.ZipkinSpanExporterAutoConfiguration,\ diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 8c9d440219d7..0642d53bce54 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,7 +1,7 @@ io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingMetricExporterAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingSpanExporterAutoConfiguration -io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLoggerExporterAutoConfiguration +io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLogRecordExporterAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpMetricExporterAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.exporters.zipkin.ZipkinSpanExporterAutoConfiguration diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogExporterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogExporterAutoConfigurationTest.java index ecba9a72c4c4..644193d8933d 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogExporterAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpLogExporterAutoConfigurationTest.java @@ -19,7 +19,8 @@ class OtlpLogExporterAutoConfigurationTest { new ApplicationContextRunner() .withConfiguration( AutoConfigurations.of( - OpenTelemetryAutoConfiguration.class, OtlpLoggerExporterAutoConfiguration.class)); + OpenTelemetryAutoConfiguration.class, + OtlpLogRecordExporterAutoConfiguration.class)); @Test void otlpEnabled() { From c92afc459658c3fc06e5007f5cbdcf4650bb7462 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 31 Jan 2024 16:21:13 +0100 Subject: [PATCH 5/9] Update instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java Co-authored-by: Trask Stalnaker --- .../autoconfigure/resources/SpringResourceConfigProperties.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java index 628deeb1cdeb..2444368b66c2 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java @@ -37,6 +37,8 @@ public SpringResourceConfigProperties( public String getString(String name) { String value = environment.getProperty(name, String.class); if (value == null && name.equals("otel.exporter.otlp.protocol")) { + // SDK autoconfigure module defaults to `grpc`, but this module aligns with recommendation + // in specification to default to `http/protobuf` return OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF; } return value; From 19699c3410b38e58276766f52a8d0b3d01f45685 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 1 Feb 2024 11:19:44 +0100 Subject: [PATCH 6/9] rename class to align with SDK --- .../spring/autoconfigure/OpenTelemetryAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java index 364573076ef4..27f36d947473 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java @@ -86,7 +86,7 @@ public MapConverterCondition() { @ConditionalOnBean(OtelResourceAutoConfiguration.class) static class Resource {} - @ConditionalOnBean(OtlpLoggerExporterAutoConfiguration.class) + @ConditionalOnBean(OtlpLogRecordExporterAutoConfiguration.class) static class Logger {} @ConditionalOnBean(OtlpSpanExporterAutoConfiguration.class) From 58db6e760d061370609acf1a80c35c1b5c1fe514 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 1 Feb 2024 13:42:00 +0100 Subject: [PATCH 7/9] re-use sdk logic for configuring otlp exporters --- .../exporters/otlp/OtlpExporterPropertiesTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java index 517ac0cd632e..b9dc9992ece4 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java @@ -8,8 +8,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; -import io.opentelemetry.instrumentation.spring.autoconfigure.MapConverterTestAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; +import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringResourceConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.util.Arrays; @@ -38,7 +38,7 @@ class OtlpExporterPropertiesTest { new ApplicationContextRunner() .withConfiguration( AutoConfigurations.of( - OpenTelemetryAutoConfiguration.class, MapConverterTestAutoConfiguration.class)); + OpenTelemetryAutoConfiguration.class, OtelResourceAutoConfiguration.class)); public static Stream headerKeys() { return Arrays.stream(HEADER_KEYS).map(Arguments::of); From a8133629e2ea78eaa610f1448766491dc2e45b59 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 5 Feb 2024 13:20:02 +0100 Subject: [PATCH 8/9] document all spring auto-config properties --- .../OpenTelemetryAutoConfiguration.java | 5 +- .../logging/LoggingExporterProperties.java | 49 --- ...oggingMetricExporterAutoConfiguration.java | 2 - .../LoggingSpanExporterAutoConfiguration.java | 2 - .../otlp/OtlpExporterProperties.java | 98 +---- .../zipkin/ZipkinSpanExporterProperties.java | 9 - ...rties.java => SpringConfigProperties.java} | 4 +- ...itional-spring-configuration-metadata.json | 349 +++++++++++++++++- .../otlp/OtlpExporterPropertiesTest.java | 4 +- ...t.java => SpringConfigPropertiesTest.java} | 6 +- 10 files changed, 358 insertions(+), 170 deletions(-) delete mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingExporterProperties.java rename instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/{SpringResourceConfigProperties.java => SpringConfigProperties.java} (96%) rename instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/{SpringResourceConfigPropertiesTest.java => SpringConfigPropertiesTest.java} (91%) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java index 27f36d947473..8ef6865c5588 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java @@ -14,7 +14,7 @@ import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.MapConverter; import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration; -import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringResourceConfigProperties; +import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringConfigProperties; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; @@ -100,8 +100,7 @@ static class Metric {} @ConditionalOnMissingBean ConfigProperties configProperties( Environment env, OtlpExporterProperties otlpExporterProperties) { - return new SpringResourceConfigProperties( - env, new SpelExpressionParser(), otlpExporterProperties); + return new SpringConfigProperties(env, new SpelExpressionParser(), otlpExporterProperties); } @Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingExporterProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingExporterProperties.java deleted file mode 100644 index c0e8402f6b91..000000000000 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingExporterProperties.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * Configuration for {@link io.opentelemetry.exporter.logging.LoggingSpanExporter} and {@link - * io.opentelemetry.exporter.logging.LoggingMetricExporter}. - */ -@ConfigurationProperties(prefix = "otel.exporter.logging") -public final class LoggingExporterProperties { - - private boolean enabled = false; - private final SignalProperties traces = new SignalProperties(); - private final SignalProperties metrics = new SignalProperties(); - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public SignalProperties getTraces() { - return traces; - } - - public SignalProperties getMetrics() { - return metrics; - } - - public static class SignalProperties { - - private boolean enabled = false; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - } -} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingMetricExporterAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingMetricExporterAutoConfiguration.java index eab905471033..0b7829b071d1 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingMetricExporterAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingMetricExporterAutoConfiguration.java @@ -11,7 +11,6 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore; 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.context.annotation.Condition; import org.springframework.context.annotation.Conditional; @@ -19,7 +18,6 @@ /** Configures {@link LoggingMetricExporter} bean for tracing. */ @Configuration -@EnableConfigurationProperties(LoggingExporterProperties.class) @AutoConfigureBefore(OpenTelemetryAutoConfiguration.class) @Conditional(LoggingMetricExporterAutoConfiguration.CustomCondition.class) @ConditionalOnClass(LoggingMetricExporter.class) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingSpanExporterAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingSpanExporterAutoConfiguration.java index 3d3038312e84..09b7234b1a79 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingSpanExporterAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/logging/LoggingSpanExporterAutoConfiguration.java @@ -11,7 +11,6 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore; 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.context.annotation.Condition; import org.springframework.context.annotation.Conditional; @@ -19,7 +18,6 @@ /** Configures {@link LoggingSpanExporter} bean for tracing. */ @Configuration -@EnableConfigurationProperties(LoggingExporterProperties.class) @AutoConfigureBefore(OpenTelemetryAutoConfiguration.class) @Conditional(LoggingSpanExporterAutoConfiguration.CustomCondition.class) @ConditionalOnClass(LoggingSpanExporter.class) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java index 9136713cb09d..bb9b3e792bf3 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java @@ -5,79 +5,26 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp; -import java.time.Duration; import java.util.HashMap; import java.util.Map; -import javax.annotation.Nullable; import org.springframework.boot.context.properties.ConfigurationProperties; /** - * Configuration for {@link io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter} and {@link - * io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter}. - * - *

Get Exporter Service Name - * - *

Get Exporter Endpoint - * - *

Get max wait time for Collector to process Span Batches - * - *

Note that this class mostly exists to support auto-completion in IDEs. The actual properties - * are read using the {@link io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties} + * Configuration for OLTP exporters. */ @ConfigurationProperties(prefix = "otel.exporter.otlp") public final class OtlpExporterProperties { - private boolean enabled = true; - @Nullable private String endpoint; - - @Nullable private String protocol; - private final Map headers = new HashMap<>(); - @Nullable private Duration timeout; private final SignalProperties traces = new SignalProperties(); private final SignalProperties metrics = new SignalProperties(); private final SignalProperties logs = new SignalProperties(); - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - @Nullable - public String getEndpoint() { - return endpoint; - } - - public void setEndpoint(String endpoint) { - this.endpoint = endpoint; - } - - @Nullable - public String getProtocol() { - return protocol; - } - - public void setProtocol(@Nullable String protocol) { - this.protocol = protocol; - } - public Map getHeaders() { return headers; } - @Nullable - public Duration getTimeout() { - return timeout; - } - - public void setTimeout(Duration timeout) { - this.timeout = timeout; - } - public SignalProperties getTraces() { return traces; } @@ -91,53 +38,10 @@ public SignalProperties getLogs() { } public static class SignalProperties { - - private boolean enabled = true; - @Nullable private String endpoint; - - @Nullable private String protocol; - private final Map headers = new HashMap<>(); - @Nullable private Duration timeout; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - @Nullable - public String getEndpoint() { - return endpoint; - } - - public void setEndpoint(@Nullable String endpoint) { - this.endpoint = endpoint; - } - - @Nullable - public String getProtocol() { - return protocol; - } - - public void setProtocol(@Nullable String protocol) { - this.protocol = protocol; - } - public Map getHeaders() { return headers; } - - @Nullable - public Duration getTimeout() { - return timeout; - } - - public void setTimeout(@Nullable Duration timeout) { - this.timeout = timeout; - } } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/zipkin/ZipkinSpanExporterProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/zipkin/ZipkinSpanExporterProperties.java index c6a7e412d8fb..d7e1df91b948 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/zipkin/ZipkinSpanExporterProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/zipkin/ZipkinSpanExporterProperties.java @@ -16,17 +16,8 @@ @ConfigurationProperties(prefix = "otel.exporter.zipkin") public class ZipkinSpanExporterProperties { - private boolean enabled = true; @Nullable private String endpoint; - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - @Nullable public String getEndpoint() { return endpoint; diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringConfigProperties.java similarity index 96% rename from instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java rename to instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringConfigProperties.java index 2444368b66c2..60210ba60991 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringConfigProperties.java @@ -17,13 +17,13 @@ import org.springframework.core.env.Environment; import org.springframework.expression.ExpressionParser; -public class SpringResourceConfigProperties implements ConfigProperties { +public class SpringConfigProperties implements ConfigProperties { private final Environment environment; private final ExpressionParser parser; private final OtlpExporterProperties otlpExporterProperties; - public SpringResourceConfigProperties( + public SpringConfigProperties( Environment environment, ExpressionParser parser, OtlpExporterProperties otlpExporterProperties) { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index b12bc3157aa6..07ca3e93af70 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -5,6 +5,198 @@ } ], "properties": [ + { + "name": "otel.experimental.exporter.otlp.retry.enabled", + "type": "java.lang.Boolean", + "description": "Enable experimental retry support. See https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#otlp-exporter-retry.", + "defaultValue": false + }, + { + "name": "otel.exporter.otlp.certificate", + "type": "java.lang.String", + "description": "The path to the file containing trusted certificates to use when verifying an OTLP trace, metric, or log server's TLS credentials.
The file should contain one or more X.509 certificates in PEM format.
By default the host platform's trusted root certificates are used." + }, + { + "name": "otel.exporter.otlp.client.certificate", + "type": "java.lang.String", + "description": "The path to the file containing trusted certificates to use when verifying an OTLP trace, metric, or log client's TLS credentials.
The file should contain one or more X.509 certificates in PEM format.
By default, no chain file is used." + }, + { + "name": "otel.exporter.otlp.client.key", + "type": "java.lang.String", + "description": "The path to the file containing private client key to use when verifying an OTLP trace, metric, or log client's TLS credentials.
The file should contain one private key PKCS8 PEM format.
By default, no client key is used." + }, + { + "name": "otel.exporter.otlp.compression", + "type": "java.lang.String", + "description": "The compression type to use on OTLP trace, metric, and log requests.
Options include gzip.
By default, no compression will be used." + }, + { + "name": "otel.exporter.otlp.endpoint", + "type": "java.lang.String", + "description": "The OTLP traces, metrics, and logs endpoint to connect to.
Must be a URL with a scheme of either http or https based on the use of TLS. If protocol is http/protobuf the version and signal will be appended to the path (e.g. v1/traces, v1/metrics, or v1/logs).
Default is http://localhost:4317 when protocol is grpc, and http://localhost:4318/v1/{signal} when protocol is http/protobuf." + }, + { + "name": "otel.exporter.otlp.headers", + "type": "java.util.Map", + "description": "Request headers for OTLP trace, metric, and log requests.
Can be either a Spring map or a key-value separated String, e.g. key1=value1,key2=value2." + }, + { + "name": "otel.exporter.otlp.logs.certificate", + "type": "java.lang.String", + "description": " The path to the file containing trusted certificates to use when verifying an OTLP log server's TLS credentials.
The file should contain one or more X.509 certificates in PEM format.
By default, the host platform's trusted root certificates are used." + }, + { + "name": "otel.exporter.otlp.logs.client.certificate", + "type": "java.lang.String", + "description": "The path to the file containing trusted certificates to use when verifying an OTLP log server's TLS credentials.
The file should contain one or more X.509 certificates in PEM format.
By default, no chain file is used." + }, + { + "name": "otel.exporter.otlp.logs.client.key", + "type": "java.lang.String", + "description": "The path to the file containing private client key to use when verifying an OTLP log client's TLS credentials.
The file should contain one private key PKCS8 PEM format.
By default, no client key file is used." + }, + { + "name": "otel.exporter.otlp.logs.compression", + "type": "java.lang.String", + "description": "The compression type to use on OTLP log requests.
Options include gzip.
By default, no compression will be used." + }, + { + "name": "otel.exporter.otlp.logs.endpoint", + "type": "java.lang.String", + "description": "The OTLP logs endpoint to connect to.
Must be a URL with a scheme of either http or https based on the use of TLS.
Default is http://localhost:4317 when protocol is grpc, and http://localhost:4318/v1/logs when protocol is http/protobuf." + }, + { + "name": "otel.exporter.otlp.logs.headers", + "type": "java.util.Map", + "description": "Request headers for OTLP log requests.
Can be either a Spring map or a key-value separated String, e.g. key1=value1,key2=value2." + }, + { + "name": "otel.exporter.otlp.logs.protocol", + "type": "java.lang.String", + "description": "The transport protocol to use on OTLP log requests.", + "defaultValue": "http/protobuf" + }, + { + "name": "otel.exporter.otlp.logs.timeout", + "type": "java.lang.String", + "description": "The maximum waiting time, in milliseconds, allowed to send each OTLP log batch.
Durations can be of the form {number}{unit}, where unit is one of:

If no unit is specified, milliseconds is the assumed duration unit.", + "defaultValue": "10000" + }, + { + "name": "otel.exporter.otlp.metrics.certificate", + "type": "java.lang.String", + "description": "The path to the file containing trusted certificates to use when verifying an OTLP metric server's TLS credentials.
The file should contain one or more X.509 certificates in PEM format.
By default, the host platform's trusted root certificates are used." + }, + { + "name": "otel.exporter.otlp.metrics.client.certificate", + "type": "java.lang.String", + "description": "The path to the file containing trusted certificates to use when verifying an OTLP metric server's TLS credentials.
The file should contain one or more X.509 certificates in PEM format.
By default, no chain file is used." + }, + { + "name": "otel.exporter.otlp.metrics.client.key", + "type": "java.lang.String", + "description": "The path to the file containing private client key to use when verifying an OTLP metric client's TLS credentials.
The file should contain one private key PKCS8 PEM format.
By default, no client key file is used." + }, + { + "name": "otel.exporter.otlp.metrics.compression", + "type": "java.lang.String", + "description": "The compression type to use on OTLP metric requests.
Options include gzip.
By default, no compression will be used." + }, + { + "name": "otel.exporter.otlp.metrics.default.histogram.aggregation", + "type": "java.lang.String", + "description": "The preferred default histogram aggregation.", + "defaultValue": "EXPLICIT_BUCKET_HISTOGRAM" + }, + { + "name": "otel.exporter.otlp.metrics.endpoint", + "type": "java.lang.String", + "description": "The OTLP metrics endpoint to connect to.
Must be a URL with a scheme of either http or https based on the use of TLS.
Default is http://localhost:4317 when protocol is grpc, and http://localhost:4318/v1/metrics when protocol is http/protobuf." + }, + { + "name": "otel.exporter.otlp.metrics.headers", + "type": "java.util.Map", + "description": "Request headers for OTLP metric requests.
Can be either a Spring map or a key-value separated String, e.g. key1=value1,key2=value2." + }, + { + "name": "otel.exporter.otlp.metrics.protocol", + "type": "java.lang.String", + "description": "The transport protocol to use on OTLP metric requests.", + "defaultValue": "http/protobuf" + }, + { + "name": "otel.exporter.otlp.metrics.temporality.preference", + "type": "java.lang.String", + "description": "The preferred output aggregation temporality.", + "defaultValue": "CUMULATIVE" + }, + { + "name": "otel.exporter.otlp.metrics.timeout", + "type": "java.lang.String", + "description": "The maximum waiting time, in milliseconds, allowed to send each OTLP metric batch.
Durations can be of the form {number}{unit}, where unit is one of:

If no unit is specified, milliseconds is the assumed duration unit.", + "defaultValue": "10000" + }, + { + "name": "otel.exporter.otlp.protocol", + "type": "java.lang.String", + "description": "The transport protocol to use on OTLP trace, metric, and log requests.", + "defaultValue": "http/protobuf" + }, + { + "name": "otel.exporter.otlp.timeout", + "type": "java.lang.String", + "description": "The maximum waiting time, in milliseconds, allowed to send each OTLP trace, metric, and log batch.
Durations can be of the form {number}{unit}, where unit is one of:

If no unit is specified, milliseconds is the assumed duration unit.", + "defaultValue": "10000" + }, + { + "name": "otel.exporter.otlp.traces.certificate", + "type": "java.lang.String", + "description": "The path to the file containing trusted certificates to use when verifying an OTLP trace server's TLS credentials.
The file should contain one or more X.509 certificates in PEM format.
By default, the host platform's trusted root certificates are used." + }, + { + "name": "otel.exporter.otlp.traces.client.certificate", + "type": "java.lang.String", + "description": "The path to the file containing trusted certificates to use when verifying an OTLP trace server's TLS credentials.
The file should contain one or more X.509 certificates in PEM format.
By default no chain file is used." + }, + { + "name": "otel.exporter.otlp.traces.client.key", + "type": "java.lang.String", + "description": "The path to the file containing private client key to use when verifying an OTLP trace client's TLS credentials.
The file should contain one private key PKCS8 PEM format.
By default, no client key file is used." + }, + { + "name": "otel.exporter.otlp.traces.compression", + "type": "java.lang.String", + "description": "The compression type to use on OTLP trace requests.
Options include gzip.
By default, no compression will be used." + }, + { + "name": "otel.exporter.otlp.traces.endpoint", + "type": "java.lang.String", + "description": "The OTLP traces endpoint to connect to.
Must be a URL with a scheme of either http or https based on the use of TLS.
Default is http://localhost:4317 when protocol is grpc, and http://localhost:4318/v1/traces when protocol is http/protobuf." + }, + { + "name": "otel.exporter.otlp.traces.headers", + "type": "java.util.Map", + "description": "Request headers for OTLP trace requests.
Can be either a Spring map or a key-value separated String, e.g. key1=value1,key2=value2." + }, + { + "name": "otel.exporter.otlp.traces.protocol", + "type": "java.lang.String", + "description": "The transport protocol to use on OTLP trace requests.", + "defaultValue": "http/protobuf" + }, + { + "name": "otel.exporter.otlp.traces.timeout", + "type": "java.lang.String", + "description": "The maximum waiting time, in milliseconds, allowed to send each OTLP trace batch.
Durations can be of the form {number}{unit}, where unit is one of:

If no unit is specified, milliseconds is the assumed duration unit.", + "defaultValue": "10000" + }, + { + "name": "otel.exporter.zipkin.endpoint", + "type": "java.lang.String", + "description": "The Zipkin endpoint to connect to.
Currently only HTTP is supported.", + "defaultValue": "http://localhost:9411/api/v2/spans" + }, { "name": "otel.instrumentation.logback-appender.experimental.capture-code-attributes", "type": "java.lang.Boolean", @@ -38,7 +230,162 @@ { "name": "otel.instrumentation.logback-appender.experimental.capture-mdc-attributes", "type": "java.lang.String", - "description": "Comma separated list of MDC attributes to capture. Use the wildcard character * to capture all attributes." + "description": "Comma separated list of MDC attributes to capture. Use the wildcard character * to capture all attributes." + }, + { + "name": "otel.logs.exporter", + "type": "java.lang.String", + "description": "List of exporters to be used for logs, separated by commas.", + "defaultValue": "otlp" + }, + { + "name": "otel.metric.export.interval", + "type": "java.lang.String", + "description": "The interval, in milliseconds, between the start of two export attempts.
Durations can be of the form {number}{unit}, where unit is one of:

If no unit is specified, milliseconds is the assumed duration unit.", + "defaultValue": "60000" + }, + { + "name": "otel.metrics.exporter", + "type": "java.lang.String", + "description": "List of exporters to be used for metrics, separated by commas.", + "defaultValue": "otlp" + }, + { + "name": "otel.traces.exporter", + "type": "java.lang.String", + "description": "List of exporters to be used for tracing, separated by commas.", + "defaultValue": "otlp" + }, + { + "name": "otel.traces.sampler.probability", + "type": "java.lang.Double", + "description": "The probability of sampling.
The value should be within [0.0, 1.0]. 1.0 means keep everything, 0.0 means drop all spans.", + "defaultValue": 1.0 + } + ], + "hints": [ + { + "name": "otel.exporter.otlp.logs.protocol", + "values": [ + { + "value": "http/protobuf" + }, + { + "value": "grpc" + } + ] + }, + { + "name": "otel.exporter.otlp.metrics.protocol", + "values": [ + { + "value": "http/protobuf" + }, + { + "value": "grpc" + } + ] + }, + { + "name": "otel.exporter.otlp.protocol", + "values": [ + { + "value": "http/protobuf" + }, + { + "value": "grpc" + } + ] + }, + { + "name": "otel.exporter.otlp.traces.protocol", + "values": [ + { + "value": "http/protobuf" + }, + { + "value": "grpc" + } + ] + }, + { + "name": "otel.exporter.otlp.metrics.default.histogram.aggregation", + "values": [ + { + "value": "BASE2_EXPONENTIAL_BUCKET_HISTOGRAM" + }, + { + "value": "EXPLICIT_BUCKET_HISTOGRAM" + } + ] + }, + { + "name": "otel.exporter.otlp.metrics.temporality.preference", + "values": [ + { + "value": "CUMULATIVE", + "description": "All instruments will have cumulative temporality." + }, + { + "value": "DELTA", + "description": "Counter (sync and async) and histograms will be delta, up down counters (sync and async) will be cumulative." + }, + { + "value": "LOWMEMORY", + "description": "Sync counter and histograms will be delta, async counter and up down counters (sync and async) will be cumulative." + } + ] + }, + { + "name": "otel.logs.exporter", + "values": [ + { + "value": "none", + "description": "No autoconfigured exporter." + }, + { + "value": "otlp", + "description": "OpenTelemetry Protocol (OTLP) exporter." + } + ] + }, + { + "name": "otel.metrics.exporter", + "values": [ + { + "value": "logging", + "description": "The logging exporter prints exported metrics to stdout. It's mainly used for testing and debugging." + }, + { + "value": "none", + "description": "No autoconfigured exporter." + }, + { + "value": "otlp", + "description": "OpenTelemetry Protocol (OTLP) exporter." + } + ] + }, + { + "name": "otel.traces.exporter", + "values": [ + { + "value": "logging", + "description": "The logging exporter prints the name of the span along with its attributes to stdout. It's mainly used for testing and debugging." + }, + { + "value": "none", + "description": "No autoconfigured exporter." + }, + { + "value": "otlp", + "description": "OpenTelemetry Protocol (OTLP) exporter." + }, + { + "value": "zipkin", + "description": "Zipkin exporter." + } + ] } ] } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java index b9dc9992ece4..8d61a4e7d4ae 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterPropertiesTest.java @@ -10,7 +10,7 @@ import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration; -import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringResourceConfigProperties; +import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.util.Arrays; import java.util.stream.Stream; @@ -87,7 +87,7 @@ void mapObjectHeaders(String key) { } private static ConfigProperties getConfig(AssertableApplicationContext context) { - return new SpringResourceConfigProperties( + return new SpringConfigProperties( context.getBean("environment", Environment.class), new SpelExpressionParser(), context.getBean(OtlpExporterProperties.class)); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringConfigPropertiesTest.java similarity index 91% rename from instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java rename to instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringConfigPropertiesTest.java index d525c04932cf..779b974db8ad 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringConfigPropertiesTest.java @@ -15,7 +15,7 @@ import org.springframework.core.env.Environment; import org.springframework.expression.spel.standard.SpelExpressionParser; -class SpringResourceConfigPropertiesTest { +class SpringConfigPropertiesTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); @Test @@ -27,8 +27,8 @@ void shouldInitializeAttributesByMapInArow() { .run( context -> { Environment env = context.getBean("environment", Environment.class); - SpringResourceConfigProperties config = - new SpringResourceConfigProperties( + SpringConfigProperties config = + new SpringConfigProperties( env, new SpelExpressionParser(), new OtlpExporterProperties()); assertThat(config.getMap("otel.springboot.test.map")) From 0f42a7e807a4f25608007b79410c70839202861e Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 5 Feb 2024 13:31:07 +0100 Subject: [PATCH 9/9] document all spring auto-config properties --- .../autoconfigure/exporters/otlp/OtlpExporterProperties.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java index bb9b3e792bf3..9ec65498e71e 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/exporters/otlp/OtlpExporterProperties.java @@ -9,9 +9,7 @@ import java.util.Map; import org.springframework.boot.context.properties.ConfigurationProperties; -/** - * Configuration for OLTP exporters. - */ +/** Configuration for OLTP exporters. */ @ConfigurationProperties(prefix = "otel.exporter.otlp") public final class OtlpExporterProperties {