X Tutup
日志就是记录程序的运行轨迹,方便查找关键信息,也方便快速定位解决问题。 > 谁不知道日志呀,下面我们看看世界上最好的语言 Java 的常用日志实现 > > ```java > private static final Logger logger = Logger.getLogger("jul"); > private static final Logger trace = LogManager.getLogger("log4j"); > private static final Logger logger = LoggerFactory.getLogger("SLF4J"); > private static final Log log = LogFactory.getLog("Apache Commons Logging"); > ``` > > 我**,这么多,怎么记得住,我要用哪个? > > ![img](https://tva1.sinaimg.cn/large/007S8ZIlly1ghjejmjjlhj3073073weh.jpg) > > 项目中有一堆日志相关的 Jar 包,到底应该引入哪个排除哪个? > > 这两个 Jar 包冲突了? 这个包需要依赖这个包? > > 这类问题有时候容易让人崩溃,所以就来缕一缕 Java 日志框架的那点事~~ ## Java常用日志框架 - **[JUL](https://docs.oracle.com/javase/8/docs/technotes/guides/logging/overview.html "JUL")** (Java Util Logging) :自 Java1.4 以来,Java 在 `Java.util.logging` 中提供的一个内置框架,也常称为 JDKLog、jdk-logging - **[Log4j](https://logging.apache.org/log4j/2.x/ "log4j")**:Apache Log4j 是一个基于 Java 的日志记录工具。最初是 Log4j 1,我们现在用的大都是 Log4j 2,Apache Log4j 2 是 Apache 开发的一款 Log4j 的升级产品,Log4j 2 与 Log4j 1 发生了很大的变化,Log4j 2 不兼容Log4j 1 - **[SLF4J](http://www.slf4j.org/ "SLF4J")**:`Simple Logging Facade for Java`,类似于 Commons Logging,是一套简易 Java 日志门面,本身并无日志的实现 - **[Logback](http://logback.qos.ch/ "Logback")**:Logback 是 `Slf4j` 的原生实现框架,同样也是出自 `Log4j` 一个人之手,但拥有比 `log4j` 更多的优点、特性和更做强的性能,现在基本都用来代替 `log4j` 成为主流 - **[tinylog](https://tinylog.org/v2/ "tinylog")**: 一个轻量级的开源日志框架 - **[Apache Commons Logging](http://commons.apache.org/proper/commons-logging/ "Apache Commons Logging")**:Apache 基金会所属的项目,是一套 Java 日志接口,之前叫 `Jakarta Commons Logging`,后更名为 Commons Logging JUL、log4j 、Logback 是**日志实现框架**,而 Apache Commons Logging 和 SLF4J 是**日志实现门面**,可以理解为一个适配器,**可以将你的应用程序从日志框架中解耦**。 > 日志门面,是门面模式的一个典型的应用。 > > 门面模式(Facade Pattern),也称之为外观模式,其核心为:外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。 > > ![](https://static01.imgkr.com/temp/34d51bca34e54c05a32d148439244496.png) > 阿里巴巴 Java 开发手册嵩山版_日志规约: > > 【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架(SLF4J、JCL--Jakarta Commons Logging)中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。 > > 说明:日志框架(SLF4J、JCL--Jakarta Commons Logging)的使用方式(推荐使用 SLF4J) > > 使用 SLF4J: > > ```java > import org.slf4j.Logger; > import org.slf4j.LoggerFactory; > private static final Logger logger = LoggerFactory.getLogger(Test.class); > ``` > > 使用 JCL: > > ```java > import org.apache.commons.logging.Log; > import org.apache.commons.logging.LogFactory; > private static final Log log = LogFactory.getLog(Test.class); > ``` 到这里我好像就明白了,有 2 个日志接口标准和其他的几个具体实现,但还是要扯一扯,要不没人点赞~~ ## [Java常用日志框架历史](https://www.cnblogs.com/chenhongliang/p/5312517.html "Java常用日志框架历史") - 1996 年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪 API(Tracing API)。经过不断的完善,这个API 终于成为一个十分受欢迎的 Java 日志软件包,即 Log4j。后来 Log4j 成为 Apache 基金会项目中的一员。 - 2002 年 Java1.4 发布,Sun 推出了自己的日志库 JUL(Java Util Logging),其实现基本模仿了 Log4j 的实现。在 JUL 出来以前,Log4j 就已经成为一项成熟的技术,使得 Log4j 在选择上占据了一定的优势。 > 谁能想到 Java1.4 之前,JDK 竟然没有内置的日志功能呢 - 因为有了两种选择,所以导致了日志使用的混乱。所以 Apache 又推出了 `Jakarta Commons Logging`,JCL 只是定义了一套日志接口,支持运行时动态加载日志组件的实现,也就是说,应用层编写代码时,只需调用 JCL 提供的统一接口来记录日志,底层实现可以是 `Log4j`,也可以是 `Java Util Logging`。 - 2006年,Log4j 的作者 Ceki Gülcü 从 Apache 离职,然后又搞出来一套类似 JCL 的接口类——Slf4j 和它的默认实现 Logback。 - 从此,Java 日志领域被划分为两大阵营:Commons Logging 阵营和 Slf4j 阵营。 - 2012 年,Apache 眼看有被 Logback 反超的势头,于是重写了 Log4j 1.x,成立了新的项目 Log4j 2,Log4j 2 具有 Logback 的所有特性。 ## Java 日志级别 不同的日志框架,级别也会有些差异 - j.u.l:OFF、SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST、ALL - log4j:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL - logback:OFF、ERROR、WARN、INFO、DEBUG、TRACE、 ALL | 日志级别 | 描述 | | -------- | -------------------------------------------------- | | OFF | 关闭:最高级别,不输出日志。 | | FATAL | 致命:输出非常严重的可能会导致应用程序终止的错误。 | | ERROR | 错误:输出错误,但应用还能继续运行。 | | WARN | 警告:输出可能潜在的危险状况。 | | INFO | 信息:输出应用运行过程的详细信息。 | | DEBUG | 调试:输出更细致的对调试应用有用的信息。 | | TRACE | 跟踪:输出更细致的程序运行轨迹。 | | ALL | 所有:输出所有级别信息。 | ## Commons Logging 与 Slf4j 实现机制对比 #### Commons Logging 实现机制 Commons Logging 是通过动态查找机制,在程序运行时,使用自己的 ClassLoader 寻找和载入本地具体的实现。详细策略可以查看 `commons-logging-*.jar` 包中的`org.apache.commons.logging.impl.LogFactoryImpl.java` 文件。由于 Osgi 不同的插件使用独立的ClassLoader,Osgi 的这种机制保证了插件互相独立,其机制限制了 Commons Logging 在 Osgi 中的正常使用。 #### Slf4j 实现机制 Slf4j 在编译期间,静态绑定本地的 Log 库,因此可以在 Osgi 中正常使用。它是通过查找类路径下`org.slf4j.impl.StaticLoggerBinder`,然后在 StaticLoggerBinder 中进行绑定。 ## 项目中选择日志框架选择 如果是在一个新的项目中建议使用 Slf4j 与 Logback 组合,这样有如下的几个优点 - Slf4j 实现机制决定 Slf4j 限制较少,使用范围更广。由于 Slf4j 在编译期间,静态绑定本地的 LOG 库使得通用性要比 Commons Logging 要好。 - Logback 拥有更好的性能。Logback 声称:某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高。这个操作在 Logback 中需要 3 纳秒,而在 Log4J 中则需要 30 纳秒。LogBack 创建记录器(logger)的速度也更快:13 毫秒,而在 Log4J 中需要 23 毫秒。更重要的是,它获取已存在的记录器只需94 纳秒,而 Log4J 需要 2234 纳秒,时间减少到了 1/23。跟 JUL 相比的性能提高也是显著的。 - Commons Logging 开销更高 在使Commons Logging时为了减少构建日志信息的开销,通常的做法是 ```java if(log.isDebugEnabled()){ log.debug("User name: " + user.getName() + " buy goods id :" + good.getId()); } ``` 在 Slf4j 阵营,你只需这么做: ```java log.debug("User name:{} ,buy goods id :{}", user.getName(),good.getId()); ``` 也就是说,Slf4j 把构建日志的开销放在了它确认需要显示这条日志之后,减少内存和 cup 的开销,使用占位符号,代码也更为简洁 - Logback 文档免费。Logback 的所有文档是全面免费提供的,不像 Log4J 那样只提供部分免费文档而需要用户去购买付费文档。 ## SLF4J 绑定日志框架 ![](https://tva1.sinaimg.cn/large/007S8ZIlly1ghjfdb8016j31cy0riwhw.jpg) ![来源:slf4j.org](http://www.slf4j.org/images/concrete-bindings.png) ## 阿里Java开发手册——日志规约 2. 【强制】日志文件至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。 3. 【强制】应用中的扩展日志(如打点、临时监控、访问日志等)命名方式: appName_logType_logName.log。 logType:日志类型,如 stats/monitor/access 等;logName:日志描述。这种命名的好处: 通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。 正例:mppserver 应用中单独监控时区转换异常,如: mppserver_monitor_timeZoneConvert.log 说明:推荐对日志进行分类,如将错误日志和业务日志分开存放,便于开发人员查看,也便于 通过日志对系统进行及时监控。 4. 【强制】对 trace/debug/info 级别的日志输出,必须使用条件输出形式或者使用占位符的方 式。 说明:logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); 如果日志级别是 warn,上述日志不会打印,但是会执行字符串拼接操作,如果 symbol 是对象, 会执行 toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。 正例:(条件)建设采用如下方式 ```java if (logger.isDebugEnabled()) { logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); } ``` 正例:(占位符) ```java logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol); ``` 5. 【强制】避免重复打印日志,浪费磁盘空间,务必在 log4j.xml 中设置 additivity=false。 正例: 6. 【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过 关键字 throws 往上抛出。 正例:logger.error(各类参数或者对象 toString() + "_" + e.getMessage(), e); 7. 【推荐】谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使 用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘 撑爆,并记得及时删除这些观察日志。 说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请 思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处? 8. 【推荐】可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适 从。如非必要,请不要在此场景打出 error 级别,避免频繁报警。 说明:注意日志输出的级别,error 级别只记录系统逻辑出错、异常或者重要的错误信息。 9. 【推荐】尽量用英文来描述日志错误信息,如果日志中的错误信息用英文描述不清楚的话使用 中文描述即可,否则容易产生歧义。国际化团队或海外部署的服务器由于字符集问题,【强制】 使用全英文来注释和描述日志错误信息。 > [Ultimate Guide to Logging](https://www.loggly.com/ultimate-guide/java-logging-basics/#layouts) > > [《Java常用日志框架介绍》](https://www.cnblogs.com/chenhongliang/p/5312517.html) http://www.slf4j.org/manual.html [https://www.cnblogs.com/chenhongliang/p/5312517.html#java%E6%97%A5%E5%BF%97%E6%A6%82%E8%BF%B0](https://www.cnblogs.com/chenhongliang/p/5312517.html#java日志概述)
X Tutup