Spring Boot的httptrace端口能够记录每次访问的请求和响应信息,但是不能记录body,这样在出问题时就不方便排查,而且httptrace不方便在原有的基础上进行扩展,所以只能寻求其他方式进行记录。

Logbook是一个可扩展的Java库,可以为不同的客户端和服务端技术提供完整的请求和响应日志记录。它能够满足一些特殊的需求:

允许web应用记录程序接收或发送的所有HTTP通信

易于保留和进行分析

Logbook在大部分情况下是开箱即用的,即使对于一些不常用的技术或者应用,实现它们也非常简单。

特性

日志记录:HTTP请求和响应,包含body;未授权的请求会记录部分日志(不包含body)

自定义:能够自定义记录格式、记录方式以及请求记录的条件

支持框架:Servlet容器,Apache’s HTTP client,Square’s OkHttp等

混淆敏感数据

Spring Boot自动配置

合理的默认值

快速开始

Logbook为Spring Boot用户提供了很方便的自动配置功能,即我们所熟悉的starter

。它使用了合理的默认值自动配置了以下功能:

Servlet filter

适用于未授权请求的Servlet filter(如果检测到项目中使用Spring Security)

Header过滤器、Parameter过滤器、Body过滤器

HTTP格式化器、JSON格式化器

日志写入方式

引入starter

模块:

默认配置下,输出的日志为JSON格式:

Request

Response

配置

下面的表格展示了可配置的选项:

配置项

描述

默认值

logbook.include

仅包含某些URL(如果设置的话)

[]

logbook.exclude

排除某些URL(会覆盖

logbook.include

)

[]

logbook.filter.enabled

是否启用

LogbookFilter

true

logbook.filter.form-request-mode

如何处理表单请求

body

logbook.secure-filter.enabled

是否启用

SecureLogbookFilter

(同时项目中使用Spring Security才会生效)

true

logbook.format.style

格式化样式(

http

json

curl

splunk

)

json

logbook.strategy

策略(

default

status-at-least

body-only-if-status-at-least

without-body

)

default

logbook.minimum-status

启用日志记录的最小HTTP响应状态值,当策略值为

status-at-least

或者

body-only-if-status-at-least

时设置

400

logbook.obfuscate.headers

需要混淆的HTTP Header集合

[Authorization]

logbook.obfuscate.paths

需要混淆的path集合

[]

logbook.obfuscate.parameters

需要混淆的parameter集合

[access_token]

logbook.write.chunk-size

日志拆分块的大小,默认不拆分

0

(禁用)

logbook.write.max-body-size

截取Body的最大长度,后面使用

拼接

-1

(禁用)

配置示例

详细用法

所有的功能集成都需要一个Logbook

实例来完成,它保存了所有的配置并将所有需要的组件连接在一起。你可以使用所有的默认值创建一个实例:

或者使用LogbookBuilder

创建一个自定义的版本:

在使用starter

时,我们只需要自定义相应的Bean

即可。

策略

Logbook使用一个非常硬性的策略来执行请求/响应日志记录:

请求/响应分开记录

请求/响应尽快记录

请求/响应一起记录或不记录

从2.0版本开始,Logbook引入了一个新的策略模式为核心,它内置了部分策略:

BodyOnlyIfStatusAtLeastStrategy

StatusAtLeastStrategy

WithoutBodyStrategy

阶段

Logbook工作在几个不同的阶段:

条件

过滤

格式化

记录

每个阶段都由一个或多个可以自定义的接口完成。每个阶段都有一个合理的默认值。

条件

记录HTTP消息并且包含其body的代价是非常大的,所以禁用某些请求的日志记录非常有意义。一个常见的情景就是忽略一些不必要的请求,比如Spring Boot的Actuator端点。

定义一个条件非常简单,只需要编写一个Predicate

来决定请求是否需要记录。当然,你也可以组合预定义的Predicate

对与路径的包含和排除也可以通过设置logbook.include

和logbook.exclude

属性实现。

过滤

过滤的目的是防止记录HTTP请求和响应的某些敏感数据。这通常包括Authorization请求头,但也可以用于某些明文查询或表单参数,例如access_token和password。

Logbook支持不同类型的过滤器:

类型

作用于

适用于

默认值

QueryFilter

请求参数

request

access_token

PathFilter

路径

request

HeaderFilter

请求头

request/response

Authorization

BodyFilter

Content-Type and body

request/response

json格式:

access_token

refresh_token

,form表单:

client_secret

password

RequestFilter

HttpRequest

request

替换二进制、文件上传和流

ResponseFilter

HttpResponse

response

替换二进制、文件上传和流

QueryFilter

,PathFilter

,HeaderFilter

和BodyFilter

能够满足绝大多数情况下的需求,对于更复杂的需求,可以使用RequestFilter

和ResponseFilter

关联

Logbook使用一个id来关联请求和响应,因为请求和响应通常位于日志文件中的不同位置。

在Spring Cloud应用中一般会集成Zipkin进行链路追踪,此时可以使用TraceId来关联请求和响应日志记录。

如果默认实现不满足你的需求,你可以提供一个自定义的实现:

格式化

格式化定义了如何把请求和响应转换为字符串的方式。格式化不会指定请求和响应的记录位置,这是由writer来完成的。

Writer

Writer定义了格式化后的请求和响应写入的位置。Logbook内置了三种实现:Logger,Stream和Chunking。

Logger

默认情况下,请求和响应使用了slf4j来进行日志记录,日志的级别为trace

。你也可以自定义:

Stream

另一种实现方式是记录请求和响应到PrintStream

,例如System.out

或System.err

。在生产环境中这是一个糟糕的选择,但有时对于短暂的本地开发和调试很有用。

Chunking

ChunkingSink

会把长的消息分割成较小的块,并且会委托给另一个sink将它们写入,只需要设置logbook.write.chunk-size

属性即可。

Sink

HttpLogFormatter

和HttpLogWriter

的组合能够适用于大部分场合,但是也有一些局限性。实现Sink

接口可以实现更复杂的需求,例如把请求和响应持久化到数据库。

你可以使用CompositeSink

将多个Sink合并为一个。

Servlet

在Servlet环境中,Logbook是通过LogbookFilter

来实现的。默认情况下,对于application/x-www-form-urlencoded

请求会同等对待,即你会在日志中看到请求body。这种方法的缺点是下游代码将无法使用任何HttpServletRequest.getParameter*(..)

方法。

从Logbook 1.5.0开始,可以使用logbook.servlet.form-request

系统属性(System Property)指定三种策略之一,这些策略定义Logbook如何处理这种情况:

属性值

优点

缺点

body

(默认)

body会被记录

下游代码不能使用

getParameter*()

parameter

body会被记录

下游代码不能使用

getInputStream()

off

下游代码可以使用

getParameter*()

或者

getInputStream()

body不会被记录

其他框架支持

Logbook默认还提供了对HTTP Client、JAX-RS、Netty、OkHttp v2.x、OkHttp v3.x的支持,具体使用方法可以参考官方文档。