Skip to content
Bluetape4k docs1.11

Coroutine MDC propagation

Latest stable Based on Bluetape4k release 1.11.0

Plain MDC cannot follow a coroutine to another thread because its state is thread-local. withCoroutineLoggingContext combines scoped MDC with MDCContext from kotlinx-coroutines-slf4j.

suspend fun handle(requestId: String) =
withCoroutineLoggingContext(
"requestId" to requestId,
"component" to "checkout",
) {
coroutineScope {
val stock = async(Dispatchers.IO) { inventory.load() }
val price = async(Dispatchers.Default) { pricing.load() }
log.info { "Composing checkout" }
stock.await() to price.await()
}
}

The helper runs the block inside withContext(MDCContext()). Child coroutines inherit their parent context, so the snapshot crosses dispatcher switches.

MDCContext captures MDC when the context is created. A plain MDC.put inside the block is not automatically recaptured for later suspensions. Use a new helper scope or MDCContext boundary when a new value must propagate.

restorePrevious=true uses the same nested restoration contract as the synchronous helper. With false, the helper also removes the applied non-null keys in an outer finally so caller-thread residue is cleared.

Code shapeChoice
Synchronous block without suspensionwithLoggingContext
suspend, async, or dispatcher switchwithCoroutineLoggingContext
Framework already owns trace MDCavoid duplicate ownership and verify its lifecycle

Before asynchronous emission, inspect the additional lifecycle in Async channel.