https://kotlinlang.org logo
#spring
Title
# spring
j

Jarle Hansen

10/11/2023, 12:23 PM
when using spring webflux and kotlin coroutines, I would like to add a header value to MDC. We already have a standard webfilter that adds the header value from the request to the reactor context. Now I want my app to read that value from the reactor-context and then put it on the MDC. I created my own WebFilter and using Mono.deferContextual I am able to get the value, like this:
Copy code
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
        return Mono.deferContextual {
            if (it.hasKey(MYID)) {
                MDC.putCloseable(MYID, it.get(MYID))
            }
            chain.filter(exchange)
        }
    }
The @RestControntroller functions are all suspended, and we are running netty (so full webflux). In the
async
code I have also added the MDCContext(), to make sure the MDC values are passed in. Is this a good solution? Are there any other pitfalls I need to be aware of? Or does anyone have a better implementation for this scenario
j

Jacob

10/11/2023, 1:16 PM
Consider using CoWebFilter
j

Jarle Hansen

10/11/2023, 1:22 PM
good idea, thanks!
k

Klitos Kyriacou

10/11/2023, 3:00 PM
As an aside, calling
putCloseable
without taking its return value is of no more use than a plain
put
.
j

Jarle Hansen

10/12/2023, 6:16 AM
yeah, get your point. its of no real use in this way, might as well use put
not sure what I am doing wrong here, but the MDC value is not available in the controller:
Copy code
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
class MyMdcFilter : CoWebFilter() {
    override suspend fun filter(exchange: ServerWebExchange, chain: CoWebFilterChain) =
        withContext(MDCContext()) {
            this.coroutineContext[ReactorContext]?.context?.let {
                if (it.hasKey(MYID)) {
                    MDC.put(
                        MYID, it.get(MYID)
                    )
                }
            }

            chain.filter(exchange)
        }
}
I can see that the MDC is populated, but is empty by the time the @RestController function is called
k

Klitos Kyriacou

10/12/2023, 8:46 AM
Could it be that the controller is running in a different thread? Each thread has its own separate MDC.
j

Jarle Hansen

10/12/2023, 8:49 AM
yeah you are most likely correct. not sure how to fix this really
b

Ben

10/12/2023, 4:19 PM
The filters run on a different context than the controllers. It isn't really possible to fix in the annotation controllers. You can kind of fix it in the functional controllers by just running the same filter before the controllers are called in the router. Hopefully this is fixed in the next version of spring. https://kotlinlang.slack.com/archives/C0B8ZTWE4/p1694083089231459
j

Jarle Hansen

10/13/2023, 6:32 AM
thanks for the info, very helpful. I am trying to solve it using
withLoggingContext
in the context of the controller function
21 Views