Add configuration to put baggage automatically to MDC

with this change it's enough to set a property to automatically propagate a baggage key to MDC

fixes gh-1071
This commit is contained in:
Marcin Grzejszczak
2018-08-23 16:42:01 +02:00
parent 5b6a4f2767
commit 713544703a
5 changed files with 91 additions and 16 deletions

View File

@@ -420,6 +420,11 @@ There are two properties to achieve this.
With the `spring.sleuth.baggage-keys`, you set keys that get prefixed with `baggage-` for HTTP calls and `baggage_` for messaging.
You can also use the `spring.sleuth.propagation-keys` property to pass a list of prefixed keys that are whitelisted without any prefix.
In order to automatically set the baggage values to Slf4j's MDC, you have to set
the `spring.sleuth.log.slf4j.whitelisted-mdc-keys` property with a list of whitelisted
baggage keys. E.g. `spring.sleuth.log.slf4j.whitelisted-mdc-keys=foo` will set the value of the
`foo` baggage into MDC.
==== Extracting a Propagated Context
The `TraceContext.Extractor<C>` reads trace identifiers and sampling status from an incoming request or message.

View File

@@ -22,6 +22,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -47,8 +48,9 @@ public class SleuthLogAutoConfiguration {
@Bean
@ConditionalOnProperty(value = "spring.sleuth.log.slf4j.enabled", matchIfMissing = true)
public CurrentTraceContext.ScopeDecorator slf4jSpanDecorator() {
return new Slf4jScopeDecorator();
public CurrentTraceContext.ScopeDecorator slf4jSpanDecorator(SleuthProperties sleuthProperties,
SleuthSlf4jProperties sleuthSlf4jProperties) {
return new Slf4jScopeDecorator(sleuthProperties, sleuthSlf4jProperties);
}
}
}

View File

@@ -16,6 +16,9 @@
package org.springframework.cloud.sleuth.log;
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@@ -28,10 +31,15 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
public class SleuthSlf4jProperties {
/**
* Enable a {@link Slf4jCurrentTraceContext} that prints tracing information in the logs.
* Enable a {@link Slf4jScopeDecorator} that prints tracing information in the logs.
*/
private boolean enabled = true;
/**
* A list of keys to be put from baggage to MDC
*/
private List<String> whitelistedMdcKeys = new ArrayList<>();
public boolean isEnabled() {
return this.enabled;
}
@@ -39,4 +47,12 @@ public class SleuthSlf4jProperties {
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public List<String> getWhitelistedMdcKeys() {
return this.whitelistedMdcKeys;
}
public void setWhitelistedMdcKeys(List<String> whitelistedMdcKeys) {
this.whitelistedMdcKeys = whitelistedMdcKeys;
}
}

View File

@@ -16,13 +16,21 @@
package org.springframework.cloud.sleuth.log;
import java.util.AbstractMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import brave.internal.HexCodec;
import brave.internal.Nullable;
import brave.propagation.CurrentTraceContext;
import brave.propagation.ExtraFieldPropagation;
import brave.propagation.TraceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
import org.springframework.util.StringUtils;
/**
* Adds {@linkplain MDC} properties "traceId", "parentId", "spanId" and "spanExportable" when a {@link
@@ -44,6 +52,14 @@ final class Slf4jScopeDecorator implements CurrentTraceContext.ScopeDecorator {
private static final Logger log = LoggerFactory.getLogger(Slf4jScopeDecorator.class);
private final SleuthProperties sleuthProperties;
private final SleuthSlf4jProperties sleuthSlf4jProperties;
Slf4jScopeDecorator(SleuthProperties sleuthProperties, SleuthSlf4jProperties sleuthSlf4jProperties) {
this.sleuthProperties = sleuthProperties;
this.sleuthSlf4jProperties = sleuthSlf4jProperties;
}
@Override public CurrentTraceContext.Scope decorateScope(TraceContext currentSpan,
CurrentTraceContext.Scope scope) {
final String previousTraceId = MDC.get("traceId");
@@ -54,6 +70,10 @@ final class Slf4jScopeDecorator implements CurrentTraceContext.ScopeDecorator {
final String legacyPreviousParentId = MDC.get(LEGACY_PARENT_ID_NAME);
final String legacyPreviousSpanId = MDC.get(LEGACY_SPAN_ID_NAME);
final String legacySpanExportable = MDC.get(LEGACY_EXPORTABLE_NAME);
final List<AbstractMap.SimpleEntry<String, String>> previousMdc =
whitelistedBaggageKeys(currentSpan)
.map(s -> new AbstractMap.SimpleEntry<>(s, MDC.get(s)))
.collect(Collectors.toList());
if (currentSpan != null) {
String traceIdString = currentSpan.traceIdString();
@@ -76,6 +96,8 @@ final class Slf4jScopeDecorator implements CurrentTraceContext.ScopeDecorator {
log.trace("With parent: {}", currentSpan.parentId());
}
}
whitelistedBaggageKeys(currentSpan)
.forEach(s -> MDC.put(s, ExtraFieldPropagation.get(currentSpan, s)));
}
else {
MDC.remove("traceId");
@@ -86,6 +108,7 @@ final class Slf4jScopeDecorator implements CurrentTraceContext.ScopeDecorator {
MDC.remove(LEGACY_PARENT_ID_NAME);
MDC.remove(LEGACY_SPAN_ID_NAME);
MDC.remove(LEGACY_EXPORTABLE_NAME);
whitelistedBaggageKeys(currentSpan).forEach(MDC::remove);
}
class ThreadContextCurrentTraceContextScope implements CurrentTraceContext.Scope {
@@ -100,11 +123,18 @@ final class Slf4jScopeDecorator implements CurrentTraceContext.ScopeDecorator {
replace(LEGACY_PARENT_ID_NAME, legacyPreviousParentId);
replace(LEGACY_SPAN_ID_NAME, legacyPreviousSpanId);
replace(LEGACY_EXPORTABLE_NAME, legacySpanExportable);
previousMdc.forEach(e -> replace(e.getKey(), e.getValue()));
}
}
return new ThreadContextCurrentTraceContextScope();
}
private Stream<String> whitelistedBaggageKeys(TraceContext context) {
return this.sleuthProperties.getBaggageKeys().stream()
.filter(s -> this.sleuthSlf4jProperties.getWhitelistedMdcKeys().contains(s) &&
context != null && StringUtils.hasText(ExtraFieldPropagation.get(context, s)));
}
private void log(String text, TraceContext span) {
if (span == null) {
return;

View File

@@ -17,43 +17,53 @@
package org.springframework.cloud.sleuth.log;
import brave.Span;
import brave.Tracing;
import brave.Tracer;
import brave.propagation.CurrentTraceContext.Scope;
import brave.propagation.StrictCurrentTraceContext;
import brave.propagation.ExtraFieldPropagation;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.MDC;
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Marcin Grzejszczak
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE,
properties = {
"spring.sleuth.baggage-keys=my-baggage",
"spring.sleuth.log.slf4j.whitelisted-mdc-keys=my-baggage"
})
@SpringBootConfiguration
@EnableAutoConfiguration
public class Slf4JSpanLoggerTest {
ArrayListSpanReporter reporter = new ArrayListSpanReporter();
Tracing tracing = Tracing.newBuilder()
.currentTraceContext(new StrictCurrentTraceContext())
.spanReporter(this.reporter)
.build();
Span span = this.tracing.tracer().nextSpan().name("span").start();
Slf4jScopeDecorator slf4jScopeDecorator = new Slf4jScopeDecorator();
@Autowired Tracer tracer;
@Autowired Slf4jScopeDecorator slf4jScopeDecorator;
Span span;
@Before
@After
public void setup() {
MDC.clear();
this.span = this.tracer.nextSpan().name("span").start();
}
@Test
public void should_set_entries_to_mdc_from_span() throws Exception {
Scope scope = this.slf4jScopeDecorator.decorateScope(this.span.context(), () -> { });
assertThat(MDC.get("X-B3-TraceId")).isEqualTo(span.context().traceIdString());
assertThat(MDC.get("traceId")).isEqualTo(span.context().traceIdString());
assertThat(MDC.get("X-B3-TraceId")).isEqualTo(this.span.context().traceIdString());
assertThat(MDC.get("traceId")).isEqualTo(this.span.context().traceIdString());
scope.close();
@@ -61,6 +71,18 @@ public class Slf4JSpanLoggerTest {
assertThat(MDC.get("traceId")).isNullOrEmpty();
}
@Test
public void should_set_entries_to_mdc_from_span_with_baggage() throws Exception {
ExtraFieldPropagation.set(this.span.context(), "my-baggage", "my-value");
Scope scope = this.slf4jScopeDecorator.decorateScope(this.span.context(), () -> { });
assertThat(MDC.get("my-baggage")).isEqualTo("my-value");
scope.close();
assertThat(MDC.get("my-baggage")).isNullOrEmpty();
}
@Test
public void should_remove_entries_from_mdc_from_null_span() throws Exception {
MDC.put("X-B3-TraceId", "A");