前言
前面已经分析了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对象打印请求信息,发起请求后打印请求响应信息,响应解码的信息打印。
Logger抽象类定义好了打印日志的方法,同时OpenFeign给Logger抽象类提供了4个实现类。
由此可知,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,提供给监控平台或者日志云平台分析等。
总结
OpenFeign日志组件实现还是比较简单的,她和其他OpenFeign组件一样提供了的扩展点,我们可以按需实现自己的日志组件,实现个性化的日志打印或者日志上报功能,你在生产环境有没有使用过OpenFeign日志组件呢?欢迎评论区留言分享讨论。