Skip to content

Instantly share code, notes, and snippets.

@chemicL
Last active March 25, 2024 16:16
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chemicL/0e0d8e95e28414f0ecb769a5b8ca326e to your computer and use it in GitHub Desktop.
Save chemicL/0e0d8e95e28414f0ecb769a5b8ca326e to your computer and use it in GitHub Desktop.
Automatic context propagation with MDC using Project Reactor
// ...
dependencies {
implementation 'io.micrometer:context-propagation:1.0.6'
// ...
}
<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS} [%thread] [key=%X{key}] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="reactor" level="info"/>
<root level="info">
<appender-ref ref="stdout"/>
</root>
</configuration>
@Test
void testMDC() {
Logger log = LoggerFactory.getLogger("test");
Hooks.enableAutomaticContextPropagation();
// To deal with the entire MDC (if we ensured no third-party code modifies it):
// ContextRegistry.getInstance().registerThreadLocalAccessor(new MdcAccessor());
// To deal with an individual key in the MDC:
ContextRegistry.getInstance().registerThreadLocalAccessor(
"key",
() -> MDC.get("key"),
value -> MDC.put("key", value),
() -> MDC.remove("key"));
MDC.put("key", "Hello");
Mono.just("Delayed")
.delayElement(Duration.ofMillis(10))
.doOnNext(log::info)
// It is vital to capture MDC contents into Reactor's context
// as it is the source of truth for propagating ThreadLocals
//.contextCapture() // Can be skipped since reactor-core:3.5.7
.block();
}
// This implementation modifies the entire MDC.
// If any other code (especially third-party libraries) interacts with the MDC
// it would collide and the results will be corrupted.
// The best strategy is to pick specific keys instead of working on the entire MDC map.
static class MdcAccessor implements ThreadLocalAccessor<Map<String, String>> {
static final String KEY = "mdc";
@Override
public Object key() {
return KEY;
}
@Override
public Map<String, String> getValue() {
return MDC.getCopyOfContextMap();
}
@Override
public void setValue(Map<String, String> value) {
MDC.setContextMap(value);
}
@Override
public void reset() {
MDC.clear();
}
}
@imosapatryk
Copy link

I'll do! 👍 Btw. I've started wondering if Hooks.enableAutomaticContextPropagation(); may have impact on reactive transaction propagation...

@chemicL
Copy link
Author

chemicL commented Aug 30, 2023

be more specific please :)

@chemicL
Copy link
Author

chemicL commented Oct 2, 2023

@leakin185
https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Hooks.html#enableAutomaticContextPropagation--

Please make sure you're using the latest version :) reactor-core is now 3.5.10, and this feature was made available since 3.5.3. If it's missing, probably you're using an older version of the library.

@chemicL
Copy link
Author

chemicL commented Oct 12, 2023

I updated the gist to reflect the best practices.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment