java日志框架梳理
因为日常做项目过程中并没有关心日志方面的问题,导致乱使用,出了问题也不知道如何定位和给出解决方案。所以就花了些时间简单了解一下java日志框架。
JCL
JCL(commongs-logging)是一个日志门面,只提供LOG API,不提供具体的实现。所以大家在应用程序中都使用JCL接口,最终程序允许时根据自己的需求选择合适的实现。
image.png
如果用Log4j, 就添加 Log4j 的jar包进去,然后写一个 Log4j 的配置文件;如果喜欢用JUL,就只需要写个 JUL 的配置文件。
如果有其他的新的日志库出现,也只需要它提供一个Adapter,运行的时候把这个日志库的 jar 包加进去。
不过,JCL对LOG4J和JUL的配置问题兼容的并不好,使用JCL可能会遇到类加载问题,导致NoClassDefFoundError的错误出现。
SLF4J
SLF4J(Simple Logging Facade for Java)和 Logback 也是Gülcü 创立的项目,目的是为了提供更高性能的实现。
SLF4J和JCL一样也是只提供了LOG API,不过Logback直接对SLF4J进行了实现。对用户来说,只要使用SLF4J提供的接口,就可隐藏具体的日志实现,用户只需按照它提供的统一纪录日志接口,最终日志的格式、纪录级别、输出方式等可通过具体日志系统的配置来实现,因此可以灵活的切换日志系统。
image.png
上图可以看出,LOG4J和JUL都可以通过桥接到SLF4J,载通过SLF4J适配到LOGBACK,要注意不能形成环状桥接。
LOG4J2
好吧,这也是一个LOG API,他们不希望用户被SLF4J抢夺,就搞出了一个LOG4J2。LOG4J2设计上很大程度上模仿了 SLF4J/Logback,性能上也获得了很大的提升。Log4j2 也做了 Facade/Implementation 分离的设计,分成了 log4j-api 和 log4j-core。
image.png
如何统一日志
因为在第三方依赖中会存在和当前应用不同的日志接口或实现,我们应该都应该统一使用SLF4J和LOGBACK的搭配。关于如何统一日志,那就是上图所示的桥接包,通过分析项目中存在的相关日志接口和实现,按照上图所示的桥接包将日志调用导向SLF4J,SLF4J的实现就使用LOGBACK,类似下图:
image.png image.png
有几点需要注意的是:
1.总是通过日志接口使用日志框架,而不是具体实现。
2.最好保持项目中只有一个日志实现。
3.在maven依赖中具体的日志依赖应该设置为 optional,并使用 runtime scope。设为optional,依赖不会传递,这样如果你是个lib项目,然后别的项目使用了你这个lib,不会被引入不想要的Log Implementation 依赖;Scope设置为runtime,是为了防止开发人员在项目中直接使用Log Implementation中的类,而不使用Log Facade中的类。
4.如果有必要, 排除依赖的第三方库中的Log Impementation依赖。第三方库的开发者未必会把具体的日志实现或者桥接器的依赖设置为optional,你的项目继承了这些依赖,但是你的项目中并不一定希望使用到它的实现。