日志系统是一个成熟 Java 应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位 bug;在运行维护阶段,日志系统又可以帮我们记录大部分的异常信息,从而帮助我们更好的完善系统。通常很多企业会通过收集日志信息来对系统的运行状态进行实时监控预警。
Java 中主要有2种日志接口,一个是 Apache 的 Commons 项目的 Logging 组件,它是一个日志的通用接口,另外一个是 SLF4J 它是一个日志的抽象层。
Java 日志演化历史
- 最开始出现的是 log4j,也是应用最广泛的日志系统,作者是 Ceki Gülcü,开始时,一切都是美好的。
- 但 java 的开发主体 Sun 公司认为自己才是正统,为了干掉 log4j,在 jdk1.4 中增加了 jul(因为在
java.util.logging
包下)日志的实现,造成了目前开发者的混乱,迄今为止仍饱受诟病。 - 各个日志系统互相没有关联,替换和统一变的非常麻烦。A 项目用 log4j 作为日志系统,但同时引了 B 项目,而 B 项目用 jul 作为日志系统,那么你的应用就得使用两个日志系统。
- 为了搞定这个坑爹的问题,开源社区 apache 提供了一个日志框架作为日志的抽象,叫 commons-logging,也被称为 jcl(java common logging),jcl 对各种日志接口进行抽象,抽象出一个接口层,对每个日志实现都适配或者桥接,这样这些提供给别人的库都直接使用抽象层即可,较好的解决了上述问题。
- 当年 Apache 说服 log4j 以及其他的日志来按照 commons-logging 的标准编写,但是由于 commons-logging 的类加载有点问题,实现起来也不友好,作为元老级日志 log4j 的作者再度出山,搞出了一个更加牛逼的新的日志框架 slf4j(这个也是抽象层),同时针对 slf4j 的接口实现了一套日志系统,即传说中的 logback。
- 同时这个作者心情一好,又把 log4j 进行了改造,就是所谓的 log4j2,同时支持 jcl 以及 slf4j。
最后,commons-logging 和 slf4j 两分天下。至于到底使用哪个,由用户来决定吧。
Java 日志抽象层
commons-logging 和 slf4j 都是日志的接口,供用户使用,而没有提供实现。
apache commons-logging
使用 JCL 一般需要一个配置 commons-logging.properties 在 classpath 上,这个文件有一行代码:
org.apache.commons.logging.LogFactory = org.apache.commons.logging.impl.LogFactoryImpl
用于通知 JCL 想要使用哪个日志系统。用户只要修改 LogFactory 的实现,就能动态的切换日志系统。
slf4j
slf4j 的设计相对较为精巧,作者将接口和实现分开,其中 slf4j-api 中定义了接口,开发者需要关心的就是这个接口,无需再关心下层如何实现,同时各个 slf4j 接口的实现者只要遵循这个接口,就能够做到日志系统间的无缝兼容。
- slf4j-api 的实现目前比较出名的是接口开发者实现的 logback,性能相较 log4j 来讲更加优秀,也支持占位符等新特性。
- 同时为了兼容 log4j,slf4j-log4j12 实现了 slf4j-api,作为 log4j 兼容的适配器,使得用户用起来像在用 log4j。
- 为了兼容 jul,slf4j-jdk14 也实现了 slf4j-api,作为 jul 兼容的适配器,使得用户用起来像在用 jul。
- 有了实现,还需要一个桥接器,桥接器将对 jcl 的调用转接到 slf4j 上:
- jul-to-slf4j 把对 jul 的调用桥接到 slf4j 上。
- jcl-over-slf4j 把对 jcl 的调用桥接到 slf4j 上。
- log4j-over-slf4j 把对 log4j 的调用桥接到 slf4j 上。
Java 日志实现
log4j
在 JDK 1.3 及以前,Java 打日志依赖 System.out.println()
,System.err.println()
或者e.printStackTrace()
,Debug 日志被写到 STDOUT 流,错误日志被写到 STDERR 流。这样打日志有一个非常大的缺陷,即无法定制化,且日志粒度不够细。log4j 是在这样的环境下诞生的,它是一个里程碑式的框架,它定义的 Logger
、Appender
、Level
等概念如今已经被广泛使用。
jul
java 官方日志 jul,位于 java.util.logging
包下。
jul 模块主要包含三个:Level、Formatter 和 Handler。
Level 表示日志的级别,总共有9种级别;Formatter 定义日志输出的格式,目前有 SimpleFormatter 和 XMLFormatter 两种格式,分别对应简单格式和 xml 格式,此外,可自定义输出格式,继承抽象类 java.util.logging.Formatter
即可;Handler 指定日志输出的目的地,目前有 FileHandler(输出到文件),ConsoleHandler(输出到控制台),SocketHandler(输出到 Socket),MemoryHandler(输出到内存)等。
logback
logback 和 log4j 是同一个作者创作,它是 log4j 的升级版,具体教程可参考 Logback 教程。
logback 相较于 log4j 有更多的优点:
- 原生实现了 SLF4J API(log4j 需要一个中间层转换)
- 支持 XML、Groovy 方式配置
- 支持配置文件中加入条件判断
- 更强大的过滤器
- 更丰富的免费文档
- 更充分的测试
- 自动重载有变更的配置文件
- 自动压缩历史日志
- 打印异常信息时自动包含 pachage 名称及版本号
log4j2
log4j2 是 log4j 的升级版,与之前的版本 log4j1.x 相比,有重大的改进,在修正了 logback 固有的架构问题的同时,改进了许多 logback 所具有的功能。
log4j2 的特性以及改进有:
- API 分离
- 改进的性能
- 多个 API 支持
- 自动配置加载
- 高级过滤功能
- 插件架构
- 属性支持
Java 日志查看工具
GCLogViewer
GCLogViewer 是一个支持 jdk 6 的 gc log 可视化工具,和 gcviewer 相比,gclogviewer 支持根据 gc log 生成 GC 的趋势图,也支持生成调优建议所需的数据趋势图。
日志采集工具
flume
Flume 则是一个日志分析系统,Flume 是分布式的,它有一个非常灵活的架构,用来收集、聚合以及移动大量日志数据,并且提供可靠、容错的系统架构。
logstash
logstash 是一款功能非常强大的日志管理工具,利用 logstash,你可以对日志进行传输、处理、管理和检索,并且提供 Web 接口以便开发者统计和查询日志信息。