我现在已经使用 akka-http 了一段时间,到目前为止我通过扩展使用 scala-logging 进行了大部分记录 StrictLogging 或 LazyLogging ,然后调用:
log.info
log.debug
....
这有点好,但很难理解为哪个请求生成了哪些日志。
作为解决方案,我只见过:
添加传递的隐式日志记录上下文(这有点冗长,会强制我将此上下文添加到所有方法调用中)+自定义记录器,将上下文信息添加到记录消息。
使用 MDC 和自定义调度程序;为了实现这种方法,必须使用刚刚弃用的 prepare()调用。
使用 AspectJ
还有其他更简单,更简洁的解决方案吗?可以改变日志库btw ..
答案 0 :(得分:1)
就个人而言,我会采用隐式上下文方法。我从:
开始(path("api" / "test") & get) {
val context = generateContext
action(requestId)
}
然后我会暗示:
(path("api" / "test") & get) {
implicit val context = generateContext
action
}
然后我会将上下文生成一个指令,例如:
val withContext: Directive1[MyContext] = Directive[Tuple1[MyContext]] {
inner => ctx => inner(Tuple1(generateContext))(ctx)
}
withContext { implicit context =>
(path("api" / "test") & get) {
action
}
}
当然,您必须将上下文作为每个操作的隐式参数。但是,它会比MDC和AspectJ有一些优势 - 它会更容易测试,因为你只需要传递价值。此外,谁说你只需要传递请求ID并用它来记录?上下文也可以传递有关登录用户,其权利以及您可以解决的其他事项的数据,甚至在调用操作和重用内部操作之前使用。
正如你可能猜到的那样,如果你想要这样的能力,这将不起作用。完全删除日志记录在这种情况下,AspectJ会更有意义。
我对MDC最怀疑。如果我理解正确的话,它假设所有逻辑都发生在同一个线程中。如果您使用Futures
或Tasks
,您真的可以保证这样吗?我希望所有日志记录调用最好都发生在同一个线程池中,但不一定是同一个线程。
最重要的是,所有可能的结果都是您已经想到的一些变体,所以问题就在于您的确切用例。