mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Merge pull request #50595 from philsttr
Closes gh-50595 * pr/50595: Polish "Allow configuring Micrometer Tracing MDC keys" Allow configuring Micrometer Tracing MDC keys
This commit is contained in:
+7
@@ -75,7 +75,14 @@ If you are using Micrometer Tracing, Spring Boot will include correlation IDs in
|
||||
The default correlation ID is built from `traceId` and `spanId` https://logback.qos.ch/manual/mdc.html[MDC] values.
|
||||
For example, if Micrometer Tracing has added an MDC `traceId` of `803B448A0489F84084905D3093480352` and an MDC `spanId` of `3425F23BB2432450` the log output will include the correlation ID `[803B448A0489F84084905D3093480352-3425F23BB2432450]`.
|
||||
|
||||
The `traceId` and `spanId` MDC key names can be customized using the configprop:management.tracing.mdc.trace-id-key[] and configprop:management.tracing.mdc.span-id-key[] properties.
|
||||
The default correlation ID format follows those keys automatically, padding them to 32 and 16 characters respectively, so log correlation keeps working without further configuration.
|
||||
|
||||
NOTE: With Brave, the MDC key names are only applied when baggage is enabled.
|
||||
Setting configprop:management.tracing.baggage.enabled[] to `false` stops Brave from writing the trace and span IDs to the MDC altogether, which disables log correlation.
|
||||
|
||||
If you prefer to use a different format for your correlation ID, you can use the configprop:logging.pattern.correlation[] property to define one.
|
||||
A value that you set yourself takes precedence over the format derived from the MDC key names, so it has to reference any customized key names itself.
|
||||
For example, the following will provide a correlation ID for Logback in format previously used by Spring Cloud Sleuth:
|
||||
|
||||
[configprops,yaml]
|
||||
|
||||
+8
@@ -19,6 +19,7 @@ package org.springframework.boot.micrometer.tracing.brave.autoconfigure;
|
||||
import java.util.List;
|
||||
|
||||
import brave.baggage.BaggageField;
|
||||
import brave.baggage.BaggageFields;
|
||||
import brave.baggage.BaggagePropagation;
|
||||
import brave.baggage.BaggagePropagation.FactoryBuilder;
|
||||
import brave.baggage.BaggagePropagationConfig;
|
||||
@@ -40,6 +41,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport;
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Baggage.Correlation;
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Mdc;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -138,7 +140,13 @@ class BravePropagationConfigurations {
|
||||
@ConditionalOnMissingBean
|
||||
CorrelationScopeDecorator.Builder mdcCorrelationScopeDecoratorBuilder(
|
||||
ObjectProvider<CorrelationScopeCustomizer> correlationScopeCustomizers) {
|
||||
Mdc mdc = this.tracingProperties.getMdc();
|
||||
CorrelationScopeDecorator.Builder builder = MDCScopeDecorator.newBuilder();
|
||||
if (mdc.isCustomized()) {
|
||||
builder.clear()
|
||||
.add(SingleCorrelationField.newBuilder(BaggageFields.TRACE_ID).name(mdc.getTraceIdKey()).build())
|
||||
.add(SingleCorrelationField.newBuilder(BaggageFields.SPAN_ID).name(mdc.getSpanIdKey()).build());
|
||||
}
|
||||
correlationScopeCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder;
|
||||
}
|
||||
|
||||
+16
@@ -26,8 +26,10 @@ import brave.Span;
|
||||
import brave.SpanCustomizer;
|
||||
import brave.Tracer;
|
||||
import brave.Tracing;
|
||||
import brave.baggage.BaggageFields;
|
||||
import brave.baggage.BaggagePropagation;
|
||||
import brave.baggage.CorrelationScopeConfig.SingleCorrelationField;
|
||||
import brave.context.slf4j.MDCScopeDecorator;
|
||||
import brave.handler.SpanHandler;
|
||||
import brave.propagation.CurrentTraceContext;
|
||||
import brave.propagation.CurrentTraceContext.ScopeDecorator;
|
||||
@@ -258,6 +260,20 @@ class BraveAutoConfigurationTests {
|
||||
.run((context) -> assertThat(context).hasBean("mdcCorrelationScopeDecoratorBuilder"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Guards the assumption behind the {@code clear()} call that
|
||||
* {@code BravePropagationConfigurations} makes when the MDC keys have been
|
||||
* customized: if Brave ever adds another default correlation field, this fails
|
||||
* instead of that field silently disappearing from the MDC of applications using
|
||||
* custom keys.
|
||||
*/
|
||||
@Test
|
||||
void shouldOnlyHaveTraceIdAndSpanIdCorrelationFieldsByDefaultInBrave() {
|
||||
assertThat(MDCScopeDecorator.newBuilder().configs())
|
||||
.extracting((config) -> ((SingleCorrelationField) config).name())
|
||||
.containsExactlyInAnyOrder(BaggageFields.TRACE_ID.name(), BaggageFields.SPAN_ID.name());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHave128BitTraceId() {
|
||||
this.contextRunner.run((context) -> {
|
||||
|
||||
+23
@@ -24,6 +24,7 @@ import io.micrometer.tracing.Span;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.slf4j.MDC;
|
||||
@@ -79,6 +80,28 @@ class BraveBaggagePropagationIntegrationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseCustomMdcKeysForTraceAndSpanId() {
|
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(BraveAutoConfiguration.class))
|
||||
.withPropertyValues("management.tracing.mdc.trace-id-key=customTraceId",
|
||||
"management.tracing.mdc.span-id-key=customSpanId")
|
||||
.run((context) -> {
|
||||
Tracer tracer = tracer(context);
|
||||
Span span = createSpan(tracer);
|
||||
try (Tracer.SpanInScope scope = tracer.withSpan(span.start())) {
|
||||
assertMdcValue("customTraceId", span.context().traceId());
|
||||
assertMdcValue("customSpanId", span.context().spanId());
|
||||
assertUnsetMdc("traceId");
|
||||
assertUnsetMdc("spanId");
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
assertUnsetMdc("customTraceId");
|
||||
assertUnsetMdc("customSpanId");
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource
|
||||
void shouldRemoveEntriesFromMdcForNullSpan(AutoConfig autoConfig) {
|
||||
|
||||
+3
-1
@@ -59,6 +59,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.NoopTracerAutoConfiguration;
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Mdc;
|
||||
import org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryPropagationConfigurations.NoPropagation;
|
||||
import org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryPropagationConfigurations.PropagationWithBaggage;
|
||||
import org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryPropagationConfigurations.PropagationWithoutBaggage;
|
||||
@@ -219,7 +220,8 @@ public final class OpenTelemetryTracingAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Slf4JEventListener otelSlf4JEventListener() {
|
||||
return new Slf4JEventListener();
|
||||
Mdc mdc = this.tracingProperties.getMdc();
|
||||
return new Slf4JEventListener(mdc.getTraceIdKey(), mdc.getSpanIdKey());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+25
@@ -26,6 +26,7 @@ import io.opentelemetry.context.Context;
|
||||
import org.assertj.core.api.ThrowingConsumer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.slf4j.MDC;
|
||||
@@ -85,6 +86,30 @@ class OpenTelemetryBaggagePropagationIntegrationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseCustomMdcKeysForTraceAndSpanId() {
|
||||
new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())
|
||||
.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,
|
||||
OpenTelemetryTracingAutoConfiguration.class))
|
||||
.withPropertyValues("management.tracing.mdc.trace-id-key=customTraceId",
|
||||
"management.tracing.mdc.span-id-key=customSpanId")
|
||||
.run((context) -> {
|
||||
Tracer tracer = tracer(context);
|
||||
Span span = createSpan(tracer);
|
||||
try (Tracer.SpanInScope scope = tracer.withSpan(span.start())) {
|
||||
assertMdcValue("customTraceId", span.context().traceId());
|
||||
assertMdcValue("customSpanId", span.context().spanId());
|
||||
assertUnsetMdc("traceId");
|
||||
assertUnsetMdc("spanId");
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
assertUnsetMdc("customTraceId");
|
||||
assertUnsetMdc("customSpanId");
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource
|
||||
void shouldRemoveEntriesFromMdcForNullSpan(AutoConfig autoConfig) {
|
||||
|
||||
+37
-3
@@ -21,6 +21,7 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.boot.EnvironmentPostProcessor;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.logging.LoggingSystem;
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Mdc;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -31,10 +32,13 @@ import org.springframework.util.ClassUtils;
|
||||
* {@link EnvironmentPostProcessor} to add a {@link PropertySource} to support log
|
||||
* correlation IDs when Micrometer Tracing is present. Adds support for the
|
||||
* {@value LoggingSystem#EXPECT_CORRELATION_ID_PROPERTY} property by delegating to
|
||||
* {@code management.tracing.export.enabled}.
|
||||
* {@code management.tracing.export.enabled}, and defaults
|
||||
* {@code logging.pattern.correlation} to the MDC keys configured through
|
||||
* {@code management.tracing.mdc.*}.
|
||||
*
|
||||
* @author Jonatan Ivanov
|
||||
* @author Phillip Webb
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class LogCorrelationEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
@@ -52,6 +56,18 @@ class LogCorrelationEnvironmentPostProcessor implements EnvironmentPostProcessor
|
||||
|
||||
private static final String NAME = "logCorrelation";
|
||||
|
||||
private static final String CORRELATION_PATTERN_PROPERTY = "logging.pattern.correlation";
|
||||
|
||||
/**
|
||||
* Expected trace ID length, matching {@code CorrelationIdFormatter.DEFAULT}.
|
||||
*/
|
||||
private static final int TRACE_ID_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* Expected span ID length, matching {@code CorrelationIdFormatter.DEFAULT}.
|
||||
*/
|
||||
private static final int SPAN_ID_LENGTH = 16;
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
LogCorrelationPropertySource(Object source, Environment environment) {
|
||||
@@ -61,17 +77,35 @@ class LogCorrelationEnvironmentPostProcessor implements EnvironmentPostProcessor
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
return new String[] { LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY };
|
||||
return new String[] { LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, CORRELATION_PATTERN_PROPERTY };
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object getProperty(String name) {
|
||||
if (name.equals(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY)) {
|
||||
return this.environment.getProperty("management.tracing.export.enabled", Boolean.class, Boolean.TRUE);
|
||||
return isExpectCorrelationId();
|
||||
}
|
||||
if (name.equals(CORRELATION_PATTERN_PROPERTY)) {
|
||||
return getCorrelationPattern();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Boolean isExpectCorrelationId() {
|
||||
return this.environment.getProperty("management.tracing.export.enabled", Boolean.class, Boolean.TRUE);
|
||||
}
|
||||
|
||||
private @Nullable String getCorrelationPattern() {
|
||||
if (!isExpectCorrelationId()) {
|
||||
return null;
|
||||
}
|
||||
String traceIdKey = this.environment.getProperty("management.tracing.mdc.trace-id-key",
|
||||
Mdc.DEFAULT_TRACE_ID_KEY);
|
||||
String spanIdKey = this.environment.getProperty("management.tracing.mdc.span-id-key",
|
||||
Mdc.DEFAULT_SPAN_ID_KEY);
|
||||
return "%%correlationId{%s(%d),%s(%d)}".formatted(traceIdKey, TRACE_ID_LENGTH, spanIdKey, SPAN_ID_LENGTH);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+57
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Configuration properties for tracing.
|
||||
@@ -53,6 +54,11 @@ public class TracingProperties {
|
||||
*/
|
||||
private final Exemplars exemplars = new Exemplars();
|
||||
|
||||
/**
|
||||
* {@code org.slf4j.MDC} key configuration for trace and span IDs.
|
||||
*/
|
||||
private final Mdc mdc = new Mdc();
|
||||
|
||||
public Sampling getSampling() {
|
||||
return this.sampling;
|
||||
}
|
||||
@@ -69,6 +75,10 @@ public class TracingProperties {
|
||||
return this.exemplars;
|
||||
}
|
||||
|
||||
public Mdc getMdc() {
|
||||
return this.mdc;
|
||||
}
|
||||
|
||||
public static class Sampling {
|
||||
|
||||
/**
|
||||
@@ -258,6 +268,53 @@ public class TracingProperties {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code org.slf4j.MDC} key configuration for trace and span IDs.
|
||||
*/
|
||||
public static class Mdc {
|
||||
|
||||
static final String DEFAULT_TRACE_ID_KEY = "traceId";
|
||||
|
||||
static final String DEFAULT_SPAN_ID_KEY = "spanId";
|
||||
|
||||
/**
|
||||
* Key under which the trace ID is added to the {@code org.slf4j.MDC}.
|
||||
*/
|
||||
private String traceIdKey = DEFAULT_TRACE_ID_KEY;
|
||||
|
||||
/**
|
||||
* Key under which the span ID is added to the {@code org.slf4j.MDC}.
|
||||
*/
|
||||
private String spanIdKey = DEFAULT_SPAN_ID_KEY;
|
||||
|
||||
public String getTraceIdKey() {
|
||||
return this.traceIdKey;
|
||||
}
|
||||
|
||||
public void setTraceIdKey(String traceIdKey) {
|
||||
Assert.hasText(traceIdKey, "'traceIdKey' must not be empty");
|
||||
this.traceIdKey = traceIdKey;
|
||||
}
|
||||
|
||||
public String getSpanIdKey() {
|
||||
return this.spanIdKey;
|
||||
}
|
||||
|
||||
public void setSpanIdKey(String spanIdKey) {
|
||||
Assert.hasText(spanIdKey, "'spanIdKey' must not be empty");
|
||||
this.spanIdKey = spanIdKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether any of the keys differs from its default.
|
||||
* @return whether the keys have been customized
|
||||
*/
|
||||
public boolean isCustomized() {
|
||||
return !DEFAULT_TRACE_ID_KEY.equals(this.traceIdKey) || !DEFAULT_SPAN_ID_KEY.equals(this.spanIdKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Exemplars configuration.
|
||||
*/
|
||||
|
||||
+37
-1
@@ -34,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Jonatan Ivanov
|
||||
* @author Phillip Webb
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class LogCorrelationEnvironmentPostProcessorTests {
|
||||
|
||||
@@ -72,7 +73,42 @@ class LogCorrelationEnvironmentPostProcessorTests {
|
||||
PropertySource<?> propertySource = this.environment.getPropertySources().get("logCorrelation");
|
||||
assertThat(propertySource).isInstanceOf(EnumerablePropertySource.class);
|
||||
assertThat(((EnumerablePropertySource<?>) propertySource).getPropertyNames())
|
||||
.containsExactly(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY);
|
||||
.containsExactly(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, "logging.pattern.correlation");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCorrelationPatternWhenMdcKeysAreDefaultReturnsPatternUsingDefaultKeys() {
|
||||
this.postProcessor.postProcessEnvironment(this.environment, this.application);
|
||||
assertThat(this.environment.getProperty("logging.pattern.correlation"))
|
||||
.isEqualTo("%correlationId{traceId(32),spanId(16)}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCorrelationPatternWhenMdcKeysAreCustomizedReturnsPatternUsingThoseKeys() {
|
||||
TestPropertyValues
|
||||
.of("management.tracing.mdc.trace-id-key=customTraceId", "management.tracing.mdc.span-id-key=customSpanId")
|
||||
.applyTo(this.environment);
|
||||
this.postProcessor.postProcessEnvironment(this.environment, this.application);
|
||||
assertThat(this.environment.getProperty("logging.pattern.correlation"))
|
||||
.isEqualTo("%correlationId{customTraceId(32),customSpanId(16)}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCorrelationPatternWhenSetByUserDoesNotOverride() {
|
||||
TestPropertyValues
|
||||
.of("management.tracing.mdc.trace-id-key=customTraceId", "logging.pattern.correlation=%correlationId{x(1)}")
|
||||
.applyTo(this.environment);
|
||||
this.postProcessor.postProcessEnvironment(this.environment, this.application);
|
||||
assertThat(this.environment.getProperty("logging.pattern.correlation")).isEqualTo("%correlationId{x(1)}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCorrelationPatternWhenTracingDisabledReturnsNull() {
|
||||
TestPropertyValues
|
||||
.of("management.tracing.export.enabled=false", "management.tracing.mdc.trace-id-key=customTraceId")
|
||||
.applyTo(this.environment);
|
||||
this.postProcessor.postProcessEnvironment(this.environment, this.application);
|
||||
assertThat(this.environment.getProperty("logging.pattern.correlation")).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.micrometer.tracing.autoconfigure;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Mdc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link TracingProperties}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class TracingPropertiesTests {
|
||||
|
||||
private final Mdc mdc = new TracingProperties().getMdc();
|
||||
|
||||
@Test
|
||||
void shouldUseTraceIdAndSpanIdAsDefaultMdcKeys() {
|
||||
assertThat(this.mdc.getTraceIdKey()).isEqualTo("traceId");
|
||||
assertThat(this.mdc.getSpanIdKey()).isEqualTo("spanId");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotBeCustomizedWhenMdcKeysAreDefault() {
|
||||
assertThat(this.mdc.isCustomized()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeCustomizedWhenAnMdcKeyDiffersFromItsDefault() {
|
||||
this.mdc.setSpanIdKey("customSpanId");
|
||||
assertThat(this.mdc.isCustomized()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectBlankTraceIdKey() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.mdc.setTraceIdKey(" "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectBlankSpanIdKey() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.mdc.setSpanIdKey(" "));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,7 @@ dependencies {
|
||||
implementation(project(":starter:spring-boot-starter-opentelemetry"))
|
||||
|
||||
testImplementation(project(":starter:spring-boot-starter-test"))
|
||||
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||
testImplementation("io.micrometer:micrometer-registry-otlp")
|
||||
|
||||
dockerTestImplementation(project(":core:spring-boot-testcontainers"))
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.opentelemetry;
|
||||
|
||||
import io.micrometer.tracing.Span;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests that the correlation ID in the log output follows the MDC keys configured through
|
||||
* {@code management.tracing.mdc.*}.
|
||||
* <p>
|
||||
* Runs with a forked class path because {@code LOG_CORRELATION_PATTERN} is a JVM-wide
|
||||
* system property that is only ever written once, so a context started by another test
|
||||
* class would pin it to the default pattern.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
@SpringBootTest(properties = { "management.tracing.mdc.trace-id-key=customTraceId",
|
||||
"management.tracing.mdc.span-id-key=customSpanId" })
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
@ForkedClassPath
|
||||
class LogCorrelationTests {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(LogCorrelationTests.class);
|
||||
|
||||
@Autowired
|
||||
private Tracer tracer;
|
||||
|
||||
@Test
|
||||
void shouldUseCustomMdcKeysForCorrelationId(CapturedOutput output) {
|
||||
Span span = this.tracer.nextSpan().name("test");
|
||||
try (Tracer.SpanInScope scope = this.tracer.withSpan(span.start())) {
|
||||
logger.info("Hello from a span");
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
assertThat(output).containsPattern(
|
||||
"\\[%s-%s\\].*Hello from a span".formatted(span.context().traceId(), span.context().spanId()));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user