1. 概述

HTTP API请求已成为现代应用的标配组件。Logbook是一个可扩展的Java库,能为不同客户端和服务端技术提供完整的请求/响应日志记录功能。它允许开发者记录应用接收或发送的任何HTTP流量,可用于日志分析、审计或流量问题排查。

本文将介绍如何将Logbook库集成到Spring Boot应用中。

2. 依赖配置

在Spring Boot中使用Logbook库,需添加以下依赖:

<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>logbook-spring-boot-starter</artifactId>
    <version>3.9.0</version>
</dependency>

最新版本可在Maven中央仓库获取。

3. 基础配置

Logbook与Spring Boot中的logback日志系统协同工作。我们需要在logback-spring.xmlapplication.properties文件中添加配置

添加Logbook依赖后,Spring Boot会自动配置Logbook。首先在application.properties中设置日志级别:

logging.level.org.zalando.logbook.Logbook=TRACE

TRACE级别会启用HTTP请求和响应的日志记录。

接着在logback-spring.xml中添加Logbook配置:

<logger name="org.zalando.logbook" level="INFO" additivity="false">
    <appender-ref ref="RollingFile"/>
</logger>

完成配置后启动应用并发起HTTP请求。每次HTTP调用后,Logbook会将请求和响应记录到logback-spring.xml中指定的日志文件

11:08:14.737 [http-nio-8083-exec-10] TRACE org.zalando.logbook.Logbook - Incoming Request: eac2321df47c4414
Remote: 0:0:0:0:0:0:0:1
GET http://localhost:8083/api/hello?name=James HTTP/1.1
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
accept-encoding: gzip, deflate, br, zstd
...
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
11:08:14.741 [http-nio-8083-exec-10] TRACE org.zalando.logbook.Logbook - Outgoing Response: eac2321df47c4414
Duration: 4 ms
HTTP/1.1 200 OK
...
Date: Tue, 18 Jun 2024 05:38:14 GMT
Keep-Alive: timeout=60

Hello, James!

以上展示了Logbook与Spring Boot的最小化集成。但这只是基础的请求/响应日志,接下来我们探讨更高级的配置。

4. 过滤与格式化

4.1 过滤配置

我们可以声明Logbook的配置Bean:

@Bean
public Logbook logbook() {
    return Logbook.builder()
      .condition(Conditions.exclude(Conditions.requestTo("/api/welcome"), 
        Conditions.contentType("application/octet-stream"), 
        Conditions.header("X-Secret", "true")))
      .sink(new DefaultSink(new DefaultHttpLogFormatter(), new DefaultHttpLogWriter()))
      .build();
}

上述代码中,我们声明了Logbook Bean供Spring Boot加载配置。

在构建Logbook Bean时,我们指定了过滤条件。**exclude()方法中指定的请求映射会被排除在日志记录之外**。例如,路径为/api/welcome的API请求/响应不会被记录。同样,我们通过contentType()header()方法对请求内容类型和请求头进行了过滤。

需要记录的HTTP API应在include()方法中指定。如果不使用include(),Logbook会记录所有请求(exclude()中指定的除外)。

要使过滤配置生效,需在application.properties中设置:

logbook.filter.enabled=true

4.2 日志格式化

Logbook默认使用sl4j logger记录日志,类别为org.zalando.logbook.Logbook,日志级别为trace

sink(new DefaultSink(
  new DefaultHttpLogFormatter(),
  new DefaultHttpLogWriter()
))

要改变日志格式,需修改logback-spring.xml中appender的encoder。Logstash encoder启用LogstashLogbackSink

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    ... 
    <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>

然后声明LogstashLogbackSink并添加到Logbook构建器:

HttpLogFormatter formatter = new JsonHttpLogFormatter(); 
LogstashLogbackSink logstashsink = new LogstashLogbackSink(formatter);
Logbook logbook = Logbook.builder()
  .sink(logstashsink)
  .build();

这里使用JsonHttpLogFormatterLogstashLogbackSink组合,将日志输出为JSON格式

{
    "@timestamp": "2024-06-07T16:46:24.5673233+05:30",
    "@version": "1",
    "message": "200 OK GET http://localhost:8083/api/hello?name=john",
    "logger_name": "org.zalando.logbook.Logbook",
    "thread_name": "http-nio-8083-exec-6",
    "level": "TRACE",
    "http":  {
        ...
        "Content-Length": [
            "12"
        ],
        ...
        "body": "Hello, john!"
    }
}

⚠️ JSON日志实际输出为单行,此处为便于阅读进行了格式化。

声明LogstashLogbackSink时可修改日志级别

LogstashLogbackSink logstashsink = new LogstashLogbackSink(formatter, Level.INFO);

也可使用SplunkHttpLogFormatter输出键值对格式:

origin=remote ... method=GET uri=http://localhost:8083/api/hello?name=John host=localhost path=/api/hello ...

4.3 组合Sink

通过组合多个Sink可形成CompositeSink

CompositeSink compsink = new CompositeSink(Arrays.asList(logstashsink, new CommonsLogFormatSink(new DefaultHttpLogWriter())));
Logbook logbook = Logbook.builder()
  .sink(compsink)
  .build();

此配置会使用组合Sink中的所有Sink记录请求详情。示例中Logbook通过两个Sink记录请求:

... "message":"GET http://localhost:8083/api/hello?name=John",... uri":"http://localhost:8083/api/hello?name=John",...
... "message":"200 OK GET http://localhost:8083/api/hello?name=John",.."headers":{"Connection":["keep-alive"],...

5. 总结

本文介绍了如何通过最小化配置将Logbook库集成到Spring Boot应用,以及如何使用exclude()include()方法过滤请求路径。还展示了如何通过LogstashLogbackSink等Sink实现配合JsonHttpLogFormatter等格式化器自定义日志格式。

完整源码示例可在GitHub获取。


原始标题:HTTP Request and Response Logging Using Logbook in Spring | Baeldung