Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rishabh9 committed Feb 17, 2017
0 parents commit 77af6da
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 0 deletions.
104 changes: 104 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Created by .ignore support plugin (hsz.mobi)
### Java template
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

.idea/
*.iml

# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml

# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml

# Gradle:
.idea/**/gradle.xml
.idea/**/libraries

# Mongo Explorer plugin:
.idea/**/mongoSettings.xml

## File-based project format:
*.iws

## Plugin-specific files:

# IntelliJ
/out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### SBT template
# Simple Build Tool
# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control

target/
lib_managed/
src_managed/
project/boot/
.history
.cache
### Scala template
*.class
*.log

# sbt specific
.cache
.history
.lib/
dist/*
target/
lib_managed/
src_managed/
project/boot/
project/plugins/project/

# Scala-IDE specific
.ensime
.ensime_cache/
.scala_dependencies
.worksheet

# ENSIME specific
.ensime_cache/
.ensime

8 changes: 8 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
This software is licensed under the Apache 2 license, quoted below.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with
the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
The Mapped Diagnostic Context (MDC) Propagation Akka Dispatcher
=============

A Mapped Diagnostic Context (MDC) propagation Akka Dispatcher for the asynchronous environment of the Play Framework.

#### Links
1. http://yanns.github.io/blog/2014/05/04/slf4j-mapped-diagnostic-context-mdc-with-play-framework/
2. https://github.com/jroper/thread-local-context-propagation/

#### How To Use

##### Configure Jitpack
1. Add the JitPack repository to your build file - build.sbt
```scala
resolvers += "jitpack" at "https://jitpack.io"
```
2. Add the dependency
```scala
libraryDependencies += "com.github.rishabh9" % "mdc-propagation-dispatcher" % "0.0.1"
```

##### Create a filter
```java
public class MappedDiagnosticContextFilter extends Filter {

/**
* @param mat This object is needed to handle streaming of requests
* and responses.
*/
@Inject
public MappedDiagnosticContextFilter(Materializer mat) {
super(mat);
}

@Override
public CompletionStage<Result> apply(Function<Http.RequestHeader, CompletionStage<Result>> next,
Http.RequestHeader requestHeader) {
try {
return next.apply(requestHeader);
} finally {
MDC.remove("X-UserId");
}
}
}
```

##### Add to Filters.java
```java
@Singleton
public class Filters implements HttpFilters {
private final MappedDiagnosticContextFilter mdcFilter;

@Inject
public Filters(MappedDiagnosticContextFilter mdcFilter) {
this.mdcFilter = mdcFilter;
}

@Override
public EssentialFilter[] filters() {
final EssentialFilter[] filters = {
mdcFilter.asJava()
};
return filters;
}
}
```

##### Update your logging configuration
```xml
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %coloredLevel %logger{35} %mdc{X-UserId:--} - %msg%n%rootException</pattern>
</encoder>
</appender>
```
45 changes: 45 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import sbtrelease.ReleasePlugin.autoImport.ReleaseTransformations._

organization := "dispatcher"

name := "mdc-propagation-dispatcher"

version := (version in ThisBuild).value

scalaVersion := "2.11.7"

exportJars := true

retrieveManaged := true

libraryDependencies ++= Seq(
"com.typesafe" % "config" % "1.3.0" % "provided",
"org.slf4j" % "slf4j-api" % "1.7.21" % "provided",
"com.typesafe.akka" %% "akka-actor" % "2.4.12" % "provided"
)

javacOptions ++= Seq("-source", "1.8", "-target", "1.8")

initialize := {
val _ = initialize.value
if (sys.props("java.specification.version") != "1.8")
sys.error("Java 8 is required for this project.")
}

sources in (Compile, doc) := Seq.empty

publishArtifact in (Compile, packageDoc) := false

// The Release configuration
releaseProcess := Seq[ReleaseStep](
checkSnapshotDependencies, // : ReleaseStep
inquireVersions, // : ReleaseStep
runTest, // : ReleaseStep
setReleaseVersion, // : ReleaseStep
commitReleaseVersion, // : ReleaseStep, performs the initial git checks
tagRelease, // : ReleaseStep
//publishArtifacts, // : ReleaseStep, checks whether `publishTo` is properly set up
setNextVersion, // : ReleaseStep
commitNextVersion, // : ReleaseStep
pushChanges // : ReleaseStep, also checks that an upstream branch is properly configured
)
2 changes: 2 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// SBT Release Plugin
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.3")
88 changes: 88 additions & 0 deletions src/main/scala/MDCPropagatingDispatcherConfigurator.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import java.util.concurrent.TimeUnit

import akka.dispatch._
import com.typesafe.config.Config
import org.slf4j.MDC

import scala.concurrent.ExecutionContext
import scala.concurrent.duration.{Duration, FiniteDuration}

/**
* Configurator for a MDC propagating dispatcher.
*
* To use it, configure play like this:
* {{{
* play {
* akka {
* actor {
* default-dispatcher = {
* type = "monitoring.MDCPropagatingDispatcherConfigurator"
* }
* }
* }
* }
* }}}
*
* Credits to James Roper for the [[https://github.com/jroper/thread-local-context-propagation/ initial implementation]]
*/
class MDCPropagatingDispatcherConfigurator(config: Config, prerequisites: DispatcherPrerequisites)
extends MessageDispatcherConfigurator(config, prerequisites) {

private val instance = new MDCPropagatingDispatcher(
this,
config.getString("id"),
config.getInt("throughput"),
FiniteDuration(config.getDuration("throughput-deadline-time", TimeUnit.NANOSECONDS), TimeUnit.NANOSECONDS),
configureExecutor(),
FiniteDuration(config.getDuration("shutdown-timeout", TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS))

override def dispatcher(): MessageDispatcher = instance
}

/**
* A MDC propagating dispatcher.
*
* This dispatcher propagates the MDC current request context if it's set when it's executed.
*/
class MDCPropagatingDispatcher(_configurator: MessageDispatcherConfigurator,
id: String,
throughput: Int,
throughputDeadlineTime: Duration,
executorServiceFactoryProvider: ExecutorServiceFactoryProvider,
shutdownTimeout: FiniteDuration)
extends Dispatcher(_configurator, id, throughput, throughputDeadlineTime, executorServiceFactoryProvider, shutdownTimeout) {

self =>

override def prepare(): ExecutionContext = new ExecutionContext {
// capture the MDC
val mdcContext = MDC.getCopyOfContextMap

def execute(r: Runnable) = self.execute(new Runnable {
def run() = {
// backup the callee MDC context
val oldMDCContext = MDC.getCopyOfContextMap

// Run the runnable with the captured context
setContextMap(mdcContext)
try {
r.run()
} finally {
// restore the callee MDC context
setContextMap(oldMDCContext)
}
}
})

def reportFailure(t: Throwable) = self.reportFailure(t)
}

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

}
1 change: 1 addition & 0 deletions version.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version in ThisBuild := "0.0.1"

0 comments on commit 77af6da

Please sign in to comment.