从System.out到Log4j2:Java日志框架的江湖演变与设计哲学

阶段一:原始时代(1999年前)—— System.out的野蛮生长标准输出(<1999)

Java最开始并没有专门记录日志的工具,大家都是用System.out和system.err输出日志。但它们只是简单的信息输出,无法区分错误级别、无法控制输出粒度,也没有什么管理、过滤能力。随着Java工程化的深入,他们的能力就有些捉襟见肘了,
:虽然 System.out和System.err默认输出到控制台,但它们还是有能力将输出保存到文件的。

System.setOut(new PrintStream(new FileOutputStream("log.txt", true)));
System.out.println("这句将输出到 log.txt 文件中");

System.setErr(new PrintStream(new FileOutputStream("error.txt", true)));
System.err.println("这句将输出到 error.txt 文件中");

阶段2:开山鼻祖(1999年)—— Log4j的横空出世

1996 年,一家名为 SEMPRA 的欧洲公司决定开发一款用于记录日志的工具,经过多次迭代,最终形成了 Log4j(log for java)。这款工具的主要作者是俄罗斯程序员 Ceki(值得特别提到)。到 1999 年,Log4j 已经被广泛使用,用户需求开始多样化。Ceki 在 2001 年选择将 Log4j 开源,借助社区的力量发展此工具。不久后,Apache 基金会接手了 Log4j,并将其更名为 Apache Log4j
它首次将日志管理从System.out的混沌中解放,定义了现代日志框架的三大核心设计:

  • 分级日志:从DEBUG到FATAL的5级分类(从低到高依次是debug、info、warn、error、fatal,输出前会校验配置的允许级别,小于此级别的日志将被忽略。除此之外还有all、off两个特殊级别,表示完全放开和完全关闭日志输出。),让日志告别“一锅粥”时代。
  • 灵活输出:控制台、文件、数据库、邮件……日志可以“想去哪就去哪”(Appender)。
  • 配置驱动:无需改代码,一个log4j.properties文件就能让日志改头换面。

有趣的是,Log4j的开源之路充满戏剧性——Ceki最初只是为自家公司开发工具,却在Apache的扶持下成为行业标准。它的成功甚至催生了“Log4X家族”:Log4Net、Log4cxx、Log4php……堪称日志界的“门萨俱乐部”。尽管如此,由于性能短板,Log4j 在 Logback 和 Log4j 2 推出后逐渐式微,最终在 2015 年,Apache 宣布终止 Log4j 的开发,全面迁移至 Log4j 2。

阶段3:官方尝试(2002年)—— JUL的仓促登场

随着 Java 工程的发展,Sun 也意识到日志记录的重要性,并决定将其纳入 JRE 原生支持。1999 年,Sun 提交了 JSR 047 提案,标题为「Logging API Specification」,但直到 2002 年,Java 官方的日志系统才随 Java 1.4 发布,称为 Java Logging API(简称 JUL)。

有传言称,Apache 希望将 Log4j 纳入 JRE 作为默认日志实现,但 Sun 拒绝了,反而推出了自己的日志系统。然而,从实际产品来看,较晚出现的 JUL 在功能和性能上均落后于 Log4j,且在 Java 5.0中有所改进,但广大的开发者依然没有迁移的动力,使得 JUL 始终未成气候。

阶段4:统一接口(2002年)—— JCL的适配野心

在 Log4j 和 JUL 之外,市场上还有如 Apache Avalon 和 Lumberjack 等日志工具。为了避免日志记录混乱,Apache 在 2002 年推出了 Jakarta Commons Logging(简称 JCL),这套接口支持多种日志工具。开发者只需调用 JCL 接口即可,最终使用的日志实现由上层业务系统决定。这是典型的接口与实现分离设计。

JCL 后来成为 Apache Commons 的子项目,尽管名字没有更改,但它与常用的 Commons Lang 和 Commons Collections 等项目属于同一系列。

阶段5:接口革新(2005年)—— Slf4j的静态绑定

Ceki 注意到 Log4j 和 JCL 的不足,于是在 2005 年推出了 Simple Logging Facade for Java(简称 Slf4j)。Slf4j 作为一个接口层,其设计与 JCL 相似,但采用静态绑定方式,性能更佳。这一设计避免了 JCL 在运行时动态判定日志实现的性能损失。

阶段6:性能巅峰(2006年)—— Logback的全面超越(Spring Boot的默认集成日志

Ceki 于 2006 年推出了 Logback,这一日志记录实现方案在易用性、功能和性能上均优于 Log4j。Logback 自然支持 Slf4j,无需额外的适配层,因而迅速获得了广泛接受。Logback 提供了许多新特性,包括日志文件切割、异步写入、条件日志输出等。
相比于Log4j,Logback提供了很多我们现在看起来理所当然的新特性

  • 支持日志文件切割滚动记录、支持异步写入
  • 针对历史日志,既支持按时间或按硬盘占用自动清理,也支持自动压缩以节省硬盘空间
  • 支持分支语法,通过、、可以按条件配置不同的日志输出逻辑,比如判断仅在开发环境输出更详细的日志信息
  • 大量的日志过滤器,甚至可以做到通过用户Session识别到每一位用具并输出到独立的日志文件
  • 异常堆栈支持打印jar信息,让我们不但知道调用出自那个文件哪一行,还可以知道这个文件来自那个jar包
    Logback主要由三部分组成
  • logback-core:记录/输出日志的核心实现
  • logback-classic:适配层,完整实现了slf4j接口
  • logback-access:用于将logback集成到Servlet容器(Tomcat、Jetty)中,让这些容器的HTTP访问日志也可以经由强大的Logback输出

阶段7:绝地反击(2012年)—— Log4j2的异步革命

Apache 于 2012 年推出了 Log4j 2,具有插件化结构和基于 LMAX Disruptor 的异步输出,性能提升明显。然而,尽管 Log4j 2 具备许多新特性,但依然未能撼动 Logback 的地位,主要由于 Log4j 2 是一套全新系统,升级意愿低,以及未提供足够吸引人的差异化能力。

Log4j2主要由两部分组成

  • Log4j-core:核心实现,功能类似于logback-core
  • log4j-api:接口层,功能类似于slf4j,里面只含有Log4j 2的接口定义
    你会发现Log4j 2的设计别具一格,提供JCL和Slf4j之外的第三个接口层(log4j-api,虽然只是自己的接口),它在官网API Separation一节中解释说,这样设计可以允许用户在一个项目中同时使用不同的接口层与实现层。

虽然 Log4j 2 发布至今已有十年,但其影响力仍然不及 Logback。开发者普遍认为,Spring Boot 继续使用 Logback 的决定是明智的,因为大多数用户并未面临日志性能问题,而 Log4j 2 的优势并非核心关切。
比如,曾有人建议Spring Boot将日志系统从Logback切换到Log4j2,但被Phil Webb(Spring Boot核心贡献者)否决。他在回复中给出的原因包括:Spring Boot需要保证向前兼容以方便用户升级,而切换Log4j 2是破坏性的;目前绝大部分用户并未面临日志性能问题,Log4j 2所推崇的性能优势并非框架与用户的核心关切;以及如果用户想在Spring Boot中切换到Log4j 2也很方便(如需切换可参考 官方文档)。

通过以上历程,我们可以看到 Java 日志记录技术的发展从最初的简单输出演变至今的多样化框架,每一步都在不断推动着日志处理技术的进步与演变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值