Scala Akka http日志记录请求标识符

Scala Akka http日志记录请求标识符,scala,logging,akka,akka-http,Scala,Logging,Akka,Akka Http,我使用akka http已经有一段时间了,到目前为止,我主要是通过扩展StrictLogging或LazyLogging然后调用 log.info log.debug .... 这还可以,但很难理解为哪个请求生成了哪些日志 作为解决方案,我只看到: 添加传递的隐式日志上下文(这有点冗长,会迫使我将此上下文添加到所有方法调用中)+将上下文信息添加到日志消息的自定义记录器 使用MDC和自定义调度程序;为了实现这种方法,必须使用刚刚被弃用的prepare()调用 使用AspectJ 还有其他更直

我使用akka http已经有一段时间了,到目前为止,我主要是通过扩展StrictLoggingLazyLogging然后调用

log.info
log.debug
....
这还可以,但很难理解为哪个请求生成了哪些日志

作为解决方案,我只看到:

  • 添加传递的隐式日志上下文(这有点冗长,会迫使我将此上下文添加到所有方法调用中)+将上下文信息添加到日志消息的自定义记录器

  • 使用MDC和自定义调度程序;为了实现这种方法,必须使用刚刚被弃用的prepare()调用

  • 使用AspectJ


还有其他更直接、更不冗长的解决方案吗?顺便说一句,更改日志库是可以的。

我个人会使用隐式上下文方法。首先,我要说:

(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并将其用于日志记录?上下文还可以传递有关已登录用户的数据、其权限以及您可以一次性解析、甚至在调用action之前使用的其他内容,并在action内部重用

正如您可能猜到的,如果您希望能够(例如)完全删除日志记录,这将不起作用。在这种情况下,AspectJ更有意义

我对MDC有很大的怀疑。如果我理解正确的话,它有一个内置的假设,即所有逻辑都会发生在同一个线程中。如果你使用的是
期货
任务
,你真的能保证这一点吗?我希望所有日志调用最多都发生在同一个线程池中,但不一定是同一个线程


底线是,所有可能的位置都是您已经计算出的某个变体,所以问题是您的确切用例。

谢谢Mateusz。。隐式上下文几乎就是我要使用的方法,唯一的不便是必须将日志上下文作为参数添加到每个希望能够记录内容的方法中,这有点麻烦。我想我只是希望有一个更好的,更少干扰的方式来做这件事是的,不幸的是,这是我看到的唯一合理的方式,如果你想访问动作内部的记录器。如果它只是一个包装器,例如记录请求执行时间,那么您可以不在其中传递任何内容而将其删除。您可以在请求和响应中添加一个合成头,以通过路由树传递上下文。我们也在考虑添加请求/响应属性,甚至可能添加RequestContext属性,这对该用例也有帮助。。这是服务间通信的方法,但问题是传播这些头的值,以便服务代码(服务、DAO、DAL等)也可以将它们记录在日志消息中。。