Skip to content

Instantly share code, notes, and snippets.

@ppearcy
Created August 31, 2015 19:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ppearcy/cf44eb3c1fe7c7efc4c0 to your computer and use it in GitHub Desktop.
Save ppearcy/cf44eb3c1fe7c7efc4c0 to your computer and use it in GitHub Desktop.
A body parser that will log failed parses
/**
* Loosely Based on info gleaned from this article: https://victorops.com/blog/capturing-raw-requests-play/
* Play really makes this harder than it should be (with some good reasons)
*/
trait ParseLoggerTrait {
val logger: LoggerLike = Logger(this.getClass)
def log[A](parser: BodyParser[A], maxLength: Int, enableBadRequestLogging: Boolean): BodyParser[A] = BodyParser("LoggingParser") { request =>
import play.api.libs.iteratee.Execution.Implicits.trampoline
// Add a max length wrapper on the raw parse. By default raw parse will pull into memory or flush to disk so we need the length check
BodyParsers.parse.maxLength(maxLength, BodyParsers.parse.raw)(request).mapM {
case Left(result) =>
Future.successful(Left(result))
case Right(rawParse) =>
rawParse match {
case Left(result) =>
Future.successful(Left(Results.EntityTooLarge))
case Right(buffer) =>
val bytes = buffer.asBytes().getOrElse(Array.empty[Byte])
Enumerator(bytes)(parser(request)) flatMap { i =>
i.run
} map {
case Left(result) =>
val badBody = Try(new String(bytes, "UTF-8")).toOption.getOrElse(Base64.encodeBase64String(bytes))
if (enableBadRequestLogging) {
logger.error(s"From request: $request with headers ${request.headers}, failed to parse body data: $badBody")
}
Left(result)
case Right(a) =>
Right(a)
}
}
}
}
}
object ParseLogger extends ParseLoggerTrait
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment