spray.io logRequestResponse 到专用日志文件

spray.io logRequestResponse to a dedicated log file

我正在为 REST api 使用 spray 框架和调试指令 logRequestResponse。我想创建一个审核日志 - 专用日志,其中包含有关访问此 api Request/Reply 的信息。为此,我正在使用 logRequestResponse,但我很难将这些日志记录分离到专用日志中。我可以提供一个标记而不是记录器,并且不能使用记录器,因为它是主要的记录器。 特征 RestApi 扩展指令 { this: ServiceActors with Core =>

// 我们将封闭的 ActorContext 或 ActorSystem 的调度程序用于我们的 Futures 和调度程序 私有隐式 val _ = system.dispatcher 隐式 val 超时 = 超时(30.seconds)

  val route: Route = 
    logRequestResponse("REST API", Logging.InfoLevel){
        new DataServiceApi(dataService).route ~
        new AnalyticsServiceApi(analyticsService).route
    }

2015-10-22 12:59:45,599 [INFO ] [BackEndServices-akka.actor.default-dispatcher-16] [akka.actor.ActorSystemImpl]ActorSystem(BackEndServices) - REST API: Response for
  Request : HttpRequest(GET,http://localhost:8080/service/analytics/ ...
  Response: HttpResponse(200 OK,HttpEntity(application/json; charset=UTF-8, ...

有没有简单的方法可以实现?

如果深入研究一下实现,您会发现 logRequestResponse 指令最终使用了 Akka 提供的日志记录工具。因此,如果您还没有查看 Akka 日志记录文档,您绝对应该查看。

Akka 2.4.0 Logging

如果您想将您的请求和响应记录到一个单独的日志文件,您最好利用您正在使用的任何日志库。

假设您正在使用 Logback,因为 Akka 为 SLF4J 提供了良好的支持,并且团队推荐它。

要开始将您的请求和响应记录到单独的日志文件中,您需要:

  1. 将您的 Spray/Akka 应用配置为使用 Logback
  2. 在您的 logback.xml
  3. 中配置单独的记录器和附加器

对于第 1 步,请执行以下操作(这些都在 Akka 文档中):

  1. 同时将 akka-slf4j jar 打包到您的项目中
  2. 将此配置添加到 application.conf

application.conf

akka {
  loggers = ["akka.event.slf4j.Slf4jLogger"]
  loglevel = "DEBUG"
}

对于第 2 步,您的 logback.xml 应该有 2 个附加程序 -- 一个用于记录所有内容的控制台,另一个用于捕获 logRequestResponse 指令生成的日志。类似于您在下面看到的内容:

logback.xml

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <target>System.out</target>
    <encoder>
        <pattern>%date{ISO8601} %-5level %logger{36} %X{akkaSource} - %msg%n</pattern>
    </encoder>
</appender>

<appender name="ACCESS" class="ch.qos.logback.core.FileAppender">
    <file>access.log</file>
    <encoder>
        <pattern>%date{ISO8601} %-5level %logger{36} %X{akkaSource} - %msg%n</pattern>
    </encoder>
</appender>


<root>
    <appender-ref ref="CONSOLE"/>
</root>

<logger name="akka.actor.RepointableActorRef" level="INFO">
    <appender-ref ref="ACCESS" />
</logger>

<logger name="akka" level="INFO"/>

这应该将您的请求和响应记录到 access.log 文件。

有一件事不是特别好,那就是我们的记录器总是输出为 "akka.actor.RepointableActorRef"。你可能最终会得到你不关心的额外日志语句写入该文件。

这是实施 Spray 的 LoggingContext 的结果,它最终通过将 ActorRef 类型传递给 LoggingAdapter 构造函数来构建 LoggingAdapter。

Logging(context.system.eventStream, context.self)

我们可以通过在您的路由中混合一个实现我们自己的 LoggingMagnet 并使用我们构建的 LoggingAdapter(而不是 Spray 库)的特征来解决这个问题。

像这样:

import akka.actor.Actor
import akka.event.Logging
import spray.http.HttpRequest
import spray.routing.directives.LoggingMagnet


trait AccessLogger { this: Actor =>

  val accessLogger: LoggingMagnet[HttpRequest => Any => Unit] = LoggingMagnet {
    request => response =>
      val accessLogger = Logging(context.system.eventStream, "com.my.AccessLogger")
      accessLogger.info("Request: " + request + "\n Response: " + response)
  }

}

对于你这个 jaksky,我想你可能会把 AccessLogger 混入 RestApi

从 logback.xml 更新记录器:

<logger name="akka.actor.RepointableActorRef" level="INFO">
    <appender-ref ref="ACCESS" />
</logger>

...为此:

<logger name="com.my.AccessLogger" level="INFO">
    <appender-ref ref="ACCESS" />
</logger>

然后,您可以将 accessLogger 从 AccessLogger 特征传递到 logRequestResponse 指令中

logRequestResponse(accessLogger){
  //... rest of route ...
}

应用这些更改后,您的所有请求和响应都应记录到 com.my.AccessLogger 记录器,该记录器又被配置为写入其自己的文件,如 ACCESS 附加程序中所配置的那样。

如果您对使用 Logback 或 Akka 进行日志记录不感兴趣,您始终可以使用类似的方法,但只需提供 AccessLogger 的不同实现即可。