如何以类似于Apache日志记录的方式(包括URL和客户端IP)记录所有来自Play 2应用程序的请求?
答案 0 :(得分:9)
我想用Play 2.5.4做同样的事情。我花了一点时间把这些碎片放在一起,所以我想我会分享我的步骤,希望它能为别人节省时间:
确保您拥有访问记录器。这是一个如何在https://www.playframework.com/documentation/2.5.x/SettingsLogger配置一个示例的示例
但你可能想玩这些设置;我将我的记录器配置为<file>${application.home:-.}/logs/access.log</file>
和<immediateFlush>true</immediateFlush>
。
在根包中创建一个新的RequestHandler,扩展默认处理程序:
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) } }
我来自Play 2.3,所以我原本打算使用GlobalSettings直到找到这个指南:https://www.playframework.com/documentation/2.5.x/GlobalSettings
向任何想要Play 2.0特定答案的人致歉,但看到我自己的2.5重点搜索引导我到这里,我认为这个答案不会造成太大伤害。
答案 1 :(得分:5)
这就是http过滤器的用途。以下是一些详细示例:http://www.playframework.com/documentation/2.1.1/ScalaHttpFilters
答案 2 :(得分:0)
创建自己的Action功能更强大,更灵活。
object MyAction {
def apply[A](bodyParser: BodyParser[A])(block: Request[A] => Result): Action[A] = Action(bodyParser) {
request =>
// TODO : authentication, cache logics here
// time it
val start = ...
// process
val r = block(request)
val end = ...
// log remote address, user agent, time, etc.
r
}
// simply override to use MyAction
def apply(block: Request[AnyContent] => Result): Action[AnyContent] = this.apply(BodyParsers.parse.anyContent)(block)
// simply override to use MyAction
def apply(block: => Result): Action[AnyContent] = this.apply(_ => block)
}
要在控制器中使用它,只需将Action替换为MyAction
即可def index = MyAction {
implicit request =>
// nothing to be changed here
}
答案 3 :(得分:0)
在Play 2.5.x中,我使用了以下
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())
}
}
确保正确配置此过滤器 - https://www.playframework.com/documentation/2.5.x/ScalaHttpFilters#Using-filters