Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MDC vs Reactor's "Context" #77

Open
cristigirbovan opened this issue Oct 13, 2023 · 1 comment
Open

MDC vs Reactor's "Context" #77

cristigirbovan opened this issue Oct 13, 2023 · 1 comment
Assignees
Labels
good first issue Good for newcomers

Comments

@cristigirbovan
Copy link

cristigirbovan commented Oct 13, 2023

While setting an MDC value at the beginning of a request might seem straightforward, in a reactive context, I think it's essential to ensure that the MDC values are propagated across any thread switches that might occur during the request's lifecycle. Without proper propagation, you might end up with missing or incorrect log context in parts of your request processing. When you set a value in the MDC at the beginning of a reactive request, you're indeed setting it for the thread that initially handles the request. However, due to the nature of reactive programming, the processing of that request might get handed off to another thread at some point, especially if there are asynchronous operations involved, an I/O call, a delay, etc. I think even if the code/method itself doesn't contain asynchronous operations, external factors might cause thread switches. For instance, if the system is under heavy load, or if there are other tasks queued up in the event loop, the framework might decide to switch threads to optimize throughput. The MDC works by storing data in a ThreadLocal variable. This means the data is specific to the current thread. If the reactive processing switches to another thread, the MDC values set in the initial thread won't be available in the new thread, leading to potential issues or missing log context. Am I missing something?

So to optimize this I think we should use something like this:
return chain.filter(exchangeDecorator).contextWrite(ctx -> ctx.put("key", value))
...........................

But in the logback.xml we can add values to the pattern only if they are already in MDC, using %X{key} where key is the name of the value you've set in the MDC:

   <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %X{key} - %msg%n</pattern>

So, I think if we want to use the %X{key} pattern in Logback to log a value, that value must be present in the MDC. Even if the value is in the Reactor Context, you'll need to transfer it to the MDC before logging. But how to do that, what is the best way to implement this? Honestly I don't know, maybe:

  1. use a utility yo set the values to MDC

    public static void setContextToMDC(Context ctx, String key, String value) {
    MDC.clear();
    ctx.stream().forEach(entry -> MDC.put(key, value));
    }

  2. use reactor's doOnEach"
    return chain.filter(exchangeDecorator)
    .contextWrite(ctx -> ctx.put("key", "value"))
    .doOnEach(signal -> {
    if (signal.isOnNext() || signal.isOnError()) {
    setContextToMDC(signal.getContext(),"key","value");
    }
    });

Or maybe I'm wrong?!?
Thanks a lot

@piomin
Copy link
Owner

piomin commented Mar 22, 2024

Maybe you could propose it via a PR?

@piomin piomin added the good first issue Good for newcomers label Mar 22, 2024
@piomin piomin assigned piomin and cristigirbovan and unassigned piomin Mar 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

2 participants