Play2(Scala)でMDCを使う

ほぼ参考にした[ここ](http://yanns.github.io/blog/2014/05/04/slf4j-mapped-diagnostic-context-mdc-with-play-framework/)のままなので原文を読んだ方が早いです。

## CustomExecutionContextを定義

原文のままだとコンパイルできなかったので、SimpleResult -> Result, Map[_, _] -> Map[String, String]に変えています。

```scala:
package concurrent

import org.slf4j.MDC
import scala.concurrent.{ ExecutionContextExecutor, ExecutionContext }

/**
 * slf4j provides a MDC [[http://logback.qos.ch/manual/mdc.html Mapped Diagnostic Context]]
 * based on a [[ThreadLocal]]. In an asynchronous environment, the callbacks can be called
 * in another thread, where the local thread variable does not exist anymore.
 *
 * This execution context fixes this problem:
 * it propagates the MDC from the caller's thread to the callee's one.
 */
object MDCHttpExecutionContext {

    /**
     * Create an MDCHttpExecutionContext with values from the current thread.
     */
    def fromThread(delegate: ExecutionContext): ExecutionContextExecutor =
        new MDCHttpExecutionContext(MDC.getCopyOfContextMap, delegate)

}

/**
 * Manages execution to ensure that the given MDC context are set correctly
 * in the current thread. Actual execution is performed by a delegate ExecutionContext.
 */
class MDCHttpExecutionContext(mdcContext: java.util.Map[String, String], delegate: ExecutionContext) extends ExecutionContextExecutor {
    def execute(runnable: Runnable) = delegate.execute(new Runnable {
        def run() {
            val oldMDCContext = MDC.getCopyOfContextMap
            setContextMap(mdcContext)
            try {
                runnable.run()
            } finally {
                setContextMap(oldMDCContext)
            }
        }
    })

    private[this] def setContextMap(context: java.util.Map[String, String]) {
        if (context == null) {
            MDC.clear()
        } else {
            MDC.setContextMap(context)
        }
    }

    def reportFailure(t: Throwable) = delegate.reportFailure(t)
}
```


### アプリケーションで使うデフォルトのExecutionContextを定義
 
```scala:
package concurrent

import scala.concurrent.ExecutionContext

/**
 * The standard [[play.api.libs.concurrent.Execution.defaultContext]] loses the MDC context.
 *
 * This custom [[ExecutionContext]] propagates the MDC context, so that the request
 * and the correlation IDs can be logged.
 */
object Execution {

    object Implicits {
        implicit def defaultContext: ExecutionContext = Execution.defaultContext
    }

    def defaultContext: ExecutionContext = MDCHttpExecutionContext.fromThread(play.api.libs.concurrent.Execution.defaultContext)

}
```

あとは

```scala:
import play.api.libs.concurrent.Execution.Implicits.defaultContext
```

を使っているところを


```scala:
import concurrent.Execution.Implicits._
```

に変える。


## CustomExecutionContextを使うためにActionを定義

```scala:
package controllers

import concurrent.Execution
import scala.concurrent.Future
import play.api.mvc.Result
import scala.concurrent.ExecutionContext
import play.api.mvc.ActionBuilder
import play.api.mvc.Request

object Action extends ActionBuilder[Request] {
    def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
        block(request)
    }

    /**
     * The standard [[play.api.mvc.Action]] loses the MDC context.
     *
     * This action builder sets the [[ExecutionContext]] so that the
     * MDC context is propagated.
     * With this custom [[ExecutionContext]], the request and the correlation IDs
     * can be logged.
     */
    override def executionContext: ExecutionContext = Execution.defaultContext
}
```

あとはこのActionを使ってControllerを記述する。