Skip to content

Instantly share code, notes, and snippets.

@ryanb93
Created February 1, 2019 12:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryanb93/432d91d1b488bc7b49d7ff7bdad06f01 to your computer and use it in GitHub Desktop.
Save ryanb93/432d91d1b488bc7b49d7ff7bdad06f01 to your computer and use it in GitHub Desktop.
MdcPropagatingExecutionContext
import java.util.{Map => JMap}
import com.twitter.inject.logging.MDCInitializer
import org.slf4j.MDC
import scala.concurrent.ExecutionContext
/**
* An `ExecutionContext` which takes the calling thread's MDC context map and copies it into
* the thread of where the runnable will be executed. As the `prepare` method of `ExecutionContext`
* is deprecated, it is advised to capture thread local data when the `ExecutionContext` is created.
* As a result of this, this `ExecutionContext` should not be stored as a `val` as it will not
* update the MDC value on each run.
*/
object MdcPropagatingExecutionContext {
def apply(underlying: ExecutionContext): ExecutionContext = new ExecutionContext {
private val context: JMap[String, String] = MDC.getCopyOfContextMap
override def execute(r: Runnable): Unit = {
val previousContext = MDC.getCopyOfContextMap
underlying.execute(() => {
MDCInitializer.let {
try {
setMdcContext(context)
r.run()
} finally {
setMdcContext(previousContext)
}
}
})
}
private def setMdcContext(context: JMap[String, String]): Unit =
if (context != null) MDC.setContextMap(context) else MDC.clear()
override def reportFailure(t: Throwable): Unit = underlying.reportFailure(t)
}
object Implicits {
/**
* Wrapper around the global execution context. Needs to be a `def` so that each call to it uses the
* current thread's MDC values.
*/
implicit def global: ExecutionContext = MdcPropagatingExecutionContext(ExecutionContext.Implicits.global)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment