diff options
author | Diego <diegolparra@gmail.com> | 2015-07-18 16:51:13 -0300 |
---|---|---|
committer | Diego <diegolparra@gmail.com> | 2015-08-09 21:03:23 -0300 |
commit | d5cec96f91b12a776a4745dcbf4ee34e2e945b5a (patch) | |
tree | 0ab8123b2684d0a6a1f9d9a0315eb4e1f7a662a4 /kamon-play24/src | |
parent | 116e5d3318cb7c6442485e04730f41d908423e56 (diff) | |
download | Kamon-d5cec96f91b12a776a4745dcbf4ee34e2e945b5a.tar.gz Kamon-d5cec96f91b12a776a4745dcbf4ee34e2e945b5a.tar.bz2 Kamon-d5cec96f91b12a776a4745dcbf4ee34e2e945b5a.zip |
+ play: play-2.4.x support
Diffstat (limited to 'kamon-play24/src')
15 files changed, 0 insertions, 922 deletions
diff --git a/kamon-play24/src/main/resources/META-INF/aop.xml b/kamon-play24/src/main/resources/META-INF/aop.xml deleted file mode 100644 index e24d48d5..00000000 --- a/kamon-play24/src/main/resources/META-INF/aop.xml +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> - -<aspectj> - <aspects> - <aspect name="kamon.play.instrumentation.RequestInstrumentation"/> - <aspect name="kamon.play.instrumentation.WSInstrumentation"/> - <aspect name="kamon.play.instrumentation.LoggerLikeInstrumentation"/> - </aspects> - - <weaver> - <include within="play.api..*"/> - </weaver> -</aspectj> diff --git a/kamon-play24/src/main/resources/reference.conf b/kamon-play24/src/main/resources/reference.conf deleted file mode 100644 index db94b3f6..00000000 --- a/kamon-play24/src/main/resources/reference.conf +++ /dev/null @@ -1,36 +0,0 @@ -# ================================== # -# Kamon-Play Reference Configuration # -# ================================== # - -kamon { - play { - - # Header name used when propagating the `TraceContext.token` value across applications. - trace-token-header-name = "X-Trace-Token" - - # When set to true, Kamon will automatically set and propogate the `TraceContext.token` value under the following - # conditions: - # - When a server side request is received containing the trace token header, the new `TraceContext` will have that - # some token, and once the response to that request is ready, the trace token header is also included in the - # response. - # - When a WS client request is issued and a `TraceContext` is available, the trace token header will be included - # in the request headers. - automatic-trace-token-propagation = true - - # Fully qualified name of the implementation of kamon.play.NameGenerator that will be used for assigning names - # to traces and client http segments. - name-generator = kamon.play.DefaultNameGenerator - - } - - modules { - kamon-play { - auto-start = yes - requires-aspectj = yes - extension-id = "kamon.play.Play" - } - } -} - -#register the module with Play -play.modules.enabled += "kamon.play.di.KamonModule"
\ No newline at end of file diff --git a/kamon-play24/src/main/scala/kamon/play/Play.scala b/kamon-play24/src/main/scala/kamon/play/Play.scala deleted file mode 100644 index 4d72f16e..00000000 --- a/kamon-play24/src/main/scala/kamon/play/Play.scala +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ========================================================================================= - * Copyright © 2013-2014 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * 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. - * ========================================================================================= - */ - -package kamon.play - -import akka.actor.{ ExtendedActorSystem, Extension, ExtensionId, ExtensionIdProvider } -import akka.event.Logging -import kamon.Kamon -import kamon.http.HttpServerMetrics -import play.api.libs.ws.WSRequest -import play.api.mvc.RequestHeader - -object Play extends ExtensionId[PlayExtension] with ExtensionIdProvider { - override def lookup(): ExtensionId[_ <: Extension] = Play - override def createExtension(system: ExtendedActorSystem): PlayExtension = new PlayExtension(system) - - val SegmentLibraryName = "WS-client" -} - -class PlayExtension(private val system: ExtendedActorSystem) extends Kamon.Extension { - val log = Logging(system, classOf[PlayExtension]) - log.info(s"Starting the Kamon(Play) extension") - - private val config = system.settings.config.getConfig("kamon.play") - val httpServerMetrics = Kamon.metrics.entity(HttpServerMetrics, "play-server") - - val includeTraceToken: Boolean = config.getBoolean("automatic-trace-token-propagation") - val traceTokenHeaderName: String = config.getString("trace-token-header-name") - - private val nameGeneratorFQN = config.getString("name-generator") - private val nameGenerator: NameGenerator = system.dynamicAccess.createInstanceFor[NameGenerator](nameGeneratorFQN, Nil).get - - def generateTraceName(requestHeader: RequestHeader): String = nameGenerator.generateTraceName(requestHeader) - def generateHttpClientSegmentName(request: WSRequest): String = nameGenerator.generateHttpClientSegmentName(request) -} - -trait NameGenerator { - def generateTraceName(requestHeader: RequestHeader): String - def generateHttpClientSegmentName(request: WSRequest): String -} - -class DefaultNameGenerator extends NameGenerator { - import scala.collection.concurrent.TrieMap - import play.api.routing.Router - import java.util.Locale - import kamon.util.TriemapAtomicGetOrElseUpdate.Syntax - - private val cache = TrieMap.empty[String, String] - private val normalizePattern = """\$([^<]+)<[^>]+>""".r - - def generateTraceName(requestHeader: RequestHeader): String = requestHeader.tags.get(Router.Tags.RouteVerb).map { verb ⇒ - val path = requestHeader.tags(Router.Tags.RoutePattern) - cache.atomicGetOrElseUpdate(s"$verb$path", { - val traceName = { - // Convert paths of form GET /foo/bar/$paramname<regexp>/blah to foo.bar.paramname.blah.get - val p = normalizePattern.replaceAllIn(path, "$1").replace('/', '.').dropWhile(_ == '.') - val normalisedPath = { - if (p.lastOption.filter(_ != '.').isDefined) s"$p." - else p - } - s"$normalisedPath${verb.toLowerCase(Locale.ENGLISH)}" - } - traceName - }) - } getOrElse s"${requestHeader.method}: ${requestHeader.uri}" - - def generateHttpClientSegmentName(request: WSRequest): String = request.url -} diff --git a/kamon-play24/src/main/scala/kamon/play/action/KamonTraceActions.scala b/kamon-play24/src/main/scala/kamon/play/action/KamonTraceActions.scala deleted file mode 100644 index 854989a4..00000000 --- a/kamon-play24/src/main/scala/kamon/play/action/KamonTraceActions.scala +++ /dev/null @@ -1,29 +0,0 @@ -/* =================================================== - * Copyright © 2013-2014 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * ========================================================== */ - -package kamon.play.action - -import kamon.trace.Tracer -import play.api.mvc._ -import scala.concurrent.Future - -case class TraceName[A](name: String)(action: Action[A]) extends Action[A] { - def apply(request: Request[A]): Future[Result] = { - Tracer.currentContext.rename(name) - action(request) - } - lazy val parser = action.parser -} diff --git a/kamon-play24/src/main/scala/kamon/play/di/KamonModule.scala b/kamon-play24/src/main/scala/kamon/play/di/KamonModule.scala deleted file mode 100644 index 372e7300..00000000 --- a/kamon-play24/src/main/scala/kamon/play/di/KamonModule.scala +++ /dev/null @@ -1,54 +0,0 @@ -/* ========================================================================================= - * Copyright © 2013-2015 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License") you may not use this file - * 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. - * ========================================================================================= - */ - -package kamon.play.di - -import javax.inject._ -import kamon.metric.MetricsModule -import kamon.trace.TracerModule -import play.api.inject.{ ApplicationLifecycle, Module } -import play.api.{ Logger, Configuration, Environment } -import scala.concurrent.Future - -trait Kamon { - def start(): Unit - def shutdown(): Unit - def metrics(): MetricsModule - def tracer(): TracerModule -} - -class KamonModule extends Module { - def bindings(environment: Environment, configuration: Configuration) = { - Seq(bind[Kamon].to[KamonAPI].eagerly()) - } -} - -@Singleton -class KamonAPI @Inject() (lifecycle: ApplicationLifecycle, environment: Environment) extends Kamon { - private val log = Logger(classOf[KamonAPI]) - - log.info("Registering the Kamon Play Module.") - - start() //force to start kamon eagerly on application startup - - def start(): Unit = kamon.Kamon.start() - def shutdown(): Unit = kamon.Kamon.shutdown() - def metrics(): MetricsModule = kamon.Kamon.metrics - def tracer(): TracerModule = kamon.Kamon.tracer - - lifecycle.addStopHook { () ⇒ - Future.successful(shutdown()) - } -} diff --git a/kamon-play24/src/main/scala/kamon/play/instrumentation/LoggerLikeInstrumentation.scala b/kamon-play24/src/main/scala/kamon/play/instrumentation/LoggerLikeInstrumentation.scala deleted file mode 100644 index 3c79fae4..00000000 --- a/kamon-play24/src/main/scala/kamon/play/instrumentation/LoggerLikeInstrumentation.scala +++ /dev/null @@ -1,42 +0,0 @@ -/* ========================================================================================= - * Copyright © 2013-2014 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * 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. - * ========================================================================================= - */ - -package kamon.play.instrumentation - -import kamon.trace.logging.MdcKeysSupport -import org.aspectj.lang.ProceedingJoinPoint -import org.aspectj.lang.annotation._ - -@Aspect -class LoggerLikeInstrumentation extends MdcKeysSupport { - - @Pointcut("execution(* play.api.LoggerLike+.info(..))") - def infoPointcut(): Unit = {} - - @Pointcut("execution(* play.api.LoggerLike+.warn(..))") - def warnPointcut(): Unit = {} - - @Pointcut("execution(* play.api.LoggerLike+.error(..))") - def errorPointcut(): Unit = {} - - @Pointcut("execution(* play.api.LoggerLike+.trace(..))") - def tracePointcut(): Unit = {} - - @Around("(infoPointcut() || warnPointcut() || errorPointcut() || tracePointcut())") - def aroundLog(pjp: ProceedingJoinPoint): Any = withMdc { - pjp.proceed() - } -} - diff --git a/kamon-play24/src/main/scala/kamon/play/instrumentation/RequestInstrumentation.scala b/kamon-play24/src/main/scala/kamon/play/instrumentation/RequestInstrumentation.scala deleted file mode 100644 index a1f199ba..00000000 --- a/kamon-play24/src/main/scala/kamon/play/instrumentation/RequestInstrumentation.scala +++ /dev/null @@ -1,83 +0,0 @@ -/* ========================================================================================= - * Copyright © 2013-2015 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * 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. - * ========================================================================================= - */ - -package kamon.play.instrumentation - -import kamon.Kamon -import kamon.Kamon.tracer -import kamon.play.Play -import kamon.trace._ -import kamon.util.SameThreadExecutionContext -import org.aspectj.lang.ProceedingJoinPoint -import org.aspectj.lang.annotation._ -import play.api.mvc.Results._ -import play.api.mvc._ - -@Aspect -class RequestInstrumentation { - - @DeclareMixin("play.api.mvc.RequestHeader+") - def mixinContextAwareNewRequest: TraceContextAware = TraceContextAware.default - - @Before("call(* play.api.http.DefaultHttpRequestHandler.routeRequest(..)) && args(requestHeader)") - def routeRequest(requestHeader: RequestHeader): Unit = { - val playExtension = Kamon(Play) - - val token = if (playExtension.includeTraceToken) { - requestHeader.headers.get(playExtension.traceTokenHeaderName) - } else None - - Tracer.setCurrentContext(tracer.newContext("UnnamedTrace", token)) - } - - @Around("call(* play.api.http.HttpFilters.filters(..))") - def filters(pjp: ProceedingJoinPoint): Any = { - val filter = new EssentialFilter { - def apply(next: EssentialAction) = EssentialAction((requestHeader) ⇒ { - val playExtension = Kamon(Play) - - def onResult(result: Result): Result = { - Tracer.currentContext.collect { ctx ⇒ - ctx.finish() - playExtension.httpServerMetrics.recordResponse(ctx.name, result.header.status.toString) - - if (playExtension.includeTraceToken) result.withHeaders(playExtension.traceTokenHeaderName -> ctx.token) - else result - - } getOrElse result - } - //override the current trace name - Tracer.currentContext.rename(playExtension.generateTraceName(requestHeader)) - // Invoke the action - next(requestHeader).map(onResult)(SameThreadExecutionContext) - }) - } - pjp.proceed().asInstanceOf[Seq[EssentialFilter]] :+ filter - } - - @Before("call(* play.api.http.HttpErrorHandler.onClientServerError(..)) && args(requestContextAware, statusCode, *)") - def onClientError(requestContextAware: TraceContextAware, statusCode: Int): Unit = { - requestContextAware.traceContext.collect { ctx ⇒ - Kamon(Play).httpServerMetrics.recordResponse(ctx.name, statusCode.toString) - } - } - - @Before("call(* play.api.http.HttpErrorHandler.onServerError(..)) && args(requestContextAware, ex)") - def onServerError(requestContextAware: TraceContextAware, ex: Throwable): Unit = { - requestContextAware.traceContext.collect { ctx ⇒ - Kamon(Play).httpServerMetrics.recordResponse(ctx.name, InternalServerError.header.status.toString) - } - } -} diff --git a/kamon-play24/src/main/scala/kamon/play/instrumentation/WSInstrumentation.scala b/kamon-play24/src/main/scala/kamon/play/instrumentation/WSInstrumentation.scala deleted file mode 100644 index 93f6d95a..00000000 --- a/kamon-play24/src/main/scala/kamon/play/instrumentation/WSInstrumentation.scala +++ /dev/null @@ -1,47 +0,0 @@ -/* =================================================== - * Copyright © 2013-2014 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * ========================================================== */ - -package kamon.play.instrumentation - -import kamon.Kamon -import kamon.play.Play -import kamon.trace.{ Tracer, SegmentCategory } -import kamon.util.SameThreadExecutionContext -import org.aspectj.lang.ProceedingJoinPoint -import org.aspectj.lang.annotation.{ Around, Aspect, Pointcut } -import play.api.libs.ws.{ WSRequest, WSResponse } -import scala.concurrent.Future -import scala.util.Try - -@Aspect -class WSInstrumentation { - - @Pointcut("execution(* play.api.libs.ws.ning.NingWSRequest.execute()) && this(request)") - def onExecuteRequest(request: WSRequest): Unit = {} - - @Around("onExecuteRequest(request)") - def aroundExecuteRequest(pjp: ProceedingJoinPoint, request: WSRequest): Any = { - Tracer.currentContext.collect { ctx ⇒ - val playExtension = Kamon(Play) - val segmentName = playExtension.generateHttpClientSegmentName(request) - val segment = ctx.startSegment(segmentName, SegmentCategory.HttpClient, Play.SegmentLibraryName) - val response = pjp.proceed().asInstanceOf[Future[WSResponse]] - - response.onComplete(result ⇒ segment.finish())(SameThreadExecutionContext) - response - } getOrElse pjp.proceed() - } -}
\ No newline at end of file diff --git a/kamon-play24/src/test/resources/META-INF/aop.xml b/kamon-play24/src/test/resources/META-INF/aop.xml deleted file mode 100644 index 2888a31a..00000000 --- a/kamon-play24/src/test/resources/META-INF/aop.xml +++ /dev/null @@ -1,11 +0,0 @@ -<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> - -<aspectj> - <aspects> - <aspect name="kamon.play.instrumentation.FakeRequestIntrumentation"/> - </aspects> - - <weaver> - <include within="play.api..*"/> - </weaver> -</aspectj> diff --git a/kamon-play24/src/test/resources/conf/application.conf b/kamon-play24/src/test/resources/conf/application.conf deleted file mode 100644 index b345fca7..00000000 --- a/kamon-play24/src/test/resources/conf/application.conf +++ /dev/null @@ -1,7 +0,0 @@ -kamon { - play { - include-trace-token-header = true - trace-token-header-name = "X-Trace-Token" - name-generator = kamon.play.DefaultNameGenerator - } -} diff --git a/kamon-play24/src/test/resources/logback.xml b/kamon-play24/src/test/resources/logback.xml deleted file mode 100644 index c336bbfe..00000000 --- a/kamon-play24/src/test/resources/logback.xml +++ /dev/null @@ -1,12 +0,0 @@ -<configuration> - <statusListener class="ch.qos.logback.core.status.NopStatusListener"/> - <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> - <encoder> - <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> - </encoder> - </appender> - - <root level="OFF"> - <appender-ref ref="STDOUT"/> - </root> -</configuration>
\ No newline at end of file diff --git a/kamon-play24/src/test/scala/kamon/play/LoggerLikeInstrumentationSpec.scala b/kamon-play24/src/test/scala/kamon/play/LoggerLikeInstrumentationSpec.scala deleted file mode 100644 index 408509c5..00000000 --- a/kamon-play24/src/test/scala/kamon/play/LoggerLikeInstrumentationSpec.scala +++ /dev/null @@ -1,122 +0,0 @@ -/* ========================================================================================= - * Copyright © 2013-2014 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License") you may not use this file - * 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. - * ========================================================================================= - */ - -package kamon.play - -import ch.qos.logback.classic.spi.ILoggingEvent -import ch.qos.logback.classic.{ AsyncAppender, LoggerContext } -import ch.qos.logback.core.read.ListAppender -import ch.qos.logback.core.status.NopStatusListener -import kamon.trace.TraceLocal -import kamon.trace.TraceLocal.AvailableToMdc -import org.scalatest.BeforeAndAfter -import org.scalatestplus.play._ -import org.slf4j -import play.api.LoggerLike -import play.api.mvc.Results.Ok -import play.api.mvc._ -import play.api.test.Helpers._ -import play.api.test._ -import scala.concurrent.duration._ - -import scala.concurrent.{ Await, Future } - -class LoggerLikeInstrumentationSpec extends PlaySpec with OneServerPerSuite with BeforeAndAfter { - System.setProperty("config.file", "./kamon-play/src/test/resources/conf/application.conf") - - val executor = scala.concurrent.ExecutionContext.Implicits.global - - val infoMessage = "Info Message" - val headerValue = "My header value" - val otherValue = "My other value" - - val TraceLocalHeaderKey = AvailableToMdc("header") - val TraceLocalOtherKey = AvailableToMdc("other") - - before { - LoggingHandler.startLogging() - } - - after { - LoggingHandler.stopLogging() - } - - implicit override lazy val app = FakeApplication(withRoutes = { - - case ("GET", "/logging") ⇒ - Action.async { - Future { - TraceLocal.store(TraceLocalHeaderKey)(headerValue) - TraceLocal.store(TraceLocalOtherKey)(otherValue) - LoggingHandler.info(infoMessage) - Ok("OK") - }(executor) - } - }) - - "the LoggerLike instrumentation" should { - "allow retrieve a value from the MDC when was created a key of type AvailableToMdc in the current request" in { - LoggingHandler.appenderStart() - - Await.result(route(FakeRequest(GET, "/logging")).get, 500 millis) - - TraceLocal.retrieve(TraceLocalHeaderKey) must be(Some(headerValue)) - TraceLocal.retrieve(TraceLocalOtherKey) must be(Some(otherValue)) - - LoggingHandler.appenderStop() - - headerValue must be(LoggingHandler.getValueFromMDC("header")) - otherValue must be(LoggingHandler.getValueFromMDC("other")) - } - } -} - -object LoggingHandler extends LoggerLike { - - val loggerContext = new LoggerContext() - val rootLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) - val asyncAppender = new AsyncAppender() - val listAppender = new ListAppender[ILoggingEvent]() - val nopStatusListener = new NopStatusListener() - - override val logger: slf4j.Logger = rootLogger - - def startLogging(): Unit = { - loggerContext.getStatusManager().add(nopStatusListener) - asyncAppender.setContext(loggerContext) - listAppender.setContext(loggerContext) - listAppender.setName("list") - listAppender.start() - } - - def stopLogging(): Unit = { - listAppender.stop() - } - - def appenderStart(): Unit = { - asyncAppender.addAppender(listAppender) - asyncAppender.start() - rootLogger.addAppender(asyncAppender) - } - - def appenderStop(): Unit = { - asyncAppender.stop() - } - - def getValueFromMDC(key: String): String = { - listAppender.list.get(0).getMDCPropertyMap.get(key) - } -} - diff --git a/kamon-play24/src/test/scala/kamon/play/RequestInstrumentationSpec.scala b/kamon-play24/src/test/scala/kamon/play/RequestInstrumentationSpec.scala deleted file mode 100644 index 9db5e20d..00000000 --- a/kamon-play24/src/test/scala/kamon/play/RequestInstrumentationSpec.scala +++ /dev/null @@ -1,262 +0,0 @@ -/* ========================================================================================= - * Copyright © 2013-2014 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * 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. - * ========================================================================================= - */ - -package kamon.play - -import javax.inject.Inject - -import kamon.Kamon -import kamon.metric.instrument.CollectionContext -import kamon.play.action.TraceName -import kamon.trace.{ TraceLocal, Tracer } -import org.scalatestplus.play._ -import play.api.DefaultGlobal -import play.api.http.{ HttpErrorHandler, HttpFilters, Writeable } -import play.api.libs.concurrent.Execution.Implicits.defaultContext -import play.api.libs.ws.WS -import play.api.mvc.Results.Ok -import play.api.mvc._ -import play.api.routing.SimpleRouter -import play.api.test.Helpers._ -import play.api.test._ -import play.core.routing._ - -import scala.concurrent.duration._ -import scala.concurrent.{ Await, Future } - -class RequestInstrumentationSpec extends PlaySpec with OneServerPerSuite { - System.setProperty("config.file", "./kamon-play/src/test/resources/conf/application.conf") - - override lazy val port: Port = 19002 - val executor = scala.concurrent.ExecutionContext.Implicits.global - - implicit override lazy val app = FakeApplication(withRoutes = { - case ("GET", "/async") ⇒ - Action.async { - Future { - Ok("Async.async") - }(executor) - } - case ("GET", "/notFound") ⇒ - Action { - Results.NotFound - } - case ("GET", "/error") ⇒ - Action { - throw new Exception("This page generates an error!") - Ok("This page will generate an error!") - } - case ("GET", "/redirect") ⇒ - Action { - Results.Redirect("/redirected", MOVED_PERMANENTLY) - } - case ("GET", "/default") ⇒ - Action { - Ok("default") - } - case ("GET", "/async-renamed") ⇒ - TraceName("renamed-trace") { - Action.async { - Future { - Ok("Async.async") - }(executor) - } - } - case ("GET", "/retrieve") ⇒ - Action { - Ok("retrieve from TraceLocal") - } - }, additionalConfiguration = Map( - ("application.router", "kamon.play.Routes"), - ("play.http.filters", "kamon.play.TestHttpFilters"), - ("play.http.requestHandler", "play.api.http.DefaultHttpRequestHandler"), - ("logger.root", "OFF"), - ("logger.play", "OFF"), - ("logger.application", "OFF"))) - - val traceTokenValue = "kamon-trace-token-test" - val traceTokenHeaderName = "X-Trace-Token" - val expectedToken = Some(traceTokenValue) - val traceTokenHeader = traceTokenHeaderName -> traceTokenValue - val traceLocalStorageValue = "localStorageValue" - val traceLocalStorageKey = "localStorageKey" - val traceLocalStorageHeader = traceLocalStorageKey -> traceLocalStorageValue - - "the Request instrumentation" should { - "respond to the Async Action with X-Trace-Token" in { - val Some(result) = route(FakeRequest(GET, "/async").withHeaders(traceTokenHeader, traceLocalStorageHeader)) - header(traceTokenHeaderName, result) must be(expectedToken) - } - - "respond to the NotFound Action with X-Trace-Token" in { - val Some(result) = route(FakeRequest(GET, "/notFound").withHeaders(traceTokenHeader)) - header(traceTokenHeaderName, result) must be(expectedToken) - } - - "respond to the Default Action with X-Trace-Token" in { - val Some(result) = route(FakeRequest(GET, "/default").withHeaders(traceTokenHeader)) - header(traceTokenHeaderName, result) must be(expectedToken) - } - - "respond to the Redirect Action with X-Trace-Token" in { - val Some(result) = route(FakeRequest(GET, "/redirect").withHeaders(traceTokenHeader)) - header("Location", result) must be(Some("/redirected")) - header(traceTokenHeaderName, result) must be(expectedToken) - } - - "respond to the Async Action with X-Trace-Token and the renamed trace" in { - val result = Await.result(route(FakeRequest(GET, "/async-renamed").withHeaders(traceTokenHeader)).get, 10 seconds) - Tracer.currentContext.name must be("renamed-trace") - Some(result.header.headers(traceTokenHeaderName)) must be(expectedToken) - } - - "propagate the TraceContext and LocalStorage through of filters in the current request" in { - route(FakeRequest(GET, "/retrieve").withHeaders(traceTokenHeader, traceLocalStorageHeader)) - TraceLocal.retrieve(TraceLocalKey).get must be(traceLocalStorageValue) - } - - "response to the getRouted Action and normalise the current TraceContext name" in { - Await.result(WS.url(s"http://localhost:$port/getRouted").get(), 10 seconds) - Kamon.metrics.find("getRouted.get", "trace") must not be empty - } - - "response to the postRouted Action and normalise the current TraceContext name" in { - Await.result(WS.url(s"http://localhost:$port/postRouted").post("content"), 10 seconds) - Kamon.metrics.find("postRouted.post", "trace") must not be empty - } - - "response to the showRouted Action and normalise the current TraceContext name" in { - Await.result(WS.url(s"http://localhost:$port/showRouted/2").get(), 10 seconds) - Kamon.metrics.find("show.some.id.get", "trace") must not be empty - } - - "record http server metrics for all processed requests" in { - val collectionContext = CollectionContext(100) - Kamon.metrics.find("play-server", "http-server").get.collect(collectionContext) - - for (repetition ← 1 to 10) { - Await.result(route(FakeRequest(GET, "/default").withHeaders(traceTokenHeader)).get, 10 seconds) - } - - for (repetition ← 1 to 5) { - Await.result(route(FakeRequest(GET, "/notFound").withHeaders(traceTokenHeader)).get, 10 seconds) - } - - for (repetition ← 1 to 5) { - Await.result(routeWithOnError(FakeRequest(GET, "/error").withHeaders(traceTokenHeader)).get, 10 seconds) - } - - val snapshot = Kamon.metrics.find("play-server", "http-server").get.collect(collectionContext) - snapshot.counter("GET: /default_200").get.count must be(10) - snapshot.counter("GET: /notFound_404").get.count must be(5) - snapshot.counter("GET: /error_500").get.count must be(5) - snapshot.counter("200").get.count must be(10) - snapshot.counter("404").get.count must be(5) - snapshot.counter("500").get.count must be(5) - } - } - - def routeWithOnError[T](req: Request[T])(implicit w: Writeable[T]): Option[Future[Result]] = { - route(req).map { result ⇒ - result.recoverWith { - case t: Throwable ⇒ DefaultGlobal.onError(req, t) - } - } - } -} - -object TraceLocalKey extends TraceLocal.TraceLocalKey { - type ValueType = String -} - -class TraceLocalFilter extends Filter { - - val traceLocalStorageValue = "localStorageValue" - val traceLocalStorageKey = "localStorageKey" - val traceLocalStorageHeader = traceLocalStorageKey -> traceLocalStorageValue - - override def apply(next: (RequestHeader) ⇒ Future[Result])(header: RequestHeader): Future[Result] = { - Tracer.withContext(Tracer.currentContext) { - - TraceLocal.store(TraceLocalKey)(header.headers.get(traceLocalStorageKey).getOrElse("unknown")) - - next(header).map { - result ⇒ - { - result.withHeaders(traceLocalStorageKey -> TraceLocal.retrieve(TraceLocalKey).get) - } - } - } - } -} - -class TestHttpFilters @Inject() (traceLocalFilter: TraceLocalFilter) extends HttpFilters { - val filters = Seq(traceLocalFilter) -} - -class Routes @Inject() (application: controllers.Application) extends GeneratedRouter with SimpleRouter { - val prefix = "/" - - lazy val defaultPrefix = { - if (prefix.endsWith("/")) "" else "/" - } - - // Gets - private[this] lazy val Application_getRouted = - Route("GET", PathPattern(List(StaticPart(prefix), StaticPart(defaultPrefix), StaticPart("getRouted")))) - - private[this] lazy val Application_show = - Route("GET", PathPattern(List(StaticPart(prefix), StaticPart(defaultPrefix), StaticPart("showRouted/"), DynamicPart("id", """[^/]+""", encodeable = true)))) - - //Posts - private[this] lazy val Application_postRouted = - Route("POST", PathPattern(List(StaticPart(prefix), StaticPart(defaultPrefix), StaticPart("postRouted")))) - - def routes: PartialFunction[RequestHeader, Handler] = { - case Application_getRouted(params) ⇒ call { - createInvoker(application.getRouted, - HandlerDef(this.getClass.getClassLoader, "", "controllers.Application", "getRouted", Nil, "GET", """some comment""", prefix + """getRouted""")).call(application.getRouted) - } - case Application_postRouted(params) ⇒ call { - createInvoker(application.postRouted, - HandlerDef(this.getClass.getClassLoader, "", "controllers.Application", "postRouted", Nil, "POST", """some comment""", prefix + """postRouted""")).call(application.postRouted) - } - case Application_show(params) ⇒ call(params.fromPath[Int]("id", None)) { (id) ⇒ - createInvoker(application.showRouted(id), - HandlerDef(this.getClass.getClassLoader, "", "controllers.Application", "showRouted", Seq(classOf[Int]), "GET", """""", prefix + """show/some/$id<[^/]+>""")).call(application.showRouted(id)) - } - } - - override def errorHandler: HttpErrorHandler = new HttpErrorHandler() { - override def onClientError(request: RequestHeader, statusCode: Int, message: String): Future[Result] = Future.successful(Results.InternalServerError) - override def onServerError(request: RequestHeader, exception: Throwable): Future[Result] = Future.successful(Results.InternalServerError) - } -} - -object controllers { - import play.api.mvc._ - - class Application extends Controller { - val postRouted = Action { - Ok("invoked postRouted") - } - val getRouted = Action { - Ok("invoked getRouted") - } - def showRouted(id: Int) = Action { - Ok("invoked show with: " + id) - } - } -}
\ No newline at end of file diff --git a/kamon-play24/src/test/scala/kamon/play/WSInstrumentationSpec.scala b/kamon-play24/src/test/scala/kamon/play/WSInstrumentationSpec.scala deleted file mode 100644 index c7cc2304..00000000 --- a/kamon-play24/src/test/scala/kamon/play/WSInstrumentationSpec.scala +++ /dev/null @@ -1,96 +0,0 @@ -/* =================================================== - * Copyright © 2013-2014 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * ========================================================== */ - -package kamon.play - -import kamon.Kamon -import kamon.metric.{ Entity, EntitySnapshot, TraceMetrics } -import kamon.trace.{ Tracer, TraceContext, SegmentCategory } -import org.scalatest.{ Matchers, WordSpecLike } -import org.scalatestplus.play.OneServerPerSuite -import play.api.libs.ws.WS -import play.api.mvc.Action -import play.api.mvc.Results.Ok -import play.api.test.Helpers._ -import play.api.test._ - -import scala.concurrent.Await -import scala.concurrent.duration._ - -class WSInstrumentationSpec extends WordSpecLike with Matchers with OneServerPerSuite { - System.setProperty("config.file", "./kamon-play/src/test/resources/conf/application.conf") - - override lazy val port: Port = 19003 - implicit override lazy val app = FakeApplication(withRoutes = { - case ("GET", "/async") ⇒ Action { Ok("ok") } - case ("GET", "/outside") ⇒ Action { Ok("ok") } - case ("GET", "/inside") ⇒ callWSinsideController(s"http://localhost:$port/async") - }) - - "the WS instrumentation" should { - "propagate the TraceContext inside an Action and complete the WS request" in { - Await.result(route(FakeRequest(GET, "/inside")).get, 10 seconds) - - val snapshot = takeSnapshotOf("GET: /inside", "trace") - snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - - val segmentMetricsSnapshot = takeSnapshotOf(s"http://localhost:$port/async", "trace-segment", - tags = Map( - "trace" -> "GET: /inside", - "category" -> SegmentCategory.HttpClient, - "library" -> Play.SegmentLibraryName)) - - segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - } - - "propagate the TraceContext outside an Action and complete the WS request" in { - Tracer.withContext(newContext("trace-outside-action")) { - Await.result(WS.url(s"http://localhost:$port/outside").get(), 10 seconds) - Tracer.currentContext.finish() - } - - val snapshot = takeSnapshotOf("trace-outside-action", "trace") - snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - - val segmentMetricsSnapshot = takeSnapshotOf(s"http://localhost:$port/outside", "trace-segment", - tags = Map( - "trace" -> "trace-outside-action", - "category" -> SegmentCategory.HttpClient, - "library" -> Play.SegmentLibraryName)) - - segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - } - } - - lazy val collectionContext = Kamon.metrics.buildDefaultCollectionContext - - def newContext(name: String): TraceContext = - Kamon.tracer.newContext(name) - - def takeSnapshotOf(name: String, category: String, tags: Map[String, String] = Map.empty): EntitySnapshot = { - val recorder = Kamon.metrics.find(Entity(name, category, tags)).get - recorder.collect(collectionContext) - } - - def callWSinsideController(url: String) = Action.async { - import play.api.Play.current - import play.api.libs.concurrent.Execution.Implicits.defaultContext - - WS.url(url).get().map { response ⇒ - Ok("Ok") - } - } -}
\ No newline at end of file diff --git a/kamon-play24/src/test/scala/kamon/play/instrumentation/FakeRequestIntrumentation.scala b/kamon-play24/src/test/scala/kamon/play/instrumentation/FakeRequestIntrumentation.scala deleted file mode 100644 index 10e285db..00000000 --- a/kamon-play24/src/test/scala/kamon/play/instrumentation/FakeRequestIntrumentation.scala +++ /dev/null @@ -1,27 +0,0 @@ -/* =================================================== - * Copyright © 2013-2014 the kamon project <http://kamon.io/> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * ========================================================== */ - -package kamon.play.instrumentation - -import org.aspectj.lang.annotation.{ DeclareMixin, Aspect } -import kamon.trace.TraceContextAware - -@Aspect -class FakeRequestIntrumentation { - - @DeclareMixin("play.api.test.FakeRequest") - def mixinContextAwareNewRequest: TraceContextAware = TraceContextAware.default -} |