OpenFeign日志组件Logger原理与应用

527 阅读2分钟

前言

前面已经分析了OpenFeign三个组件了

今天还是继续分析OpenFeign的组件,分布式rpc服务调用的日志信息是非常关键的,OpenFeign提供了Logger组件,通过Logger组件可以实现openfeign接口调用的日志的打印。

OpenFeign日志打印源码

OpenFeign如何打印日志的,我们可以看到OpenFeign执行请求主流程源码 位于feign.SynchronousMethodHandler#executeAndDecode

Object executeAndDecode(RequestTemplate template) throws Throwable {

Request request = targetRequest(template);

//打印请求日志

if (logLevel != Logger.Level.NONE) {

logger.logRequest(metadata.configKey(), logLevel, request);

}

Response response;

long start = System.nanoTime();

try {

response = client.execute(request, options);

} catch (IOException e) {

//异常日志打印

if (logLevel != Logger.Level.NONE) {

logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));

}

throw errorExecuting(request, e);

}

long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);

boolean shouldClose = true;

try {

//日志打印响应

if (logLevel != Logger.Level.NONE) {

response = logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);

}

//相应解码

Object result = decode(response);

return result;

} catch (IOException e) {

//打印响应解码日志

if (logLevel != Logger.Level.NONE) {

logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);

}

throw errorReading(request, response, e);

}

}

从源码可以看出,OpenFeign分别在发起请求前使用Logger对象打印请求信息,发起请求后打印请求响应信息,响应解码的信息打印。

image.png

Logger抽象类定义好了打印日志的方法,同时OpenFeign给Logger抽象类提供了4个实现类。

image.png

由此可知,OpenFeign默认支持Slf4j,JavaLogger等日志组件。

OpenFeign默认使用Slf4j日志组件

我们在自动装配类FeignClientsConfiguration中,发现没有配置Logger的Bean实现。 只是配置了FeignLoggerFactory的Bean是DefaultFeignLoggerFactory

那么OpenFeign默认使用什么日志组件呢?通过feignLoggerFactory就可以看得出来。

@Configuration(
    proxyBeanMethods = false
)
public class FeignClientsConfiguration {

    @Autowired(required = false)
    private Logger logger;
    @Bean
    @ConditionalOnMissingBean(FeignLoggerFactory.class)
    public FeignLoggerFactory feignLoggerFactory() {
       return new DefaultFeignLoggerFactory(this.logger);
    }
}    
public class DefaultFeignLoggerFactory implements FeignLoggerFactory {

   private Logger logger;

   public DefaultFeignLoggerFactory(Logger logger) {
      this.logger = logger;
   }

   @Override
   public Logger create(Class<?> type) {
      //logger为空,默认使用log4j
      return this.logger != null ? this.logger : new Slf4jLogger(type);
   }

}

由此可知OpenFeign默认使用Slf4j日志组件打印日志。

日志级别

在Logger抽象类的方法参数里,对request和response方法日志打印还支持日志Level,日志等级共有4个。

public static enum Level {
    NONE,//不打印
    BASIC, //打印基本信息
    HEADERS,//只打印头
    FULL; //全部打印

    private Level() {
    }
}

定制日志组件与日志级别

  • 针对单个Feign客户端
public class TestFeignClientConfiguration {
    
    @Bean
    public Logger logger() {
        return new Logger.JavaLogger();
    }
    
    @Bean 
    public Logger.Level level() {
        return  Logger.Level.FULL;
    }
}


@RestController
@FeignClient(value = "fox-server", configuration = TestFeignClientConfiguration.class)
public interface FeignService {
    @PostMapping("/get")
    String getName(@RequestBody @Validated DemoRequest request);
}
  • 针对全局Feign客户端
@Configuration
public class TestFeignClientConfiguration {
    
    @Bean
    public Logger logger() {
        return new Logger.JavaLogger();
    }
    
    @Bean 
    public Logger.Level level() {
        return  Logger.Level.FULL;
    }
}
  • 自定义日志组件

我们也可以自己实现自己的日志组件,只要继承抽象类feign.Logger,实现log方法,比如我们想把日志上报到kafka,提供给监控平台或者日志云平台分析等。

image.png

总结

OpenFeign日志组件实现还是比较简单的,她和其他OpenFeign组件一样提供了的扩展点,我们可以按需实现自己的日志组件,实现个性化的日志打印或者日志上报功能,你在生产环境有没有使用过OpenFeign日志组件呢?欢迎评论区留言分享讨论。

image.png