java日志和SLF4J随想

简介:

本文漫谈java中的日志:以前怎样使用日志,以及类似SLF4J的库为我们带来了什么。

日志是创建软件时的基本需求之一,常见的用例如:

  • 软件开发过程中的调试
  • 生产环境下诊断bug
  • 出于安全目的而跟踪访问
  • 创建统计使用的数据
  • 等等


无论用途为何,日志都应该是详尽、可配置和可靠的。
历史
在早期,java日志使用System.out.println(), System.err.println() 或 e.printStackTrace()。调试信息输出到标准输出System.out,错误信息输出到标准错误System.err。在生产环境中,二者都被重定向:前者重定向到null(注:不输出),后者重定向到需要的日志文件。这种做法够用但有很大的缺点:不可配置。它是个是或否的开关,要么全记录要么完全不,不能在某一层或某个包上关注具体的日志。

Log4J充当了救星,它满足了人们对日志框架的几乎所有需求。它引入了许多日志框架中今天仍在使用的概念(它是我首个使用的框架所以请原谅我若某个概念其实不是它发明的):

  • Logger的概念,每个logger可以单独配置
  • Appender的概念,每个appender可以将日志输出到它想要的任何地方(文件、数据库、消息等等)
  • Level的概念,开发人员可以单独配置是否输出每条日志

之后,Sun意识到需要在JDK中提供日志特性,它没有直接使用Log4J,而是模仿Log4J创建了自己的API。然而,新API的完成度不及Log4J。如果你想使用JDK1.4的日志API,你可能必须创建自己的Appender-在java API中叫Handler-因为能直接用的日志目的地只有控制台和文件。

使用这些框架都需要多份配置,因为不管你选择哪个,至少有一个你的依赖会使用另一个。Apache Commons Logging是一个将它自己与日志框架连接的API桥梁。库应该调用commons-logging,这样库使用的实际框架和你的工程是相同的,而不是它强制使用的。现实不总是这样,所以Commons Logging没有解决双重配置问题。此外,Commons Logging还会遇到类加载的问题,导致NoClassDefFoundError报错。

最后,Log4J核心的开发者由于此处不便细说的原因退出了Log4J工程。他创建了另一个日志框架,这个本应成为Log4J第二版的日志框架被命名为SLF4J。

一些奇怪的事实

以下是前述框架困扰我的一些事实,它们不一定都是缺陷但值得指出来:

  • Log4J通过maven强制依赖JMS, Mail和JMX,意味着如果你不嫌麻烦特意排除它们那这些就会出现在你工程的类路径中。
  • 类似地,Commons Logging通过maven强制依赖Avalon(另一个日志框架),Log4J, LogKit和Servlet API(!)
  • Log4J中始终包含一个Swing日志查看器,即使它是用在无需展现的环境中,例如批处理或应用服务器。
  • Log4J 1.3版的主页重定向到1.2版,而2.0版还在实验室阶段。

选择哪个框架?

Log4J是可以选择的框架(对大多数)但它不再开发了。1.2版是参考,1.3版废弃了而2.0还处在它的早期阶段。
Commons Logging是作为库的好选择(相比应用),但我无法忍受类加载器的问题,一次就够了(最后,我抛开Commons Logging直接用了Log4J).
JDK1.4日志是标准而且不存在多版本共用的问题,但它缺少太多特性,如果不二次开发如数据库适配器或其它就不能使用。太糟了。。。但仍未回答这个问题:选择哪个框架?

最近,我公司的架构师决定使用SLF4J,为什么会选择它?

SLF4J
SLF4J不及Log4J使用普遍,因为许多架构师和开发者熟悉Log4J而不知道SLF4J,或不关注SLF4J而坚持使用Log4J。此外,Log4J满足了许多工程的所有日志需求。不过,有趣的是,Hibernate使用了SLF4J。它拥有一些Log4J没有的美好特性。

简单的语法

看这个Log4J示例:
Logger.debug("Hello " + name);
由于字符串拼接的问题(注:上述语句会先拼接字符串,再根据当前级别是否低于debug决定是否输出本条日志,即使不输出日志,字符串拼接操作也会执行),许多公司强制使用下面的语句,这样只有当前处于DEBUG级别时才会执行字符串拼接:
if (logger.isDebugEnabled()) {

LOGGER.debug(“Hello ” + name);
}

它避免了字符串拼接问题,但有点太繁琐了是不是?相对地,SLF4J提供下面这样简单的语法:
LOGGER.debug("Hello {}", name);
它的形式类似第一条示例,而又没有字符串拼接问题,也不像第二条那样繁琐。

SLF4J API和实现
此外,SLF4J很好地解耦了API和实现,所以你在开发环境和生产环境中使用它的API都可以极佳地适配。例如,你可以强制使用SLF4J的API,而保持生产环境中用了几年的旧的Log4J.properties文件。SLF4J的日志实现是LogKit。

SLF4J桥接
SLF4J具有桥接的特性,你可以移除你的工程及其依赖组件使用的所有Log4J和commons-logging包,只使用SLF4J。
SLF4J为每一种日志框架提供一个JAR包:它模仿其它日志框架的API但将实现引向SLF4J的API(进而使用环境中真实的框架)。一点警告:小心不要让classpath中同时出现同一种日志的桥接库和实现库,否则会陷入循环。例如,使用Log4J桥接库时,每个Log4J的API被引向SLF4J,如果SLF4J的Log4J实现同时存在,会再次引向Log4J,这样循环下去。

SLF4JAPI和Log4J实现
综合所有考虑,我的建议是使用SLF4J的API和Log4J的实现。这样,你仍像以前一样配置Log4J,但调用更简单的SLF4J接口。要这样做,你需要:

操作 位置 描述
加入classpath slf4j-api.jar* 主API,没有它就无法使用SLF4J
slf4j-log4j.jar* SLF4J的Log4J实现
jul-to-slf4j.jar* 允许重定向 JDK 1.4日志到 SLF4J
jcl-over-slf4j.jar* 重定向commons-logging调用到SLF4J
从classpath移除 commons-logging.jar* 会跟 jcl-over-slf4j.jar里的commons-logging API冲突
SLF4JBridgeHandler.install()** 主应用 重定向JDK 1.4日志调用到SLF4J
* Jar名可能包含版本
**只在你需要单一入口或少量调用

如果你的应用在应用服务器中运行,你可能需要修改它的库和/或配置来达成以上修改。
更多:
SLF4J项目
Log4J项目
Commons Logging项目
Commons Logging类加载问题


转载自 并发编程网 - ifeve.com

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
12月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `<appender>` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `<logger>` 和 `<root>` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
2817 1
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
4418 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
12月前
|
Java 微服务 Spring
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录——使用Logger在项目中打印日志
本文介绍了如何在项目中使用Logger打印日志。通过SLF4J和Logback,可设置不同日志级别(如DEBUG、INFO、WARN、ERROR)并支持占位符输出动态信息。示例代码展示了日志在控制器中的应用,说明了日志配置对问题排查的重要性。附课程源码下载链接供实践参考。
1275 0
|
12月前
|
SQL Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— application.yml 中对日志的配置
在 Spring Boot 项目中,`application.yml` 文件用于配置日志。通过 `logging.config` 指定日志配置文件(如 `logback.xml`),实现日志详细设置。`logging.level` 可定义包的日志输出级别,例如将 `com.itcodai.course03.dao` 包设为 `trace` 级别,便于开发时查看 SQL 操作。日志级别从高到低为 ERROR、WARN、INFO、DEBUG,生产环境建议调整为较高级别以减少日志量。本课程采用 yml 格式,因其层次清晰,但需注意格式要求。
1093 0
|
12月前
|
Java API 开发者
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录——slf4j 介绍
在软件开发中,`System.out.println()`常被用于打印信息,但大量使用会增加资源消耗。实际项目推荐使用slf4j结合logback输出日志,效率更高。Slf4j(Simple Logging Facade for Java)是一个日志门面,允许开发者通过统一方式记录日志,无需关心具体日志系统。它支持灵活切换日志实现(如log4j或logback),且具备简洁占位符和日志级别判断等优势。阿里巴巴《Java开发手册》强制要求使用slf4j,以保证日志处理方式的统一性和维护性。使用时只需通过`LoggerFactory`创建日志实例即可。
775 0
|
Java Apache 开发工具
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
270 1
|
12月前
|
SQL druid Oracle
【YashanDB知识库】yasdb jdbc驱动集成druid连接池,业务(java)日志中有token IDENTIFIER start异常
客户Java日志中出现异常,影响Druid的merge SQL功能(将SQL字面量替换为绑定变量以统计性能),但不影响正常业务流程。原因是Druid在merge SQL时传入null作为dbType,导致无法解析递归查询中的`start`关键字。
|
Java Maven
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
在Java项目中,启动jar包时遇到“no main manifest attribute”错误,且打包大小明显偏小。常见原因包括:1) Maven配置中跳过主程序打包;2) 缺少Manifest文件或Main-Class属性。解决方案如下:
3038 8
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
|
数据采集 监控 Java
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
本文是关于SpringBoot日志的详细教程,涵盖日志的定义、用途、SLF4J框架的使用、日志级别、持久化、文件分割及格式配置等内容。
1247 2
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
|
人工智能 Oracle Java
解决 Java 打印日志吞异常堆栈的问题
前几天有同学找我查一个空指针问题,Java 打印日志时,异常堆栈信息被吞了,导致定位不到出问题的地方。
381 2