Last active
August 29, 2015 14:11
-
-
Save magro/a330717d615f21820e3c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object CassandraTracing { | |
def traceSegment(res: Future[ResultSet]): Future[ResultSet] = { | |
TraceRecorder.withTraceContextAndSystem { (ctx, system) => | |
// Because we don't know the actual table that was queried for now we | |
// use a general name for the segment, it's renamed once we have the result | |
val segment = ctx.startSegment("db", "cassandra-client", "datastax") | |
res.onComplete { | |
case Success(rs) => | |
// Get the table name from the result so that we can give the segment | |
// a more specific name | |
val table = rs.getColumnDefinitions.getTable(0) | |
segment.rename("db_" + table) | |
segment.finish() | |
case Failure(e) => segment.finish() | |
}(Execution.tracingContext) | |
res | |
}.getOrElse(res) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import io.ino.play.tracing.{SlowRequestLogger, StoreRequestInfoFilter} | |
import play.api.Application | |
import play.api.libs.concurrent.Akka | |
import play.api.mvc.WithFilters | |
object Global extends WithFilters(StoreRequestInfoFilter) { | |
override def onStart(app: Application): Unit = { | |
SlowRequestLogger.start(Akka.system(app)) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.ino.play.tracing | |
import akka.actor.{Actor, ActorLogging, ActorSystem, Props} | |
import kamon.Kamon | |
import kamon.trace.{SegmentInfo, Trace, TraceInfo} | |
import play.api.Logger | |
import scala.concurrent.duration._ | |
/** | |
* Kamon trace subscriber that logs slow requests. Relies on request method + uri stored | |
* under the keys TraceMetadata.{RequestMethod, RequestUri} in the trace context's metadata. | |
*/ | |
class SlowRequestLogger extends Actor with ActorLogging { | |
private val logger = Logger("SlowRequestLog") | |
import TraceMetadata._ | |
override def receive: Receive = { | |
case trace: TraceInfo => | |
val requestTime = NANOSECONDS.toMillis(trace.elapsedTime.nanos) | |
val segmentsMsg = formatSegmentsInfo(trace.segments) | |
val msg = s""""${trace.metadata(RequestMethod)} ${trace.metadata(RequestUri)}" ($requestTime ms)$segmentsMsg""" | |
logger.info(msg) | |
} | |
/** | |
* Ugly stuff to build segment info, produces s.th. like | |
* "segments: segment1 (23 ms), segment2 (42 ms, someMeta: someValue) | |
*/ | |
private def formatSegmentsInfo(segments: Seq[SegmentInfo]): String = { | |
if (segments.isEmpty) { | |
"" | |
} else { | |
", segments: " + segments.map { segment => | |
val detailsMsg = if (segment.metadata.isEmpty) { | |
"" | |
} else { | |
", " + segment.metadata.map { case (key, value) => s"$key: $value"}.mkString(", ") | |
} | |
segment.name + " (" + NANOSECONDS.toMillis(segment.elapsedTime.nanos) + " ms" + detailsMsg + ")" | |
}.mkString(", ") | |
} | |
} | |
} | |
object SlowRequestLogger { | |
/** | |
* Starts the SlowRequestLogger - subscribe to traces recorded by kamon. | |
*/ | |
def start(implicit system: ActorSystem): Unit = { | |
val slowRequestLogger = system.actorOf(Props(new SlowRequestLogger)) | |
Kamon(Trace).subscribe(slowRequestLogger) | |
} | |
} | |
object TraceMetadata { | |
val RequestMethod = "requestMethod" | |
val RequestUri = "requestUri" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.ino.play.tracing | |
import kamon.trace.TraceRecorder | |
import play.api.mvc.{Filter, RequestHeader, Result} | |
import scala.concurrent.Future | |
/** | |
* Stores request info in kamon's trace local storage, so that it's available for logging (SlowRequestLogger). | |
*/ | |
object StoreRequestInfoFilter extends Filter { | |
import TraceMetadata._ | |
override def apply(next: (RequestHeader) => Future[Result])(rh: RequestHeader): Future[Result] = { | |
val ctxt = TraceRecorder.currentContext | |
ctxt.addMetadata(RequestMethod, rh.method) | |
ctxt.addMetadata(RequestUri, rh.uri) | |
next(rh) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val TracingRequestInterceptor = new RequestInterceptor { | |
override def interceptQuery(f: (SolrServer, SolrQuery) => Future[QueryResponse]) | |
(solrServer: SolrServer, q: SolrQuery): Future[QueryResponse] = { | |
TraceRecorder.withTraceContextAndSystem { (ctx, system) => | |
val segment = ctx.startSegment("solrQuery", "solr-client", "solrs") | |
val response = f(solrServer, q) | |
response.onComplete { | |
case Success(qr) => | |
// Add the query time measured by solr as segment metadata | |
segment.addMetadata("solrQTime", qr.getQTime.toString) | |
segment.finish() | |
case Failure(e) => segment.finish() | |
}(ExecutionContext.global) | |
response | |
}.getOrElse(f(solrServer, q)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment