Skip to content

Instantly share code, notes, and snippets.

@arturaz
Created October 31, 2012 16:23
Show Gist options
  • Save arturaz/3988045 to your computer and use it in GitHub Desktop.
Save arturaz/3988045 to your computer and use it in GitHub Desktop.
package helpers.action
import play.api._
import http.HeaderNames
import libs.iteratee.Iteratee
import play.api.mvc._
trait Logging extends ActionComposition {
override def Action[A](bodyParser: BodyParser[A])(
block: Request[A] => Result
) = {
implicit val log = Logger("application")
super.Action(bodyParser) { request =>
val reqStr = "%s %s%s%s at %s%s%s (uid: %s%s%s)".format(
request.method,
Console.GREEN, request.uri, Console.RESET,
Console.BLUE, new java.util.Date(), Console.RESET,
Console.YELLOW, Integer.toString(request.hashCode, 36), Console.RESET
)
log.info("Request " + reqStr)
log.info(" Parameters: " + mapStrs(request.queryString))
log.debug(" Headers: " + mapStrs(request.headers.toMap))
log.debug(" Body:\n" + request.body)
val start = System.currentTimeMillis
val res = block(request)
val elapsed = System.currentTimeMillis - start
logResult(res, reqStr, elapsed)
res
}
}
private[this] def logResult(res: Result, reqStr: String, elapsed: Long)(
implicit log: Logger
) {
logResult(res, reqStr, elapsed, "")
}
private[this] def logResult(
res: Result, reqStr: String, elapsed: Long, prefix: String
)(implicit log: Logger) {
val elapsedStr =
"%s%dms%s".format(Console.MAGENTA, elapsed, Console.RESET)
res match {
case result: SimpleResult[_] =>
logResult(result, elapsedStr, prefix)
case AsyncResult(promise) =>
log.info("Completed async in %s\n".format(elapsedStr))
val promiseStart = System.currentTimeMillis
promise.onRedeem { result =>
val promiseElapsed = System.currentTimeMillis - promiseStart
logResult(
result, reqStr, promiseElapsed,
"Redeemed %s | ".format(reqStr)
)
}
case _ =>
log.info(
"%sCompleted with %s%s%s in %s\n".format(
prefix, Console.GREEN, res.getClass, Console.RESET, elapsedStr
)
)
}
}
private[this] def logResult[A](
res: SimpleResult[A], elapsedStr: String, prefix: String
)(implicit log: Logger) {
log.debug("Response completed:")
log.debug(" Headers: " + mapStr(res.header.headers.toMap))
log.debug({
var bodyStr = ""
res.body(Iteratee.foreach { e => bodyStr += e.toString })
if (bodyStr == "") " Empty response body" else (" Body:\n" + bodyStr)
})
val status = res.header.status match {
case 404 => Console.RED + "404" + Console.RESET
case s => s.toString
}
log.info("%sCompleted %s in %s\n".format(prefix, status, elapsedStr))
}
private[this] def mapStrs[A](map: Map[String, Seq[String]]) = {
def seqStr(seq: Seq[String]) = seq.map(v => '"'+v+'"').mkString(",")
"{" + map.map { case (key, values) =>
var valuesStr = seqStr(values)
if (values.size > 1) valuesStr = "["+valuesStr+"]"
'"' + key + "\": " + valuesStr
}.mkString(", ") + "}"
}
private[this] def mapStr[A](map: Map[String, String]) = {
"{" + map.map { case (key, value) =>
'"' + key + "\": \"" + value + '"'
}.mkString(", ") + "}"
}
}
trait App extends Controller with Logging
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment