scala - Reproducir/Registrar/Imprimir cuerpo de respuesta/Ejecutar sobre enumerador/tamponar el cuerpo
logging playframework (3)
Como me parece, si result.body &> Enumeratee.map
sesión en result.body &> Enumeratee.map
(como se sugiere en https://stackoverflow.com/a/27630208/1781549 ) y el cuerpo del resultado se presenta en más de un fragmento, entonces cada fragmento se registrará de forma independiente. Probablemente no quieras esto.
Lo implementaría así:
val ret = block(request).flatMap { result =>
val consume = Iteratee.consume[Array[Byte]]()
val bodyF = Iteratee.flatten(result.body(consume)).run
bodyF.map { bodyBytes: Array[Byte] =>
//
// Log the body
//
result.copy(body = Enumerator(bodyBytes))
}
}
Pero tenga cuidado: la idea general de esto es consumir todos los datos del Enumerador result.body
antes de iniciar sesión (y devolver el nuevo Enumerator). Por lo tanto, si la respuesta es grande o confía en la transmisión, probablemente también sea lo que no desea.
Estoy buscando una forma de imprimir el cuerpo de respuesta en Play framework, tengo un código como este:
object AccessLoggingAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
Logger.info(s"""Request:
id=${request.id}
method=${request.method}
uri=${request.uri}
remote-address=${request.remoteAddress}
body=${request.body}
""")
val ret = block(request)
/*
ret.map {result =>
Logger.info(s"""Response:
id=${request.id}
body=${result.body}
""")
}
*/ //TODO: find out how to print result.body (be careful not to consume the enumerator)
ret
}
}
Actualmente, el código comentado no funciona como yo quería, es decir, se imprimiría:
Response:
id=1
body=play.api.libs.iteratee.Enumerator$$anon$18@39e6c1a2
Entonces, necesito encontrar una manera de obtener una Cadena de Enumerador [Matriz [Byte]]. Traté de entender el concepto de Enumerator leyendo esto: http://mandubian.com/2012/08/27/understanding-play2-iteratees-for-normal-humans/
Entonces ... si lo entiendo correctamente:
No debería secar el enumerador en el proceso de convertirlo a String. De lo contrario, el cliente no recibiría nada.
Supongamos que descubro cómo implementar el mecanismo de T / filtro. Pero entonces ... ¿no vencería el propósito del marco Play como un marco de transmisión sin bloqueo (porque estaría construyendo la matriz completa de bytes en la memoria, antes de llamar a String y finalmente registrarla)?
Entonces, ¿cuál es la forma correcta de registrar la respuesta?
Gracias de antemano, Raka
Este código funciona:
object AccessLoggingAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
val start = System.currentTimeMillis
Logger.info(s"""Request:
id=${request.id}
method=${request.method}
uri=${request.uri}
remote-address=${request.remoteAddress}
body=${request.body}
""")
val resultFut = block(request)
resultFut.map {result =>
val time = System.currentTimeMillis - start
Result(result.header, result.body &> Enumeratee.map(arrOfBytes => {
val body = new String(arrOfBytes.map(_.toChar))
Logger.info(s"""Response:
id=${request.id}
method=${request.method}
uri=${request.uri}
delay=${time}ms
status=${result.header.status}
body=${body}""")
arrOfBytes
}), result.connection)
}
}
}
En parte aprendí esto desde aquí (sobre cómo sacar el conjunto de bytes del enumerador): Scala Play 2.1: Acceder a los cuerpos de solicitud y respuesta en un filtro .
Estoy usando Play 2.3.7 mientras que el enlace que di usa 2.1 (y todavía usa PlainResult, que ya no existe en 2.3).
Utilicé la respuesta anterior como punto de partida, pero noté que solo registrará las respuestas si hay un cuerpo presente. Lo hemos adaptado a esto:
var responseBody = None:Option[String]
val captureBody = Enumeratee.map[Array[Byte]](arrOfBytes => {
val body = new String(arrOfBytes.map(_.toChar))
responseBody = Some(body)
arrOfBytes
})
val withLogging = (result.body &> captureBody).onDoneEnumerating({
logger.debug(.. create message here ..)
})
result.copy(body=withLogging)