1 /* 2 * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.coroutines.slf4j 6 7 import kotlinx.coroutines.* 8 import org.slf4j.MDC 9 import kotlin.coroutines.AbstractCoroutineContextElement 10 import kotlin.coroutines.CoroutineContext 11 12 /** 13 * The value of [MDC] context map. 14 * See [MDC.getCopyOfContextMap]. 15 */ 16 public typealias MDCContextMap = Map<String, String>? 17 18 /** 19 * [MDC] context element for [CoroutineContext]. 20 * 21 * Example: 22 * 23 * ``` 24 * MDC.put("kotlin", "rocks") // Put a value into the MDC context 25 * 26 * launch(MDCContext()) { 27 * logger.info { "..." } // The MDC context contains the mapping here 28 * } 29 * ``` 30 * 31 * Note that you cannot update MDC context from inside the coroutine simply 32 * using [MDC.put]. These updates are going to be lost on the next suspension and 33 * reinstalled to the MDC context that was captured or explicitly specified in 34 * [contextMap] when this object was created on the next resumption. 35 * Use `withContext(MDCContext()) { ... }` to capture updated map of MDC keys and values 36 * for the specified block of code. 37 * 38 * @param contextMap the value of [MDC] context map. 39 * Default value is the copy of the current thread's context map that is acquired via 40 * [MDC.getCopyOfContextMap]. 41 */ 42 public class MDCContext( 43 /** 44 * The value of [MDC] context map. 45 */ 46 @Suppress("MemberVisibilityCanBePrivate") 47 public val contextMap: MDCContextMap = MDC.getCopyOfContextMap() 48 ) : ThreadContextElement<MDCContextMap>, AbstractCoroutineContextElement(Key) { 49 /** 50 * Key of [MDCContext] in [CoroutineContext]. 51 */ 52 public companion object Key : CoroutineContext.Key<MDCContext> 53 54 /** @suppress */ updateThreadContextnull55 override fun updateThreadContext(context: CoroutineContext): MDCContextMap { 56 val oldState = MDC.getCopyOfContextMap() 57 setCurrent(contextMap) 58 return oldState 59 } 60 61 /** @suppress */ restoreThreadContextnull62 override fun restoreThreadContext(context: CoroutineContext, oldState: MDCContextMap) { 63 setCurrent(oldState) 64 } 65 setCurrentnull66 private fun setCurrent(contextMap: MDCContextMap) { 67 if (contextMap == null) { 68 MDC.clear() 69 } else { 70 MDC.setContextMap(contextMap) 71 } 72 } 73 } 74