How can I log all requests coming in to a Play 2 application, in a similar way to how Apache logs (i.e. including the URL and client IP)?
I wanted to do the same thing with with Play 2.5.4. It took me a little while to put the pieces together, so I thought I'd share my steps in the hope that it'll save time for someone else:
Make sure you have an access logger. There's an example of how to configure one at https://www.playframework.com/documentation/2.5.x/SettingsLogger
but you might want to play with the settings; I put configured my logger with <file>${application.home:-.}/logs/access.log</file>
, and <immediateFlush>true</immediateFlush>
.
Create a new RequestHandler in your root package, extending the default handler:
import javax.inject.Inject import play.api.http._ import play.api.routing._ import play.api.mvc.RequestHeader import play.api.Logger /** * Implemented to get custom, apache-style logging of requests without dumping the full netty wire. */ class RequestHandler @Inject() (router: Router, errorHandler: HttpErrorHandler, configuration: HttpConfiguration, filters: HttpFilters) extends DefaultHttpRequestHandler( router, errorHandler, configuration, filters) { override def routeRequest(request: RequestHeader) = { Logger("access").info(s"Request from ${request.remoteAddress}: ${request}") super.routeRequest(request) } }
I was coming from Play 2.3, so I was originally planning to use GlobalSettings until I found this guide: https://www.playframework.com/documentation/2.5.x/GlobalSettings
Apologies to anyone who wants answers specific to Play 2.0, but seeing as my own 2.5-focused searches led me here, I figure this answer won't do much harm.
That's what http filters are for. Here are some detailed examples: http://www.playframework.com/documentation/2.1.1/ScalaHttpFilters
In Play 2.5.x, I used the following
import javax.inject.Inject
import akka.stream.Materializer
import play.api.Logger
import play.api.mvc._
import scala.concurrent.{ExecutionContext, Future}
import java.util.Calendar
import java.text.SimpleDateFormat
class ApacheLoggingFilter @Inject() (implicit val mat: Materializer, ec: ExecutionContext) extends Filter {
def apply(nextFilter: RequestHeader => Future[Result])
(requestHeader: RequestHeader): Future[Result] = {
nextFilter(requestHeader).map { result =>
val responseSize = result.body.contentLength.getOrElse("-")
Logger("access").info(s"""${requestHeader.remoteAddress} - - [${serverTime}] "${requestHeader}" ${result.header.status} ${responseSize}""")
result
}
}
private def serverTime = {
val calendar = Calendar.getInstance()
val dateFormat = new SimpleDateFormat(
"dd/MMM/yyyy:HH:mm:ss Z")
dateFormat.setTimeZone(calendar.getTimeZone)
dateFormat.format(calendar.getTime())
}
}
Make sure you configure this Filter correctly - https://www.playframework.com/documentation/2.5.x/ScalaHttpFilters#Using-filters
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With