aboutsummaryrefslogtreecommitdiff
path: root/kamon-play
diff options
context:
space:
mode:
authorDiego <diegolparra@gmail.com>2014-03-08 20:17:15 -0300
committerDiego <diegolparra@gmail.com>2014-03-08 20:17:15 -0300
commitb8a26e0f173a528c700a3d0cfa4ed2f8079a7ae1 (patch)
tree67e184bf958f2690b69db82a42eb396788e314e2 /kamon-play
parent347319f58f7aca927729c5144b3d7d59750be7e4 (diff)
downloadKamon-b8a26e0f173a528c700a3d0cfa4ed2f8079a7ae1.tar.gz
Kamon-b8a26e0f173a528c700a3d0cfa4ed2f8079a7ae1.tar.bz2
Kamon-b8a26e0f173a528c700a3d0cfa4ed2f8079a7ae1.zip
WIP:Play integration WebExternal
Diffstat (limited to 'kamon-play')
-rw-r--r--kamon-play/src/main/resources/META-INF/aop.xml1
-rw-r--r--kamon-play/src/main/scala/kamon/play/instrumentation/RequestInstrumentation.scala2
-rw-r--r--kamon-play/src/main/scala/kamon/play/instrumentation/WSInstrumentation.scala70
-rw-r--r--kamon-play/src/test/scala/kamon/play/RequestInstrumentationSpec.scala7
-rw-r--r--kamon-play/src/test/scala/kamon/play/WSInstrumentationSpec.scala59
5 files changed, 137 insertions, 2 deletions
diff --git a/kamon-play/src/main/resources/META-INF/aop.xml b/kamon-play/src/main/resources/META-INF/aop.xml
index ca119c2b..3c3cceed 100644
--- a/kamon-play/src/main/resources/META-INF/aop.xml
+++ b/kamon-play/src/main/resources/META-INF/aop.xml
@@ -3,6 +3,7 @@
<aspectj>
<aspects>
<aspect name="kamon.play.instrumentation.RequestInstrumentation"/>
+ <aspect name="kamon.play.instrumentation.WSInstrumentation"/>
</aspects>
<weaver options="-verbose -showWeaveInfo">
diff --git a/kamon-play/src/main/scala/kamon/play/instrumentation/RequestInstrumentation.scala b/kamon-play/src/main/scala/kamon/play/instrumentation/RequestInstrumentation.scala
index 76edb90c..c55f89e0 100644
--- a/kamon-play/src/main/scala/kamon/play/instrumentation/RequestInstrumentation.scala
+++ b/kamon-play/src/main/scala/kamon/play/instrumentation/RequestInstrumentation.scala
@@ -30,7 +30,7 @@ import scala.concurrent.ExecutionContext.Implicits.global
@Aspect
class RequestInstrumentation {
- @DeclareMixin("play.api.mvc.Request || play.api.mvc.WrappedRequest || play.api.test.FakeRequest")
+ @DeclareMixin("play.api.mvc.RequestHeader || play.api.test.FakeRequest")
def mixinContextAwareNewRequest: TraceContextAware = TraceContextAware.default
@Pointcut("execution(* play.api.GlobalSettings+.onStart(*)) && args(application)")
diff --git a/kamon-play/src/main/scala/kamon/play/instrumentation/WSInstrumentation.scala b/kamon-play/src/main/scala/kamon/play/instrumentation/WSInstrumentation.scala
new file mode 100644
index 00000000..2fedcd70
--- /dev/null
+++ b/kamon-play/src/main/scala/kamon/play/instrumentation/WSInstrumentation.scala
@@ -0,0 +1,70 @@
+package kamon.play.instrumentation
+
+import javax.net.ssl.SSLContext
+import org.aspectj.lang.annotation.{ Around, Pointcut, Aspect }
+import org.aspectj.lang.ProceedingJoinPoint
+import com.ning.http.client._
+import com.ning.http.client.filter.{ RequestFilter, FilterContext }
+import kamon.trace.{ SegmentCompletionHandle, TraceRecorder }
+import kamon.metrics.TraceMetrics.HttpClientRequest
+
+@Aspect
+class WSInstrumentation {
+
+ @Pointcut("call(* play.api.libs.ws.WS$.newClient(..))")
+ def onNewAsyncHttpClient(): Unit = {}
+
+ @Around("onNewAsyncHttpClient()")
+ def aroundNewAsyncHttpClient(pjp: ProceedingJoinPoint): Any = {
+ val playConfig = play.api.Play.maybeApplication.map(_.configuration)
+ val wsTimeout = playConfig.flatMap(_.getMilliseconds("ws.timeout"))
+ val asyncHttpConfig = new AsyncHttpClientConfig.Builder()
+ .setConnectionTimeoutInMs(playConfig.flatMap(_.getMilliseconds("ws.timeout.connection")).orElse(wsTimeout).getOrElse(120000L).toInt)
+ .setIdleConnectionTimeoutInMs(playConfig.flatMap(_.getMilliseconds("ws.timeout.idle")).orElse(wsTimeout).getOrElse(120000L).toInt)
+ .setRequestTimeoutInMs(playConfig.flatMap(_.getMilliseconds("ws.timeout.request")).getOrElse(120000L).toInt)
+ .setFollowRedirects(playConfig.flatMap(_.getBoolean("ws.followRedirects")).getOrElse(true))
+ .setUseProxyProperties(playConfig.flatMap(_.getBoolean("ws.useProxyProperties")).getOrElse(true))
+
+ playConfig.flatMap(_.getString("ws.useragent")).map { useragent ⇒
+ asyncHttpConfig.setUserAgent(useragent)
+ }
+ if (!playConfig.flatMap(_.getBoolean("ws.acceptAnyCertificate")).getOrElse(false)) {
+ asyncHttpConfig.setSSLContext(SSLContext.getDefault)
+ }
+
+ asyncHttpConfig.addRequestFilter(new KamonRequestFilter())
+
+ new AsyncHttpClient(asyncHttpConfig.build())
+ }
+}
+
+class KamonRequestFilter extends RequestFilter {
+ import KamonRequestFilter._
+
+ override def filter(ctx: FilterContext[_]): FilterContext[_] = {
+ val completionHandle = TraceRecorder.startSegment(HttpClientRequest(ctx.getRequest.getRawURI.toString(), UserTime), basicRequestAttributes(ctx.getRequest()))
+ new FilterContext.FilterContextBuilder(ctx).asyncHandler(new AsyncHandlerWrapper[Response](ctx.getAsyncHandler(), completionHandle)).build()
+ }
+
+ class AsyncHandlerWrapper[T](asyncHandler: AsyncHandler[_], completionHandle: Option[SegmentCompletionHandle]) extends AsyncCompletionHandler[T] {
+ override def onCompleted(response: Response): T = {
+ completionHandle.map(_.finish(Map.empty))
+ asyncHandler.onCompleted().asInstanceOf[T]
+ }
+ override def onThrowable(t: Throwable) = {
+ asyncHandler.onThrowable(t)
+ }
+ }
+}
+
+object KamonRequestFilter {
+ val UserTime = "UserTime"
+
+ def basicRequestAttributes(request: Request): Map[String, String] = {
+ Map[String, String](
+ "host" -> request.getHeaders().getFirstValue("host"),
+ "path" -> request.getURI.getPath,
+ "method" -> request.getMethod)
+ }
+}
+
diff --git a/kamon-play/src/test/scala/kamon/play/RequestInstrumentationSpec.scala b/kamon-play/src/test/scala/kamon/play/RequestInstrumentationSpec.scala
index 5b75359f..2dce39f8 100644
--- a/kamon-play/src/test/scala/kamon/play/RequestInstrumentationSpec.scala
+++ b/kamon-play/src/test/scala/kamon/play/RequestInstrumentationSpec.scala
@@ -75,7 +75,12 @@ class RequestInstrumentationSpec extends PlaySpecification {
private val expectedToken = Some(traceTokenValue)
private val traceTokenHeader = (traceTokenHeaderName -> traceTokenValue)
- "the request instrumentation" should {
+ "the Request instrumentation" should {
+ "respond to the asyncResult action with X-Trace-Token" in new WithServer(appWithRoutes) {
+ val Some(result) = route(FakeRequest(GET, "/asyncResult").withHeaders(traceTokenHeader))
+ header(traceTokenHeaderName, result) must equalTo(expectedToken)
+ }
+
"respond to the async action with X-Trace-Token" in new WithServer(appWithRoutes) {
val Some(result) = route(FakeRequest(GET, "/async").withHeaders(traceTokenHeader))
header(traceTokenHeaderName, result) must equalTo(expectedToken)
diff --git a/kamon-play/src/test/scala/kamon/play/WSInstrumentationSpec.scala b/kamon-play/src/test/scala/kamon/play/WSInstrumentationSpec.scala
new file mode 100644
index 00000000..2cebfe42
--- /dev/null
+++ b/kamon-play/src/test/scala/kamon/play/WSInstrumentationSpec.scala
@@ -0,0 +1,59 @@
+/* ===================================================
+ * 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 play.api.test._
+import play.api.mvc.{ Results, Action }
+import play.api.mvc.Results.Ok
+import scala.Some
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.concurrent.Future
+import org.junit.runner.RunWith
+import org.specs2.runner.JUnitRunner
+import play.api.mvc.AsyncResult
+import play.api.test.FakeApplication
+import kamon.play.action.TraceName
+import play.api.libs.ws.WS
+
+@RunWith(classOf[JUnitRunner])
+class WSInstrumentationSpec extends PlaySpecification {
+
+ System.setProperty("config.file", "./kamon-play/src/test/resources/conf/application.conf")
+
+ val appWithRoutes = FakeApplication(withRoutes = {
+
+ case ("GET", "/async") ⇒
+ Action.async {
+ WS.url("http://www.google.com").get().map {
+ response ⇒
+ Ok(response.toString())
+ }
+ }
+ })
+
+ "the WS instrumentation" should {
+ "respond to the async action" in new WithServer(appWithRoutes) {
+ val Some(result) = route(FakeRequest(GET, "/async"))
+ println("-902425309-53095-5 " + result)
+ result.onComplete {
+ case scala.util.Success(r) ⇒ println(r)
+ case scala.util.Failure(t) ⇒ println(t)
+ }
+ Thread.sleep(3000)
+ }
+ }
+} \ No newline at end of file