gun
gun

Reputation: 1076

Scala Play 2.5.0 2.5.1 Filtering with access to result body

I didn't find a way to get the body within a Filter in Play 2.5.x. I want to create a "BadRequestLogFilter", which should log the request AND the result, if my appliation returns a status code 400-500

In Play 2.4.x, I used Iteratees and it worked. I was not able to migrate this piece of code to Play 2.5.x. Can somebody give me a hint here? Maybe the hole approach to get the body in an Filter is an bad idea?

Here is my old (in 2.4.x working properly) Filter for Play 2.4.x

class BadRequestLogFilter @Inject() (implicit val mat: Materializer, ec: ExecutionContext) extends Filter {
  val logger = Logger("bad_status").underlyingLogger

  override def apply(next: (RequestHeader) => Future[Result])(request: RequestHeader): Future[Result] = {
    val resultFuture = next(request)
    resultFuture.foreach(result => {

      val status = result.header.status
      if (status < 200 || status >= 400) {
        val c = Try(request.tags(Router.Tags.RouteController))
        val a = Try(request.tags(Router.Tags.RouteActionMethod))

        val body = result.body.run(Iteratee.fold(Array.empty[Byte]) { (memo, nextChunk) => memo ++ nextChunk })
        val futResponse = body.map(bytes => new String(bytes))
        futResponse.map { response =>

          val m = Map("method" -> request.method,
            "uri" -> request.uri,
            "status" -> status,
            "response" -> response,
            "request" -> request,
            "controller" -> c.getOrElse("empty"),
            "actionMethod" -> a.getOrElse("empty"))

          val msg = m.map { case (k, v) => s"$k=$v" }.mkString(", ")
          logger.info(appendEntries(m), msg)
        }
      }
    })
    resultFuture
  }
}

I guess I just need an valid replacement for this line here:

val body = result.body.run(Iteratee.fold(Array.empty[Byte]) { (memo, nextChunk) => memo ++ nextChunk })

Upvotes: 3

Views: 533

Answers (1)

Anton Sarov
Anton Sarov

Reputation: 3748

The body of a result in Play 2.5.x is of type HttpEntity

So once you have the result you can get the body and then materialize it:

val body = result.body.consumeData(mat)

Here mat is the implicit Materializer you have. This is going to return you a Future[ByteString] which you can then decode to get a String representation (I have omitted future handling here for simplicity):

val bodyAsString = body.decodeString("UTF-8")
logger.info(bodyAsString)

Upvotes: 3

Related Questions