JAVA Feign 调用日志不打印?Slf4jLogger 与 Logbook 集成配置

JAVA Feign 调用日志不打印?Slf4jLogger 与 Logbook 集成配置

大家好,今天我们来聊聊 Feign 调用日志不打印的问题,以及如何通过 Slf4jLoggerLogbook 这两个强大的工具来解决它,并实现更加灵活和可控的日志记录。

为什么 Feign 日志不打印?

Feign 默认情况下并不会自动打印请求和响应的详细信息。这主要是因为默认配置下,Feign 的日志级别可能没有开启,或者没有配置合适的 Logger。要让 Feign 打印日志,需要进行一些配置。常见的原因主要有以下几个方面:

  1. 日志级别未开启: Feign 自带的日志功能默认是关闭的,需要手动开启。
  2. Logger 未配置: Feign 默认使用 java.util.logging.Logger,但在实际项目中,我们通常更喜欢使用 Slf4j
  3. 配置错误: 即使配置了日志级别和 Logger,如果配置不正确,仍然可能无法打印日志。

使用 Slf4jLogger 开启 Feign 日志

Slf4jLogger 是 Feign 提供的一个简单的 Logger 实现,它将 Feign 的日志输出到 Slf4j。要使用 Slf4jLogger,需要进行以下步骤:

  1. 添加依赖: 确保项目中已经添加了 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>
  2. 配置 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
  3. 配置 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 再次处理,避免重复输出。
  4. 启动应用程序并测试: 启动应用程序,并调用 Feign Client。检查控制台或日志文件,应该能够看到 Feign 的日志信息。

使用 Logbook 实现更强大的日志功能

Logbook 是一个更加强大的 HTTP 请求和响应日志记录库。它提供了更多的配置选项,可以自定义日志格式,过滤敏感信息,以及将日志输出到不同的目的地。

  1. 添加依赖:pom.xml 中添加 Logbook 的依赖。

    <dependency>
       <groupId>org.zalando</groupId>
       <artifactId>logbook-spring-boot-starter</artifactId>
       <version>3.4.0</version> <!-- 使用最新版本 -->
    </dependency>
  2. 配置 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$defaultValueHeaderFilters$defaultValue 分别表示不记录请求的 query 参数和 header 信息。
  3. 配置 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
  4. 配置 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 再次处理,避免重复输出。
  5. 启动应用程序并测试: 启动应用程序,并调用 Feign Client。检查控制台或日志文件,应该能够看到 Logbook 记录的详细的 HTTP 请求和响应信息。

敏感信息过滤

在实际应用中,经常需要过滤掉一些敏感信息,例如密码,信用卡号等。Logbook 提供了多种方式来过滤敏感信息。

  1. 使用 BodyFilters: 可以使用 BodyFilters 来过滤请求和响应的 body。Logbook 提供了几个默认的 BodyFilters,例如 replacetruncatedefaultValue。也可以自定义 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"
  2. 使用 QueryFiltersHeaderFilters: 可以使用 QueryFiltersHeaderFilters 来过滤请求的 query 参数和 header 信息。Logbook 提供了几个默认的 QueryFiltersHeaderFilters,例如 defaultValuereplace。也可以自定义 QueryFiltersHeaderFilters

    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) 文件中配置使用自定义的 QueryFilterHeaderFilter

    logbook.query-filter=@customQueryFilter
    logbook.header-filter=@customHeaderFilter

    或者

    logbook:
     query-filter: "@customQueryFilter"
     header-filter: "@customHeaderFilter"

不同场景下的配置方案

场景 配置方案 优点 缺点
只需要基本的请求和响应信息 使用 Slf4jLogger,并设置 Logger.LevelBASIC 配置简单,易于上手,性能开销小。 只能记录基本的请求和响应信息,无法自定义日志格式,无法过滤敏感信息。
需要详细的请求和响应信息 使用 Slf4jLogger,并设置 Logger.LevelFULL 可以记录详细的请求和响应信息。 无法自定义日志格式,无法过滤敏感信息,可能会泄露敏感信息。
需要自定义日志格式,过滤敏感信息 使用 Logbook,并配置 logbook.format.stylelogbook.body-filterlogbook.query-filterlogbook.header-filter 可以自定义日志格式,过滤敏感信息,将日志输出到不同的目的地。 配置复杂,需要学习 Logbook 的 API,性能开销相对较大。
需要将日志输出到不同的目的地 (例如 ELK) 使用 Logbook,并配置 logbook.sink。可以自定义 Sink,将日志输出到 Elasticsearch,Logstash,Kafka 等。 可以将日志输出到不同的目的地,方便日志分析和监控。 配置非常复杂,需要深入了解 Logbook 的 API,以及目标系统的配置。
开发环境需要详细日志,生产环境需要精简日志 可以使用 Spring Profiles 来区分不同环境下的配置。在开发环境下,使用 Slf4jLogger,并设置 Logger.LevelFULL。在生产环境下,使用 Logbook,并配置 logbook.format.stylehttp,并过滤掉敏感信息。 可以根据不同的环境,选择不同的日志配置,兼顾开发效率和安全性。 配置相对复杂,需要在不同的 Spring Profile 中配置不同的日志配置。

调试技巧

如果在配置了 Feign 日志后,仍然无法打印日志,可以尝试以下方法:

  1. 检查依赖: 确保已经添加了 Slf4j 和 Logback (或者 Log4j2) 的依赖,并且版本兼容。
  2. 检查配置: 仔细检查 Feign Client 的配置类,以及 logback.xml (或者 log4j2.xml) 文件,确保配置正确。
  3. 检查日志级别: 确保 feign.Logger 的日志级别设置为 DEBUG 或者 TRACE
  4. 检查 Logger 名称: 确保 logback.xml (或者 log4j2.xml) 文件中配置的 Logger 名称是 feign.Logger 或者 org.zalando.logbook
  5. 使用调试器: 使用调试器来跟踪 Feign 的执行过程,查看日志是否被正确输出。
  6. 查看日志框架的配置: 确保日志框架的配置正确,例如 Logback 的 logback.xml 文件是否正确加载。

让 Feign 日志输出更清晰

通过以上步骤,我们就可以成功开启 Feign 的日志功能,并利用 Slf4jLogger 或者 Logbook 实现更加灵活和可控的日志记录。

  • Slf4jLogger 提供了一种简单的方式来将 Feign 的日志输出到 Slf4j。
  • Logbook 提供了更加强大的功能,可以自定义日志格式,过滤敏感信息,以及将日志输出到不同的目的地。

选择合适的日志记录方案,可以帮助我们更好地调试和监控应用程序。希望今天的分享对大家有所帮助。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注