add support for OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_HEADERS and OTEL_EXPORTER_OTLP_PROTOCOL for spring boot starter (#9950)
This commit is contained in:
parent
67facf3ef7
commit
87615cc9d9
|
@ -390,51 +390,105 @@ If an exporter is present in the classpath during runtime and a spring bean of t
|
|||
|
||||
#### Configuration Properties
|
||||
|
||||
##### Enabling/Disabling Features
|
||||
##### Enabling/Disabling Exporters
|
||||
|
||||
| Feature | Property | Default Value | ConditionalOnClass |
|
||||
|------------------|---------------------------------------------|---------------|------------------------|
|
||||
| spring-web | otel.instrumentation.spring-webmvc.enabled | `true` | RestTemplate |
|
||||
| spring-webmvc | otel.instrumentation.spring-web.enabled | `true` | OncePerRequestFilter |
|
||||
| spring-webflux | otel.instrumentation.spring-webflux.enabled | `true` | WebClient |
|
||||
| @WithSpan | otel.instrumentation.annotations.enabled | `true` | WithSpan, Aspect |
|
||||
| Otlp Exporter | otel.exporter.otlp.enabled | `true` | OtlpGrpcSpanExporter |
|
||||
| Jaeger Exporter | otel.exporter.jaeger.enabled | `true` | JaegerGrpcSpanExporter |
|
||||
| Zipkin Exporter | otel.exporter.zipkin.enabled | `true` | ZipkinSpanExporter |
|
||||
| Logging Exporter | otel.exporter.logging.enabled | `true` | LoggingSpanExporter |
|
||||
All exporters can be enabled or disabled as in the
|
||||
[SDK auto-configuration](https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#exporters).
|
||||
This is the preferred way to enable/disable exporters and takes precedence over the properties below.
|
||||
|
||||
| Feature | Property | Default Value | ConditionalOnClass |
|
||||
|-----------------------|---------------------------------------------|---------------|---------------------------|
|
||||
| Otlp Exporter | otel.exporter.otlp.enabled | `true` | - |
|
||||
| Otlp Span Exporter | otel.exporter.otlp.traces.enabled | `true` | OtlpGrpcSpanExporter |
|
||||
| Otlp Metrics Exporter | otel.exporter.otlp.metrics.enabled | `true` | OtlpGrpcMetricExporter |
|
||||
| Otlp Logs Exporter | otel.exporter.otlp.logs.enabled | `true` | OtlpGrpcLogRecordExporter |
|
||||
| Jaeger Exporter | otel.exporter.jaeger.enabled | `true` | JaegerGrpcSpanExporter |
|
||||
| Zipkin Exporter | otel.exporter.zipkin.enabled | `true` | ZipkinSpanExporter |
|
||||
| Logging Exporter | otel.exporter.logging.enabled | `false` | LoggingSpanExporter |
|
||||
|
||||
<!-- Slf4j Log Correlation otel.springboot.loggers.slf4j.enabled true org.slf4j.MDC -->
|
||||
|
||||
##### Enabling/Disabling Features
|
||||
|
||||
| Feature | Property | Default Value | ConditionalOnClass |
|
||||
|-----------------------|---------------------------------------------|---------------|---------------------------|
|
||||
| spring-web | otel.instrumentation.spring-webmvc.enabled | `true` | RestTemplate |
|
||||
| spring-webmvc | otel.instrumentation.spring-web.enabled | `true` | OncePerRequestFilter |
|
||||
| spring-webflux | otel.instrumentation.spring-webflux.enabled | `true` | WebClient |
|
||||
| @WithSpan | otel.instrumentation.annotations.enabled | `true` | WithSpan, Aspect |
|
||||
|
||||
##### Resource Properties
|
||||
|
||||
| Feature | Property | Default Value |
|
||||
| -------- | ------------------------------------------------ | ---------------------- |
|
||||
| Resource | otel.springboot.resource.enabled | `true` |
|
||||
| | otel.springboot.resource.attributes.service.name | `unknown_service:java` |
|
||||
| | otel.springboot.resource.attributes | `empty map` |
|
||||
| Feature | Property | Default Value |
|
||||
| -------- |---------------------------------------------------------------------| ---------------------- |
|
||||
| Resource | otel.springboot.resource.enabled | `true` |
|
||||
| | otel.resource.attributes (old: otel.springboot.resource.attributes) | `empty map` |
|
||||
|
||||
`unknown_service:java` will be used as the service-name if no value has been specified to the
|
||||
property `spring.application.name` or `otel.springboot.resource.attributes.service.name` (which has
|
||||
the highest priority)
|
||||
|
||||
`otel.springboot.resource.attributes` supports a pattern-based resource configuration in the
|
||||
`otel.resource.attributes` supports a pattern-based resource configuration in the
|
||||
application.properties like this:
|
||||
|
||||
```
|
||||
otel.springboot.resource.attributes.environment=dev
|
||||
otel.springboot.resource.attributes.xyz=foo
|
||||
otel.resource.attributes.environment=dev
|
||||
otel.resource.attributes.xyz=foo
|
||||
```
|
||||
|
||||
It's also possible to specify the resource attributes in `application.yaml`:
|
||||
|
||||
```yaml
|
||||
otel:
|
||||
resource:
|
||||
attributes:
|
||||
environment: dev
|
||||
xyz: foo
|
||||
```
|
||||
|
||||
Finally, the resource attributes can be specified as a comma-separated list, as described in the
|
||||
[specification](https://opentelemetry.io/docs/concepts/sdk-configuration/general-sdk-configuration/#otel_resource_attributes):
|
||||
|
||||
```shell
|
||||
export OTEL_RESOURCE_ATTRIBUTES="key1=value1,key2=value2"
|
||||
```
|
||||
|
||||
The service name is determined by the following precedence, in accordance with the OpenTelemetry
|
||||
[specification](https://opentelemetry.io/docs/concepts/sdk-configuration/general-sdk-configuration/#otel_service_name):
|
||||
|
||||
1. `otel.service.name` spring property or `OTEL_SERVICE_NAME` environment variable (highest
|
||||
precedence)
|
||||
2. `service.name` in `otel.resource.attributes` system/spring property or `OTEL_RESOURCE_ATTRIBUTES`
|
||||
environment variable
|
||||
3. `service.name` in `otel.springboot.resource.attributes` system/spring property
|
||||
4. `spring.application.name` spring property
|
||||
5. the default value `unknown_service:java` (lowest precedence)
|
||||
|
||||
##### Exporter Properties
|
||||
|
||||
| Feature | Property | Default Value |
|
||||
| --------------- | ----------------------------- | ------------------------------------ |
|
||||
|-----------------|-------------------------------|--------------------------------------|
|
||||
| Otlp Exporter | otel.exporter.otlp.endpoint | `localhost:4317` |
|
||||
| | otel.exporter.otlp.protocol | `grpc` |
|
||||
| | otel.exporter.otlp.headers | |
|
||||
| | otel.exporter.otlp.timeout | `1s` |
|
||||
| Jaeger Exporter | otel.exporter.jaeger.endpoint | `localhost:14250` |
|
||||
| | otel.exporter.jaeger.timeout | `1s` |
|
||||
| Zipkin Exporter | otel.exporter.jaeger.endpoint | `http://localhost:9411/api/v2/spans` |
|
||||
|
||||
The `otel.exporter.otlp.headers` property can be specified as a comma-separated list,
|
||||
which is compliant with the
|
||||
[specification](https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_headers).
|
||||
Similar to the resource attributes, the headers can be specified in `application.properties` or
|
||||
`application.yaml`:
|
||||
|
||||
```yaml
|
||||
otel:
|
||||
exporter:
|
||||
otlp:
|
||||
headers:
|
||||
- key: "header1"
|
||||
value: "value1"
|
||||
- key: "header2"
|
||||
value: "value2"
|
||||
```
|
||||
|
||||
##### Tracer Properties
|
||||
|
||||
| Feature | Property | Default Value |
|
||||
|
|
|
@ -90,6 +90,7 @@ testing {
|
|||
implementation(project(":testing-common"))
|
||||
implementation("io.opentelemetry:opentelemetry-sdk")
|
||||
implementation("io.opentelemetry:opentelemetry-sdk-testing")
|
||||
implementation("org.mockito:mockito-inline")
|
||||
implementation("org.springframework.boot:spring-boot-autoconfigure:$springBootVersion")
|
||||
|
||||
implementation(project(":instrumentation:logback:logback-appender-1.0:library"))
|
||||
|
|
|
@ -8,6 +8,11 @@ package io.opentelemetry.instrumentation.spring.autoconfigure;
|
|||
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.OtlpLoggerExporterAutoConfiguration;
|
||||
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;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringResourceConfigProperties;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
|
@ -30,8 +35,10 @@ import io.opentelemetry.sdk.trace.samplers.Sampler;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -56,6 +63,19 @@ public class OpenTelemetryAutoConfiguration {
|
|||
@ConditionalOnProperty(name = "otel.sdk.disabled", havingValue = "false", matchIfMissing = true)
|
||||
public static class OpenTelemetrySdkConfig {
|
||||
|
||||
@Bean
|
||||
@ConfigurationPropertiesBinding
|
||||
@ConditionalOnBean({
|
||||
OtelResourceAutoConfiguration.class,
|
||||
OtlpLoggerExporterAutoConfiguration.class,
|
||||
OtlpSpanExporterAutoConfiguration.class,
|
||||
OtlpMetricExporterAutoConfiguration.class
|
||||
})
|
||||
public MapConverter mapConverter() {
|
||||
// needed for otlp exporter headers and OtelResourceProperties
|
||||
return new MapConverter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SdkTracerProvider sdkTracerProvider(
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import javax.annotation.Nullable;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
* any time.
|
||||
*/
|
||||
public final class ExporterConfigEvaluator {
|
||||
|
||||
private ExporterConfigEvaluator() {}
|
||||
|
||||
public static boolean isExporterEnabled(
|
||||
Environment environment,
|
||||
@Nullable String oldAllKey,
|
||||
String oldKey,
|
||||
String exportersKey,
|
||||
String wantExporter,
|
||||
boolean defaultValue) {
|
||||
|
||||
String exporter = environment.getProperty(exportersKey);
|
||||
if (exporter != null) {
|
||||
return Arrays.asList(exporter.split(",")).contains(wantExporter);
|
||||
}
|
||||
|
||||
String old = environment.getProperty(oldKey);
|
||||
if (old != null) {
|
||||
return "true".equals(old);
|
||||
}
|
||||
if (oldAllKey != null) {
|
||||
String oldAll = environment.getProperty(oldAllKey);
|
||||
if (oldAll != null) {
|
||||
return "true".equals(oldAll);
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
|
@ -6,12 +6,14 @@
|
|||
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.jaeger;
|
||||
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
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;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
|
@ -23,7 +25,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
@Configuration
|
||||
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(JaegerSpanExporterProperties.class)
|
||||
@ConditionalOnProperty(prefix = "otel.exporter.jaeger", name = "enabled", matchIfMissing = true)
|
||||
@Conditional(JaegerSpanExporterAutoConfiguration.CustomCondition.class)
|
||||
@ConditionalOnClass(io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter.class)
|
||||
@Deprecated
|
||||
public class JaegerSpanExporterAutoConfiguration {
|
||||
|
@ -43,4 +45,19 @@ public class JaegerSpanExporterAutoConfiguration {
|
|||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static final class CustomCondition implements Condition {
|
||||
@Override
|
||||
public boolean matches(
|
||||
org.springframework.context.annotation.ConditionContext context,
|
||||
org.springframework.core.type.AnnotatedTypeMetadata metadata) {
|
||||
return ExporterConfigEvaluator.isExporterEnabled(
|
||||
context.getEnvironment(),
|
||||
null,
|
||||
"otel.exporter.jaeger.enabled",
|
||||
"otel.traces.exporter",
|
||||
"jaeger",
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
|
|||
import io.opentelemetry.exporter.logging.LoggingMetricExporter;
|
||||
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
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;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
@ -21,7 +21,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
@Configuration
|
||||
@EnableConfigurationProperties(LoggingExporterProperties.class)
|
||||
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
|
||||
@Conditional(LoggingMetricExporterAutoConfiguration.AnyPropertyEnabled.class)
|
||||
@Conditional(LoggingMetricExporterAutoConfiguration.CustomCondition.class)
|
||||
@ConditionalOnClass(LoggingMetricExporter.class)
|
||||
public class LoggingMetricExporterAutoConfiguration {
|
||||
|
||||
|
@ -30,16 +30,18 @@ public class LoggingMetricExporterAutoConfiguration {
|
|||
return LoggingMetricExporter.create();
|
||||
}
|
||||
|
||||
static final class AnyPropertyEnabled extends AnyNestedCondition {
|
||||
|
||||
AnyPropertyEnabled() {
|
||||
super(ConfigurationPhase.PARSE_CONFIGURATION);
|
||||
static final class CustomCondition implements Condition {
|
||||
@Override
|
||||
public boolean matches(
|
||||
org.springframework.context.annotation.ConditionContext context,
|
||||
org.springframework.core.type.AnnotatedTypeMetadata metadata) {
|
||||
return ExporterConfigEvaluator.isExporterEnabled(
|
||||
context.getEnvironment(),
|
||||
"otel.exporter.logging.enabled",
|
||||
"otel.exporter.logging.metrics.enabled",
|
||||
"otel.metrics.exporter",
|
||||
"logging",
|
||||
false);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty("otel.exporter.logging.enabled")
|
||||
static class LoggingEnabled {}
|
||||
|
||||
@ConditionalOnProperty("otel.exporter.logging.metrics.enabled")
|
||||
static class LoggingMetricsEnabled {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,13 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
|
|||
|
||||
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
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;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
@ -21,7 +21,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
@Configuration
|
||||
@EnableConfigurationProperties(LoggingExporterProperties.class)
|
||||
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
|
||||
@Conditional(LoggingSpanExporterAutoConfiguration.AnyPropertyEnabled.class)
|
||||
@Conditional(LoggingSpanExporterAutoConfiguration.CustomCondition.class)
|
||||
@ConditionalOnClass(LoggingSpanExporter.class)
|
||||
public class LoggingSpanExporterAutoConfiguration {
|
||||
|
||||
|
@ -31,16 +31,18 @@ public class LoggingSpanExporterAutoConfiguration {
|
|||
return LoggingSpanExporter.create();
|
||||
}
|
||||
|
||||
static final class AnyPropertyEnabled extends AnyNestedCondition {
|
||||
|
||||
AnyPropertyEnabled() {
|
||||
super(ConfigurationPhase.PARSE_CONFIGURATION);
|
||||
static final class CustomCondition implements Condition {
|
||||
@Override
|
||||
public boolean matches(
|
||||
org.springframework.context.annotation.ConditionContext context,
|
||||
org.springframework.core.type.AnnotatedTypeMetadata metadata) {
|
||||
return ExporterConfigEvaluator.isExporterEnabled(
|
||||
context.getEnvironment(),
|
||||
"otel.exporter.logging.enabled",
|
||||
"otel.exporter.logging.traces.enabled",
|
||||
"otel.traces.exporter",
|
||||
"logging",
|
||||
false);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty("otel.exporter.logging.enabled")
|
||||
static class LoggingEnabled {}
|
||||
|
||||
@ConditionalOnProperty("otel.exporter.logging.traces.enabled")
|
||||
static class LoggingTracesEnabled {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
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;
|
||||
|
||||
|
@ -24,6 +26,11 @@ public final class OtlpExporterProperties {
|
|||
|
||||
private boolean enabled = true;
|
||||
@Nullable private String endpoint;
|
||||
|
||||
@Nullable private String protocol;
|
||||
|
||||
private final Map<String, String> headers = new HashMap<>();
|
||||
|
||||
@Nullable private Duration timeout;
|
||||
private final SignalProperties traces = new SignalProperties();
|
||||
private final SignalProperties metrics = new SignalProperties();
|
||||
|
@ -46,6 +53,19 @@ public final class OtlpExporterProperties {
|
|||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(@Nullable String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Duration getTimeout() {
|
||||
return timeout;
|
||||
|
@ -71,6 +91,11 @@ public final class OtlpExporterProperties {
|
|||
|
||||
private boolean enabled = true;
|
||||
@Nullable private String endpoint;
|
||||
|
||||
@Nullable private String protocol;
|
||||
|
||||
private final Map<String, String> headers = new HashMap<>();
|
||||
|
||||
@Nullable private Duration timeout;
|
||||
|
||||
public boolean isEnabled() {
|
||||
|
@ -90,6 +115,19 @@ public final class OtlpExporterProperties {
|
|||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(@Nullable String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Duration getTimeout() {
|
||||
return timeout;
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class OtlpExporterUtil {
|
||||
private OtlpExporterUtil() {}
|
||||
|
||||
static <G, H, E> E applySignalProperties(
|
||||
String dataType,
|
||||
OtlpExporterProperties properties,
|
||||
OtlpExporterProperties.SignalProperties signalProperties,
|
||||
Supplier<G> newGrpcBuilder,
|
||||
Supplier<H> newHttpBuilder,
|
||||
BiConsumer<G, String> setGrpcEndpoint,
|
||||
BiConsumer<H, String> setHttpEndpoint,
|
||||
BiConsumer<G, Map.Entry<String, String>> addGrpcHeader,
|
||||
BiConsumer<H, Map.Entry<String, String>> addHttpHeader,
|
||||
BiConsumer<G, Duration> setGrpcTimeout,
|
||||
BiConsumer<H, Duration> setHttpTimeout,
|
||||
Function<G, E> buildGrpcExporter,
|
||||
Function<H, E> buildHttpExporter) {
|
||||
|
||||
String protocol = signalProperties.getProtocol();
|
||||
if (protocol == null) {
|
||||
protocol = properties.getProtocol();
|
||||
}
|
||||
|
||||
G grpcBuilder = newGrpcBuilder.get();
|
||||
H httpBuilder = newHttpBuilder.get();
|
||||
|
||||
boolean isHttpProtobuf = Objects.equals(protocol, OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF);
|
||||
|
||||
String endpoint = signalProperties.getEndpoint();
|
||||
if (endpoint == null) {
|
||||
endpoint = properties.getEndpoint();
|
||||
}
|
||||
if (endpoint != null) {
|
||||
if (isHttpProtobuf) {
|
||||
if (!endpoint.endsWith("/")) {
|
||||
endpoint += "/";
|
||||
}
|
||||
endpoint += signalPath(dataType);
|
||||
}
|
||||
|
||||
if (isHttpProtobuf) {
|
||||
setHttpEndpoint.accept(httpBuilder, endpoint);
|
||||
} else {
|
||||
setGrpcEndpoint.accept(grpcBuilder, endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> headers = signalProperties.getHeaders();
|
||||
if (headers.isEmpty()) {
|
||||
headers = properties.getHeaders();
|
||||
}
|
||||
for (Map.Entry<String, String> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,48 +5,64 @@
|
|||
|
||||
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.logs.OtlpGrpcLogRecordExporter;
|
||||
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
|
||||
import java.time.Duration;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
|
||||
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.autoconfigure.condition.ConditionalOnProperty;
|
||||
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)
|
||||
@ConditionalOnProperty(
|
||||
prefix = "otel.exporter.otlp",
|
||||
name = {"enabled", "logs.enabled"},
|
||||
matchIfMissing = true)
|
||||
@Conditional(OtlpLoggerExporterAutoConfiguration.CustomCondition.class)
|
||||
@ConditionalOnClass(OtlpGrpcLogRecordExporter.class)
|
||||
public class OtlpLoggerExporterAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OtlpGrpcLogRecordExporter otelOtlpGrpcLogRecordExporter(
|
||||
OtlpExporterProperties properties) {
|
||||
OtlpGrpcLogRecordExporterBuilder builder = OtlpGrpcLogRecordExporter.builder();
|
||||
@ConditionalOnMissingBean({OtlpGrpcLogRecordExporter.class, OtlpHttpLogRecordExporter.class})
|
||||
public LogRecordExporter otelOtlpLogRecordExporter(OtlpExporterProperties properties) {
|
||||
|
||||
String endpoint = properties.getLogs().getEndpoint();
|
||||
if (endpoint == null) {
|
||||
endpoint = properties.getEndpoint();
|
||||
}
|
||||
if (endpoint != null) {
|
||||
builder.setEndpoint(endpoint);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
Duration timeout = properties.getLogs().getTimeout();
|
||||
if (timeout == null) {
|
||||
timeout = properties.getTimeout();
|
||||
static final class CustomCondition implements Condition {
|
||||
@Override
|
||||
public boolean matches(
|
||||
org.springframework.context.annotation.ConditionContext context,
|
||||
org.springframework.core.type.AnnotatedTypeMetadata metadata) {
|
||||
return ExporterConfigEvaluator.isExporterEnabled(
|
||||
context.getEnvironment(),
|
||||
"otel.exporter.otlp.enabled",
|
||||
"otel.exporter.otlp.logs.enabled",
|
||||
"otel.logs.exporter",
|
||||
"otlp",
|
||||
true);
|
||||
}
|
||||
if (timeout != null) {
|
||||
builder.setTimeout(timeout);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,49 +5,65 @@
|
|||
|
||||
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.metrics.OtlpGrpcMetricExporter;
|
||||
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
|
||||
import java.time.Duration;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
|
||||
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.autoconfigure.condition.ConditionalOnProperty;
|
||||
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;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(OtlpExporterProperties.class)
|
||||
@ConditionalOnProperty(
|
||||
prefix = "otel.exporter.otlp",
|
||||
name = {"enabled", "metrics.enabled"},
|
||||
matchIfMissing = true)
|
||||
@Conditional(OtlpMetricExporterAutoConfiguration.CustomCondition.class)
|
||||
@ConditionalOnClass(OtlpGrpcMetricExporter.class)
|
||||
public class OtlpMetricExporterAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OtlpGrpcMetricExporter otelOtlpGrpcMetricExporter(OtlpExporterProperties properties) {
|
||||
OtlpGrpcMetricExporterBuilder builder = OtlpGrpcMetricExporter.builder();
|
||||
@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);
|
||||
}
|
||||
|
||||
String endpoint = properties.getMetrics().getEndpoint();
|
||||
if (endpoint == null) {
|
||||
endpoint = properties.getEndpoint();
|
||||
static final class CustomCondition implements Condition {
|
||||
@Override
|
||||
public boolean matches(
|
||||
org.springframework.context.annotation.ConditionContext context,
|
||||
org.springframework.core.type.AnnotatedTypeMetadata metadata) {
|
||||
return ExporterConfigEvaluator.isExporterEnabled(
|
||||
context.getEnvironment(),
|
||||
"otel.exporter.otlp.enabled",
|
||||
"otel.exporter.otlp.metrics.enabled",
|
||||
"otel.metrics.exporter",
|
||||
"otlp",
|
||||
true);
|
||||
}
|
||||
if (endpoint != null) {
|
||||
builder.setEndpoint(endpoint);
|
||||
}
|
||||
|
||||
Duration timeout = properties.getMetrics().getTimeout();
|
||||
if (timeout == null) {
|
||||
timeout = properties.getTimeout();
|
||||
}
|
||||
if (timeout != null) {
|
||||
builder.setTimeout(timeout);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,21 @@
|
|||
|
||||
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.trace.OtlpGrpcSpanExporter;
|
||||
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
|
||||
import java.time.Duration;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
|
||||
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.autoconfigure.condition.ConditionalOnProperty;
|
||||
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;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
|
@ -25,34 +30,53 @@ import org.springframework.context.annotation.Configuration;
|
|||
@Configuration
|
||||
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(OtlpExporterProperties.class)
|
||||
@ConditionalOnProperty(
|
||||
prefix = "otel.exporter.otlp",
|
||||
name = {"enabled", "traces.enabled"},
|
||||
matchIfMissing = true)
|
||||
@Conditional(OtlpSpanExporterAutoConfiguration.CustomCondition.class)
|
||||
@ConditionalOnClass(OtlpGrpcSpanExporter.class)
|
||||
public class OtlpSpanExporterAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OtlpGrpcSpanExporter otelOtlpGrpcSpanExporter(OtlpExporterProperties properties) {
|
||||
OtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder();
|
||||
@ConditionalOnMissingBean({OtlpHttpSpanExporterBuilder.class})
|
||||
public OtlpHttpSpanExporterBuilder otelOtlpHttpSpanExporterBuilder() {
|
||||
// used for testing only - the builder is final
|
||||
return OtlpHttpSpanExporter.builder();
|
||||
}
|
||||
|
||||
String endpoint = properties.getTraces().getEndpoint();
|
||||
if (endpoint == null) {
|
||||
endpoint = properties.getEndpoint();
|
||||
}
|
||||
if (endpoint != null) {
|
||||
builder.setEndpoint(endpoint);
|
||||
}
|
||||
@Bean
|
||||
@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);
|
||||
}
|
||||
|
||||
Duration timeout = properties.getTraces().getTimeout();
|
||||
if (timeout == null) {
|
||||
timeout = properties.getTimeout();
|
||||
static final class CustomCondition implements Condition {
|
||||
@Override
|
||||
public boolean matches(
|
||||
org.springframework.context.annotation.ConditionContext context,
|
||||
org.springframework.core.type.AnnotatedTypeMetadata metadata) {
|
||||
return ExporterConfigEvaluator.isExporterEnabled(
|
||||
context.getEnvironment(),
|
||||
"otel.exporter.otlp.enabled",
|
||||
"otel.exporter.otlp.traces.enabled",
|
||||
"otel.traces.exporter",
|
||||
"otlp",
|
||||
true);
|
||||
}
|
||||
if (timeout != null) {
|
||||
builder.setTimeout(timeout);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,14 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.zipkin;
|
|||
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
|
||||
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
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;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
|
@ -24,7 +26,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
@Configuration
|
||||
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(ZipkinSpanExporterProperties.class)
|
||||
@ConditionalOnProperty(prefix = "otel.exporter.zipkin", name = "enabled", matchIfMissing = true)
|
||||
@Conditional(ZipkinSpanExporterAutoConfiguration.CustomCondition.class)
|
||||
@ConditionalOnClass(ZipkinSpanExporter.class)
|
||||
public class ZipkinSpanExporterAutoConfiguration {
|
||||
|
||||
|
@ -38,4 +40,19 @@ public class ZipkinSpanExporterAutoConfiguration {
|
|||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static final class CustomCondition implements Condition {
|
||||
@Override
|
||||
public boolean matches(
|
||||
org.springframework.context.annotation.ConditionContext context,
|
||||
org.springframework.core.type.AnnotatedTypeMetadata metadata) {
|
||||
return ExporterConfigEvaluator.isExporterEnabled(
|
||||
context.getEnvironment(),
|
||||
null,
|
||||
"otel.exporter.zipkin.enabled",
|
||||
"otel.traces.exporter",
|
||||
"zipkin",
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.spring.autoconfigure.internal;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
/**
|
||||
* The MapConverter class is used to convert a String to a Map. The String is expected to be in the
|
||||
* format of a comma separated list of key=value pairs, e.g. key1=value1,key2=value2.
|
||||
*
|
||||
* <p>This is the expected format for the <code>OTEL_RESOURCE_ATTRIBUTES</code> and <code>
|
||||
* OTEL_EXPORTER_OTLP_HEADERS</code> environment variables.
|
||||
*
|
||||
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
|
||||
* at any time.
|
||||
*/
|
||||
public class MapConverter implements Converter<String, Map<String, String>> {
|
||||
|
||||
public static final String KEY = "key";
|
||||
|
||||
@Override
|
||||
public Map<String, String> convert(String source) {
|
||||
DefaultConfigProperties properties =
|
||||
DefaultConfigProperties.createFromMap(Collections.singletonMap(KEY, source));
|
||||
|
||||
return properties.getMap(KEY);
|
||||
}
|
||||
}
|
|
@ -25,14 +25,16 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(OtelResourceProperties.class)
|
||||
@EnableConfigurationProperties({OtelSpringResourceProperties.class, OtelResourceProperties.class})
|
||||
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
|
||||
@ConditionalOnProperty(prefix = "otel.springboot.resource", name = "enabled", matchIfMissing = true)
|
||||
public class OtelResourceAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ResourceProvider otelResourceProvider(OtelResourceProperties otelResourceProperties) {
|
||||
return new SpringResourceProvider(otelResourceProperties);
|
||||
public ResourceProvider otelResourceProvider(
|
||||
OtelSpringResourceProperties otelSpringResourceProperties,
|
||||
OtelResourceProperties otelResourceProperties) {
|
||||
return new SpringResourceProvider(otelSpringResourceProperties, otelResourceProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.util.Collections;
|
|||
import java.util.Map;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "otel.springboot.resource")
|
||||
@ConfigurationProperties(prefix = "otel.resource")
|
||||
public class OtelResourceProperties {
|
||||
private Map<String, String> attributes = Collections.emptyMap();
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "otel.springboot.resource")
|
||||
public class OtelSpringResourceProperties {
|
||||
private Map<String, String> attributes = Collections.emptyMap();
|
||||
|
||||
public Map<String, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(Map<String, String> attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
}
|
|
@ -11,30 +11,32 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
|||
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.semconv.ResourceAttributes;
|
||||
import java.util.Map;
|
||||
|
||||
public class SpringResourceProvider implements ResourceProvider {
|
||||
|
||||
private final OtelSpringResourceProperties otelSpringResourceProperties;
|
||||
private final OtelResourceProperties otelResourceProperties;
|
||||
|
||||
public SpringResourceProvider(OtelResourceProperties otelResourceProperties) {
|
||||
public SpringResourceProvider(
|
||||
OtelSpringResourceProperties otelSpringResourceProperties,
|
||||
OtelResourceProperties otelResourceProperties) {
|
||||
this.otelSpringResourceProperties = otelSpringResourceProperties;
|
||||
this.otelResourceProperties = otelResourceProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource createResource(ConfigProperties configProperties) {
|
||||
String applicationName = configProperties.getString("spring.application.name");
|
||||
Map<String, String> attributes = otelResourceProperties.getAttributes();
|
||||
AttributesBuilder attributesBuilder = Attributes.builder();
|
||||
attributes.forEach(attributesBuilder::put);
|
||||
return defaultResource(applicationName).merge(Resource.create(attributesBuilder.build()));
|
||||
}
|
||||
|
||||
private static Resource defaultResource(String applicationName) {
|
||||
if (applicationName == null) {
|
||||
return Resource.getDefault();
|
||||
String springApplicationName = configProperties.getString("spring.application.name");
|
||||
if (springApplicationName != null) {
|
||||
attributesBuilder.put(ResourceAttributes.SERVICE_NAME, springApplicationName);
|
||||
}
|
||||
return Resource.getDefault()
|
||||
.merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName)));
|
||||
otelSpringResourceProperties.getAttributes().forEach(attributesBuilder::put);
|
||||
otelResourceProperties.getAttributes().forEach(attributesBuilder::put);
|
||||
String applicationName = configProperties.getString("otel.service.name");
|
||||
if (applicationName != null) {
|
||||
attributesBuilder.put(ResourceAttributes.SERVICE_NAME, applicationName);
|
||||
}
|
||||
return Resource.create(attributesBuilder.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.spring.autoconfigure;
|
||||
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.MapConverter;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Unconditionally create {@link MapConverter} bean, because the tests don't evaluate the
|
||||
* ConditionalOnBean annotation correctly.
|
||||
*/
|
||||
@Configuration
|
||||
public class MapConverterTestAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConfigurationPropertiesBinding
|
||||
public MapConverter mapConverter() {
|
||||
return new MapConverter();
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ class MetricExporterAutoConfigurationTest {
|
|||
void defaultConfiguration() {
|
||||
contextRunner.run(
|
||||
context -> {
|
||||
assertThat(context.getBean("otelOtlpGrpcMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
assertThat(context.getBean("otelOtlpMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
.as("OTLP exporter is enabled by default")
|
||||
.isNotNull();
|
||||
assertThat(context.containsBean("otelLoggingMetricExporter"))
|
||||
|
@ -43,8 +43,7 @@ class MetricExporterAutoConfigurationTest {
|
|||
.withPropertyValues("otel.exporter.logging.enabled=true")
|
||||
.run(
|
||||
context -> {
|
||||
assertThat(
|
||||
context.getBean("otelOtlpGrpcMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
assertThat(context.getBean("otelOtlpMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
.as("OTLP exporter is present even with logging enabled")
|
||||
.isNotNull();
|
||||
assertThat(context.getBean("otelLoggingMetricExporter", LoggingMetricExporter.class))
|
||||
|
|
|
@ -28,7 +28,7 @@ class SpanExporterAutoConfigurationTest {
|
|||
void defaultConfiguration() {
|
||||
contextRunner.run(
|
||||
context -> {
|
||||
assertThat(context.getBean("otelOtlpGrpcSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
assertThat(context.getBean("otelOtlpSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
.as("OTLP exporter is enabled by default")
|
||||
.isNotNull();
|
||||
assertThat(context.containsBean("otelLoggingSpanExporter"))
|
||||
|
@ -43,7 +43,7 @@ class SpanExporterAutoConfigurationTest {
|
|||
.withPropertyValues("otel.exporter.logging.enabled=true")
|
||||
.run(
|
||||
context -> {
|
||||
assertThat(context.getBean("otelOtlpGrpcSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
assertThat(context.getBean("otelOtlpSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
.as("OTLP exporter is present even with logging enabled")
|
||||
.isNotNull();
|
||||
assertThat(context.getBean("otelLoggingSpanExporter", LoggingSpanExporter.class))
|
||||
|
|
|
@ -61,12 +61,20 @@ class JaegerSpanExporterAutoConfigurationTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("when exporters are DISABLED should NOT initialize JaegerGrpcSpanExporter bean")
|
||||
void disabledProperty() {
|
||||
void disabledPropertyOld() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("otel.exporter.jaeger.enabled=false")
|
||||
.run(context -> assertThat(context.containsBean("otelJaegerSpanExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("when exporters are DISABLED should NOT initialize JaegerGrpcSpanExporter bean")
|
||||
void disabledProperty() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("otel.traces.exporter=none")
|
||||
.run(context -> assertThat(context.containsBean("otelJaegerSpanExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName(
|
||||
"when jaeger enabled property is MISSING should initialize JaegerGrpcSpanExporter bean")
|
||||
|
|
|
@ -22,6 +22,17 @@ class LoggingMetricExporterAutoConfigurationTest {
|
|||
OpenTelemetryAutoConfiguration.class,
|
||||
LoggingMetricExporterAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void loggingEnabledNew() {
|
||||
runner
|
||||
.withPropertyValues("otel.metrics.exporter=logging")
|
||||
.run(
|
||||
context ->
|
||||
assertThat(
|
||||
context.getBean("otelLoggingMetricExporter", LoggingMetricExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
void loggingEnabled() {
|
||||
runner
|
||||
|
|
|
@ -24,6 +24,16 @@ class LoggingSpanExporterAutoConfigurationTest {
|
|||
OpenTelemetryAutoConfiguration.class,
|
||||
LoggingSpanExporterAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void loggingEnabledNew() {
|
||||
contextRunner
|
||||
.withPropertyValues("otel.traces.exporter=logging")
|
||||
.run(
|
||||
context ->
|
||||
assertThat(context.getBean("otelLoggingSpanExporter", LoggingSpanExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("when exporters are ENABLED should initialize LoggingSpanExporter bean")
|
||||
void loggingEnabled() {
|
||||
|
|
|
@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
|
||||
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.Test;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
@ -27,9 +28,7 @@ class OtlpLogExporterAutoConfigurationTest {
|
|||
.withPropertyValues("otel.exporter.otlp.enabled=true")
|
||||
.run(
|
||||
context ->
|
||||
assertThat(
|
||||
context.getBean(
|
||||
"otelOtlpGrpcLogRecordExporter", OtlpGrpcLogRecordExporter.class))
|
||||
assertThat(context.getBean("otelOtlpLogRecordExporter", LogRecordExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
|
||||
|
@ -39,9 +38,7 @@ class OtlpLogExporterAutoConfigurationTest {
|
|||
.withPropertyValues("otel.exporter.otlp.logs.enabled=true")
|
||||
.run(
|
||||
context ->
|
||||
assertThat(
|
||||
context.getBean(
|
||||
"otelOtlpGrpcLogRecordExporter", OtlpGrpcLogRecordExporter.class))
|
||||
assertThat(context.getBean("otelOtlpLogRecordExporter", LogRecordExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
|
||||
|
@ -49,16 +46,21 @@ class OtlpLogExporterAutoConfigurationTest {
|
|||
void otlpDisabled() {
|
||||
runner
|
||||
.withPropertyValues("otel.exporter.otlp.enabled=false")
|
||||
.run(
|
||||
context -> assertThat(context.containsBean("otelOtlpGrpcLogRecordExporter")).isFalse());
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpLogRecordExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void otlpLogsDisabledOld() {
|
||||
runner
|
||||
.withPropertyValues("otel.exporter.otlp.logs.enabled=false")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpLogRecordExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void otlpLogsDisabled() {
|
||||
runner
|
||||
.withPropertyValues("otel.exporter.otlp.logs.enabled=false")
|
||||
.run(
|
||||
context -> assertThat(context.containsBean("otelOtlpGrpcLogRecordExporter")).isFalse());
|
||||
.withPropertyValues("otel.logs.exporter=none")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpLogRecordExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -66,8 +68,7 @@ class OtlpLogExporterAutoConfigurationTest {
|
|||
runner.run(
|
||||
context ->
|
||||
assertThat(
|
||||
context.getBean(
|
||||
"otelOtlpGrpcLogRecordExporter", OtlpGrpcLogRecordExporter.class))
|
||||
context.getBean("otelOtlpLogRecordExporter", OtlpGrpcLogRecordExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,7 @@ class OtlpMetricExporterAutoConfigurationTest {
|
|||
.withPropertyValues("otel.exporter.otlp.enabled=true")
|
||||
.run(
|
||||
context ->
|
||||
assertThat(
|
||||
context.getBean("otelOtlpGrpcMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
assertThat(context.getBean("otelOtlpMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
|
||||
|
@ -38,8 +37,7 @@ class OtlpMetricExporterAutoConfigurationTest {
|
|||
.withPropertyValues("otel.exporter.otlp.metrics.enabled=true")
|
||||
.run(
|
||||
context ->
|
||||
assertThat(
|
||||
context.getBean("otelOtlpGrpcMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
assertThat(context.getBean("otelOtlpMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
|
||||
|
@ -47,21 +45,28 @@ class OtlpMetricExporterAutoConfigurationTest {
|
|||
void otlpDisabled() {
|
||||
runner
|
||||
.withPropertyValues("otel.exporter.otlp.enabled=false")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpGrpcMetricExporter")).isFalse());
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpMetricExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void otlpMetricsDisabledOld() {
|
||||
runner
|
||||
.withPropertyValues("otel.exporter.otlp.metrics.enabled=false")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpMetricExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void otlpMetricsDisabled() {
|
||||
runner
|
||||
.withPropertyValues("otel.exporter.otlp.metrics.enabled=false")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpGrpcMetricExporter")).isFalse());
|
||||
.withPropertyValues("otel.metrics.exporter=none")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpMetricExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void exporterPresentByDefault() {
|
||||
runner.run(
|
||||
context ->
|
||||
assertThat(context.getBean("otelOtlpGrpcMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
assertThat(context.getBean("otelOtlpMetricExporter", OtlpGrpcMetricExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,21 +7,32 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
|
|||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
|
||||
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;
|
||||
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.MapConverterTestAutoConfiguration;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
|
||||
import io.opentelemetry.sdk.trace.export.SpanExporter;
|
||||
import java.util.stream.Collectors;
|
||||
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 OtlpHttpSpanExporterBuilder otlpHttpSpanExporterBuilder =
|
||||
Mockito.mock(OtlpHttpSpanExporterBuilder.class);
|
||||
private final ApplicationContextRunner contextRunner =
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(
|
||||
OpenTelemetryAutoConfiguration.class, OtlpSpanExporterAutoConfiguration.class));
|
||||
OpenTelemetryAutoConfiguration.class,
|
||||
OtlpSpanExporterAutoConfiguration.class,
|
||||
MapConverterTestAutoConfiguration.class))
|
||||
.withBean(OtlpHttpSpanExporterBuilder.class, () -> otlpHttpSpanExporterBuilder);
|
||||
|
||||
@Test
|
||||
@DisplayName("when exporters are ENABLED should initialize OtlpGrpcSpanExporter bean")
|
||||
|
@ -30,8 +41,10 @@ class OtlpSpanExporterAutoConfigurationTest {
|
|||
.withPropertyValues("otel.exporter.otlp.enabled=true")
|
||||
.run(
|
||||
context ->
|
||||
assertThat(context.getBean("otelOtlpGrpcSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
assertThat(context.getBean("otelOtlpSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
.isNotNull());
|
||||
|
||||
Mockito.verifyNoMoreInteractions(otlpHttpSpanExporterBuilder);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -40,7 +53,7 @@ class OtlpSpanExporterAutoConfigurationTest {
|
|||
.withPropertyValues("otel.exporter.otlp.traces.enabled=true")
|
||||
.run(
|
||||
context ->
|
||||
assertThat(context.getBean("otelOtlpGrpcSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
assertThat(context.getBean("otelOtlpSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
|
||||
|
@ -49,14 +62,21 @@ class OtlpSpanExporterAutoConfigurationTest {
|
|||
void otlpDisabled() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("otel.exporter.otlp.enabled=false")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpGrpcSpanExporter")).isFalse());
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpSpanExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void otlpTracesDisabledOld() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("otel.exporter.otlp.traces.enabled=false")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpSpanExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void otlpTracesDisabled() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("otel.exporter.otlp.traces.enabled=false")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpGrpcSpanExporter")).isFalse());
|
||||
.withPropertyValues("otel.traces.exporter=none")
|
||||
.run(context -> assertThat(context.containsBean("otelOtlpSpanExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -64,7 +84,57 @@ class OtlpSpanExporterAutoConfigurationTest {
|
|||
void exporterPresentByDefault() {
|
||||
this.contextRunner.run(
|
||||
context ->
|
||||
assertThat(context.getBean("otelOtlpGrpcSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
assertThat(context.getBean("otelOtlpSpanExporter", OtlpGrpcSpanExporter.class))
|
||||
.isNotNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("use http/protobuf when protocol set")
|
||||
void useHttp() {
|
||||
this.contextRunner
|
||||
.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 -> {});
|
||||
|
||||
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
|
||||
.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);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("logging exporter can still be configured")
|
||||
void loggingExporter() {
|
||||
this.contextRunner
|
||||
.withBean(LoggingSpanExporter.class, LoggingSpanExporter::create)
|
||||
.run(
|
||||
context ->
|
||||
assertThat(
|
||||
context.getBeanProvider(SpanExporter.class).stream()
|
||||
.collect(Collectors.toList()))
|
||||
.hasSize(2));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,12 +53,20 @@ class ZipkinSpanExporterAutoConfigurationTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("when exporters are DISABLED should NOT initialize ZipkinSpanExporter bean")
|
||||
void disabledProperty() {
|
||||
void disabledPropertyOld() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("otel.exporter.zipkin.enabled=false")
|
||||
.run(context -> assertThat(context.containsBean("otelZipkinSpanExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("when exporters are DISABLED should NOT initialize ZipkinSpanExporter bean")
|
||||
void disabledProperty() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("otel.traces.exporter=none")
|
||||
.run(context -> assertThat(context.containsBean("otelZipkinSpanExporter")).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("when zipkin enabled property is MISSING should initialize ZipkinSpanExporter bean")
|
||||
void noProperty() {
|
||||
|
|
|
@ -8,6 +8,11 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.instrumentation.spring.autoconfigure.MapConverterTestAutoConfiguration;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
|
@ -17,7 +22,9 @@ public class OtelResourcePropertiesTest {
|
|||
private final ApplicationContextRunner contextRunner =
|
||||
new ApplicationContextRunner()
|
||||
.withPropertyValues("otel.springboot.resource.enabled=true")
|
||||
.withConfiguration(AutoConfigurations.of(OtelResourceAutoConfiguration.class));
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(
|
||||
OtelResourceAutoConfiguration.class, MapConverterTestAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
@DisplayName("when attributes are SET should set OtelResourceProperties with given attributes")
|
||||
|
@ -25,20 +32,29 @@ public class OtelResourcePropertiesTest {
|
|||
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"otel.springboot.resource.attributes.environment=dev",
|
||||
"otel.springboot.resource.attributes.xyz=foo",
|
||||
"otel.springboot.resource.attributes.service.name=backend-name",
|
||||
"otel.resource.attributes=foo=bar,environment=dev,service.name=hidden2",
|
||||
"otel.springboot.resource.attributes.foo=baz", // hidden by otel.resource.attributes
|
||||
"otel.springboot.resource.attributes.service.name=hidden1",
|
||||
"otel.springboot.resource.attributes.service.instance.id=id-example")
|
||||
.run(
|
||||
context -> {
|
||||
OtelResourceProperties propertiesBean = context.getBean(OtelResourceProperties.class);
|
||||
ResourceProvider resource =
|
||||
context.getBean("otelResourceProvider", ResourceProvider.class);
|
||||
|
||||
assertThat(propertiesBean.getAttributes())
|
||||
assertThat(
|
||||
resource
|
||||
.createResource(
|
||||
DefaultConfigProperties.createFromMap(
|
||||
ImmutableMap.of(
|
||||
"spring.application.name", "hidden0",
|
||||
"otel.service.name", "backend")))
|
||||
.getAttributes()
|
||||
.asMap())
|
||||
.contains(
|
||||
entry("environment", "dev"),
|
||||
entry("xyz", "foo"),
|
||||
entry("service.name", "backend-name"),
|
||||
entry("service.instance.id", "id-example"));
|
||||
entry(AttributeKey.stringKey("foo"), "bar"),
|
||||
entry(AttributeKey.stringKey("environment"), "dev"),
|
||||
entry(AttributeKey.stringKey("service.name"), "backend"),
|
||||
entry(AttributeKey.stringKey("service.instance.id"), "id-example"));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -48,6 +64,7 @@ public class OtelResourcePropertiesTest {
|
|||
|
||||
this.contextRunner.run(
|
||||
context ->
|
||||
assertThat(context.getBean(OtelResourceProperties.class).getAttributes()).isEmpty());
|
||||
assertThat(context.getBean(OtelSpringResourceProperties.class).getAttributes())
|
||||
.isEmpty());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class SpringBootSmokeTest extends SmokeTest {
|
|||
|
||||
@Override
|
||||
protected Map<String, String> getExtraEnv() {
|
||||
return Collections.singletonMap("OTEL_METRICS_EXPORTER", "otlp")
|
||||
return ["OTEL_METRICS_EXPORTER": "otlp", "OTEL_RESOURCE_ATTRIBUTES": "foo=bar"]
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,6 +87,13 @@ class SpringBootSmokeTest extends SmokeTest {
|
|||
metrics.hasMetricsNamed("jvm.memory.limit")
|
||||
metrics.hasMetricsNamed("jvm.memory.used_after_last_gc")
|
||||
|
||||
then: "resource attributes are read from the environment"
|
||||
def foo = findResourceAttribute(traces, "foo")
|
||||
.map { it.stringValue }
|
||||
.findAny()
|
||||
foo.isPresent()
|
||||
foo.get() == "bar"
|
||||
|
||||
then: "service name is autodetected"
|
||||
def serviceName = findResourceAttribute(traces, "service.name")
|
||||
.map { it.stringValue }
|
||||
|
|
Loading…
Reference in New Issue