JAVA Feign 调用日志不打印?Slf4jLogger 与 Logbook 集成配置
大家好,今天我们来聊聊 Feign 调用日志不打印的问题,以及如何通过 Slf4jLogger 和 Logbook 这两个强大的工具来解决它,并实现更加灵活和可控的日志记录。
为什么 Feign 日志不打印?
Feign 默认情况下并不会自动打印请求和响应的详细信息。这主要是因为默认配置下,Feign 的日志级别可能没有开启,或者没有配置合适的 Logger。要让 Feign 打印日志,需要进行一些配置。常见的原因主要有以下几个方面:
- 日志级别未开启: Feign 自带的日志功能默认是关闭的,需要手动开启。
- Logger 未配置: Feign 默认使用
java.util.logging.Logger,但在实际项目中,我们通常更喜欢使用Slf4j。 - 配置错误: 即使配置了日志级别和 Logger,如果配置不正确,仍然可能无法打印日志。
使用 Slf4jLogger 开启 Feign 日志
Slf4jLogger 是 Feign 提供的一个简单的 Logger 实现,它将 Feign 的日志输出到 Slf4j。要使用 Slf4jLogger,需要进行以下步骤:
-
添加依赖: 确保项目中已经添加了 Slf4j 的依赖。如果使用 Maven,可以在
pom.xml中添加:<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.9</version> <!-- 使用最新版本 --> </dependency>同时,还需要添加 Slf4j 的具体实现,例如 Logback 或者 Log4j2。例如,使用 Logback:
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.4.11</version> <!-- 使用最新版本 --> </dependency> -
配置 Feign Client: 在 Feign Client 的配置类中,使用
Slf4jLogger作为 Logger。import feign.Logger; import feign.slf4j.Slf4jLogger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; // 设置日志级别 } @Bean Logger logger() { return new Slf4jLogger(); } }feignLoggerLevel()方法用于设置 Feign 的日志级别。Logger.Level有以下几个选项:NONE: 不记录任何日志。BASIC: 仅记录请求方法和 URL,以及响应状态码和执行时间。HEADERS: 记录基本信息,以及请求和响应的头部信息。FULL: 记录所有信息,包括请求和响应的 body。
logger()方法用于配置 Feign 使用Slf4jLogger。
-
配置 Logback (或者 Log4j2): 配置 Logback (或者 Log4j2) 来控制日志的输出。创建一个
logback.xml(或者log4j2.xml) 文件,并配置相应的 Appender 和 Logger。<!-- logback.xml --> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="feign.Logger" level="DEBUG" additivity="false"> <appender-ref ref="STDOUT" /> </logger> <root level="INFO"> <appender-ref ref="STDOUT" /> </root> </configuration><logger name="feign.Logger" level="DEBUG"这行配置指定了feign.Logger的日志级别为DEBUG。这意味着所有 Feign 的日志都会以DEBUG级别输出。additivity="false"阻止 Feign 的日志被 root logger 再次处理,避免重复输出。
-
启动应用程序并测试: 启动应用程序,并调用 Feign Client。检查控制台或日志文件,应该能够看到 Feign 的日志信息。
使用 Logbook 实现更强大的日志功能
Logbook 是一个更加强大的 HTTP 请求和响应日志记录库。它提供了更多的配置选项,可以自定义日志格式,过滤敏感信息,以及将日志输出到不同的目的地。
-
添加依赖: 在
pom.xml中添加 Logbook 的依赖。<dependency> <groupId>org.zalando</groupId> <artifactId>logbook-spring-boot-starter</artifactId> <version>3.4.0</version> <!-- 使用最新版本 --> </dependency> -
配置 Logbook: 在
application.properties(或者application.yml) 文件中配置 Logbook。# application.properties logbook.format.style=json logbook.strategy=org.zalando.logbook.DefaultStrategy logbook.include=org.zalando.logbook.BodyFilters$defaultValue logbook.exclude=org.zalando.logbook.QueryFilters$defaultValue,org.zalando.logbook.HeaderFilters$defaultValue或者
# application.yml logbook: format: style: json strategy: org.zalando.logbook.DefaultStrategy include: org.zalando.logbook.BodyFilters$defaultValue exclude: org.zalando.logbook.QueryFilters$defaultValue,org.zalando.logbook.HeaderFilters$defaultValue一些常用的配置项:
logbook.format.style: 指定日志格式。可以设置为http(默认),json, 或者自定义格式。logbook.strategy: 指定日志记录策略。DefaultStrategy会记录所有的请求和响应。logbook.include: 指定要包含的过滤器。BodyFilters$defaultValue表示记录请求和响应的 body。logbook.exclude: 指定要排除的过滤器。QueryFilters$defaultValue和HeaderFilters$defaultValue分别表示不记录请求的 query 参数和 header 信息。
-
配置 Feign Client: 使用 Logbook 的
LogbookInterceptor来拦截 Feign 的请求和响应。import feign.RequestInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.zalando.logbook.Logbook; import org.zalando.logbook.feign.LogbookInterceptor; @Configuration public class FeignConfig { @Bean RequestInterceptor logbookInterceptor(final Logbook logbook) { return new LogbookInterceptor(logbook); } }logbookInterceptor()方法创建一个LogbookInterceptor,并将其注册为 Feign 的RequestInterceptor。
-
配置 Logback (或者 Log4j2): 配置 Logback (或者 Log4j2) 来控制 Logbook 的日志输出。
<!-- logback.xml --> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="org.zalando.logbook" level="INFO" additivity="false"> <appender-ref ref="STDOUT" /> </logger> <root level="INFO"> <appender-ref ref="STDOUT" /> </root> </configuration><logger name="org.zalando.logbook" level="INFO"这行配置指定了org.zalando.logbook的日志级别为INFO。这意味着所有 Logbook 的日志都会以INFO级别输出。additivity="false"阻止 Logbook 的日志被 root logger 再次处理,避免重复输出。
-
启动应用程序并测试: 启动应用程序,并调用 Feign Client。检查控制台或日志文件,应该能够看到 Logbook 记录的详细的 HTTP 请求和响应信息。
敏感信息过滤
在实际应用中,经常需要过滤掉一些敏感信息,例如密码,信用卡号等。Logbook 提供了多种方式来过滤敏感信息。
-
使用
BodyFilters: 可以使用BodyFilters来过滤请求和响应的 body。Logbook 提供了几个默认的BodyFilters,例如replace,truncate,defaultValue。也可以自定义BodyFilters。import org.zalando.logbook.BodyFilter; import org.zalando.logbook.BodyFilters; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class LogbookConfig { @Bean BodyFilter customBodyFilter() { return BodyFilters.replace( "password", "<PASSWORD>") // 将 body 中的 "password" 替换为 "<PASSWORD>" .andThen(BodyFilters.truncate(1024)); // 截断 body 到 1024 个字符 } }在
application.properties(或者application.yml) 文件中配置使用自定义的BodyFilter。logbook.body-filter=@customBodyFilter或者
logbook: body-filter: "@customBodyFilter" -
使用
QueryFilters和HeaderFilters: 可以使用QueryFilters和HeaderFilters来过滤请求的 query 参数和 header 信息。Logbook 提供了几个默认的QueryFilters和HeaderFilters,例如defaultValue,replace。也可以自定义QueryFilters和HeaderFilters。import org.zalando.logbook.QueryFilter; import org.zalando.logbook.QueryFilters; import org.zalando.logbook.HeaderFilter; import org.zalando.logbook.HeaderFilters; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class LogbookConfig { @Bean QueryFilter customQueryFilter() { return QueryFilters.replace("credit_card", "<CREDIT_CARD>"); // 将 query 参数中的 "credit_card" 替换为 "<CREDIT_CARD>" } @Bean HeaderFilter customHeaderFilter() { return HeaderFilters.replace("Authorization", "<AUTHORIZATION>"); // 将 header 中的 "Authorization" 替换为 "<AUTHORIZATION>" } }在
application.properties(或者application.yml) 文件中配置使用自定义的QueryFilter和HeaderFilter。logbook.query-filter=@customQueryFilter logbook.header-filter=@customHeaderFilter或者
logbook: query-filter: "@customQueryFilter" header-filter: "@customHeaderFilter"
不同场景下的配置方案
| 场景 | 配置方案 | 优点 | 缺点 |
|---|---|---|---|
| 只需要基本的请求和响应信息 | 使用 Slf4jLogger,并设置 Logger.Level 为 BASIC。 |
配置简单,易于上手,性能开销小。 | 只能记录基本的请求和响应信息,无法自定义日志格式,无法过滤敏感信息。 |
| 需要详细的请求和响应信息 | 使用 Slf4jLogger,并设置 Logger.Level 为 FULL。 |
可以记录详细的请求和响应信息。 | 无法自定义日志格式,无法过滤敏感信息,可能会泄露敏感信息。 |
| 需要自定义日志格式,过滤敏感信息 | 使用 Logbook,并配置 logbook.format.style,logbook.body-filter,logbook.query-filter,logbook.header-filter。 |
可以自定义日志格式,过滤敏感信息,将日志输出到不同的目的地。 | 配置复杂,需要学习 Logbook 的 API,性能开销相对较大。 |
| 需要将日志输出到不同的目的地 (例如 ELK) | 使用 Logbook,并配置 logbook.sink。可以自定义 Sink,将日志输出到 Elasticsearch,Logstash,Kafka 等。 |
可以将日志输出到不同的目的地,方便日志分析和监控。 | 配置非常复杂,需要深入了解 Logbook 的 API,以及目标系统的配置。 |
| 开发环境需要详细日志,生产环境需要精简日志 | 可以使用 Spring Profiles 来区分不同环境下的配置。在开发环境下,使用 Slf4jLogger,并设置 Logger.Level 为 FULL。在生产环境下,使用 Logbook,并配置 logbook.format.style 为 http,并过滤掉敏感信息。 |
可以根据不同的环境,选择不同的日志配置,兼顾开发效率和安全性。 | 配置相对复杂,需要在不同的 Spring Profile 中配置不同的日志配置。 |
调试技巧
如果在配置了 Feign 日志后,仍然无法打印日志,可以尝试以下方法:
- 检查依赖: 确保已经添加了 Slf4j 和 Logback (或者 Log4j2) 的依赖,并且版本兼容。
- 检查配置: 仔细检查 Feign Client 的配置类,以及
logback.xml(或者log4j2.xml) 文件,确保配置正确。 - 检查日志级别: 确保
feign.Logger的日志级别设置为DEBUG或者TRACE。 - 检查 Logger 名称: 确保
logback.xml(或者log4j2.xml) 文件中配置的 Logger 名称是feign.Logger或者org.zalando.logbook。 - 使用调试器: 使用调试器来跟踪 Feign 的执行过程,查看日志是否被正确输出。
- 查看日志框架的配置: 确保日志框架的配置正确,例如 Logback 的
logback.xml文件是否正确加载。
让 Feign 日志输出更清晰
通过以上步骤,我们就可以成功开启 Feign 的日志功能,并利用 Slf4jLogger 或者 Logbook 实现更加灵活和可控的日志记录。
Slf4jLogger提供了一种简单的方式来将 Feign 的日志输出到 Slf4j。Logbook提供了更加强大的功能,可以自定义日志格式,过滤敏感信息,以及将日志输出到不同的目的地。
选择合适的日志记录方案,可以帮助我们更好地调试和监控应用程序。希望今天的分享对大家有所帮助。