我们目前正在使用Play框架,并且正在使用标准的日志记录机制。我们已经实现了一个隐式上下文,以支持将用户名和会话ID传递给所有服务方法。我们要实现日志记录,使其基于会话。这需要实现我们自己的记录器。这适用于我们自己的日志,但是对于基本的异常处理和结果日志,我们该如何做同样的事情。也许有更好的方法可以使用隐式捕获,或者如何覆盖异常处理日志记录。本质上,我们希望获得与会话关联的尽可能多的日志消息。
这取决于您要进行反应式样式开发还是标准同步开发:
如果您正在进行反应式开发,则有两种选择:
您仍然可以使用MDC,除非必须使用自定义的执行上下文将有效的MDC值复制到线程,因为理论上每个请求都可以由多个线程处理。(如此处所述:http : //code.hootsuite.com/logging-contextual-info-in-an-asynchronous-scala-application/)
另一种选择是我倾向于使用的解决方案(接近于您现在使用的解决方案):您可以创建一个代表MyAppRequest的类。设置用户名,会话信息以及其他内容。您可以继续将其作为隐式传递。但是,您可以创建自己的MyAction类,而不是使用Action.async,如下所示
myAction.async {隐式myRequest => //一些代码}
在myAction内部,您必须捕获所有Exceptions并处理将来的失败,并手动执行错误处理,而不是依赖ErrorHandler。我经常将myAction注入到我的Controllers中,并添加通用的过滤器功能。
不利的一面是,这只是一种手动方法。另外,我还使MyAppRequest保留了可记录值的映射,该映射可以在任何地方设置,这意味着它必须是可变的映射。另外,有时您需要制作多个myAction.async。优点是,它非常明确,并且在您的控制中没有太多的ExecutionContext / ThreadLocal魔术。
下面是一些非常粗糙的示例代码,作为手动解决方案的入门:
def logErrorAndRethrow(myrequest:MyRequest, x:Throwable): Nothing = {
//log your error here in the format you like
throw x //you can do this or handle errors how you like
}
class MyRequest {
val attr : mutable.Map[String, String] = new mutable.HashMap[String, String]()
}
//make this a util to inject, or move it into a common parent controller
def myAsync(block: MyRequest => Future[Result] ): Action[AnyContent] = {
val myRequest = new MyRequest()
try {
Action.async(
block(myRequest).recover { case cause => logErrorAndRethrow(myRequest, cause) }
)
} catch {
case x:Throwable =>
logErrorAndRethrow(myRequest, x)
}
}
//the method your Route file refers to
def getStuff = myAsync { request:MyRequest =>
//execute your code here, passing around request as an implicit
Future.successful(Results.Ok)
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句