log

日志框架的兼容性

另一篇文档:https://my.oschina.net/pingpangkuangmo/blog/406618

日志facade:

编程的时候,对外提供的jar中应该只能引用日志的facade,目前常见的日志facade包有:

  • log4j的日志api,log4j的api与log4j的实现在同一个包中;
  • log4j2的日志api;
  • JCL(Jakarta Common Log)(commons-logging),这个也只是一个api;
  • slf4j(Simple Log Facade for Java) api;

日志实现系统。

这些包建议可以只在运行阶段引入(runtime),要不当别人的系统使用的日志实现与你提供的jar使用的不是同一个日志实现的时候,会有问题,可能造成你jar中的日志打印不出来或者报缺少包。目前常见的日志实现包有:

  • log4j的日志实现;
  • log4j2的日志实现;
  • slf4j 的具体实现是logback;
  • JUL 的具体实现在JDK中;

日志接口桥接器(接口转换器):

所谓的桥接器就是一个假的日志实现工具, 目前最流行的日志facade是slf4j, 由于历史原因,一些三方包已经使用了其它的日志facade, 比如,早期Spring, Apache引用的都是commons-logging的facade,那为了兼容这些接口,则就有了日志接口桥接器,也即将这些接口通过代理,转发到slf4j接口上去。

日志实现适配器:

slf4j的直接实现是logback, slf4j为了使用log4j的实现(slf4j-log4j12),slf4j适配jdk 日志的实现(slf4j-jdk14)。

日志接口桥接器(将别人的日志接口桥接到自己的日志系统) 与 日志实现适配器(将自己的日志接口适配别人的日志接口或实现) 并没有严格的区分,这两者的使用并没有一个强制的规范,这里也是引用日志的包最容易出现问题的地方,很容易互相转换,造成死循环。比如,同时引入 log4j-over-slf4j.jar 与 slf4j-log4j12 就会有问题。

  • log4j-over-slf4j 与 slf4j-log4j12 不能并存
  • log4j-slf4j-impl 与 slf4j-log4j12 不能并存
  • log4j-slf4j-impl 与 log4j-to-slf4j 不能并存
  • log4j-jcl 与 jcl-over-slf4j 不能并存
  • jcl-over-slf4j 与 commons-logging 不能并存

如何确定要使用哪些桥接器,重要的是看你使用哪个日志facade及哪个日志实现系统,并要兼容哪些日志接口。

基于目前最常见的搭配 slf4j+log4j, slf4j+log4j2, 下面给出这两种搭配的最佳实践:

  • slf4j+log4j, 即自己的应用使用slf4j facade 并使用 lof4j日志实现系统;
  • slf4j + log4j2 即自己的应用使用slf4j facade 并使用 lof4j2日志实现系统;

异常注意事项

  1. 异常被打印的地方(logger);
  2. 异常的类型:异常的内容(message);
  3. at 后面是异常的堆栈信息,从 异常产生的地方(new或jvm产生) 到 最初调用的地方;
  4. Caused by 顾名思义,真正发生问题的地方,最下面的是直接原因;
  5. 分清 异常产生的地方(new或jvm产生) 与 异常被打印的地方(logger);
  6. catch 异常后可以抛出一个新的异常,也可抛出原异常,还可忽略异常继续执行;异常设计(catch,new E)很重要,混乱的异常设计不利于问题排查;

日志注意事项

  1. 打印前一般会先判断级别是否合适;info日志一般是包含关键信息的字符串,格式化要借助String.format()函数;error日志要输出异常的堆栈信息;
  2. 日志的格式怎么:时间,级别,(线程),名称或者类,这四样是固定的,其他的想怎么打怎么打;
  3. 应用下日志的分类:中间件(rpc,health-check,tracelog),本应用各子模块日志;

logbakc日志框架要点

appender -指定日志文件名,日志格式,日志文件最大天数;
logger -指向代码中的日志name,或者日志class,需要ref上面的appender
root -指向代码中的其他日志(除去上面的指定)
springProfile -在指定的profile下才生效

log4j2 日志框架

RollingFile -指定日志文件名
AsyncLogger/Logger -指向代码中的日志name,或者日志class

Tracer

TraceId 不是rpc拦截器,是SofaRequest的一个属性传下去的。