X Tutup
Skip to content

Latest commit

 

History

History
218 lines (127 loc) · 12.1 KB

File metadata and controls

218 lines (127 loc) · 12.1 KB

日志就是记录程序的运行轨迹,方便查找关键信息,也方便快速定位解决问题。

谁不知道日志呀,下面我们看看世界上最好的语言 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

项目中有一堆日志相关的 Jar 包,到底应该引入哪个排除哪个?

这两个 Jar 包冲突了? 这个包需要依赖这个包?

这类问题有时候容易让人崩溃,所以就来缕一缕 Java 日志框架的那点事~~

Java常用日志框架

  • JUL (Java Util Logging) :自 Java1.4 以来,Java 在 Java.util.logging 中提供的一个内置框架,也常称为 JDKLog、jdk-logging
  • Log4j:Apache Log4j 是一个基于 Java 的日志记录工具。最初是 Log4j 1,我们现在用的大都是 Log4j 2,Apache Log4j 2 是 Apache 开发的一款 Log4j 的升级产品,Log4j 2 与 Log4j 1 发生了很大的变化,Log4j 2 不兼容Log4j 1
  • SLF4JSimple Logging Facade for Java,类似于 Commons Logging,是一套简易 Java 日志门面,本身并无日志的实现
  • Logback:Logback 是 Slf4j 的原生实现框架,同样也是出自 Log4j 一个人之手,但拥有比 log4j 更多的优点、特性和更做强的性能,现在基本都用来代替 log4j 成为主流
  • tinylog: 一个轻量级的开源日志框架
  • Apache Commons Logging:Apache 基金会所属的项目,是一套 Java 日志接口,之前叫 Jakarta Commons Logging,后更名为 Commons Logging

JUL、log4j 、Logback 是日志实现框架,而 Apache Commons Logging 和 SLF4J 是日志实现门面,可以理解为一个适配器,可以将你的应用程序从日志框架中解耦

日志门面,是门面模式的一个典型的应用。

门面模式(Facade Pattern),也称之为外观模式,其核心为:外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。

阿里巴巴 Java 开发手册嵩山版_日志规约:

【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架(SLF4J、JCL--Jakarta Commons Logging)中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

说明:日志框架(SLF4J、JCL--Jakarta Commons Logging)的使用方式(推荐使用 SLF4J)

使用 SLF4J:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Test.class);

使用 JCL:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
private static final Log log = LogFactory.getLog(Test.class);

到这里我好像就明白了,有 2 个日志接口标准和其他的几个具体实现,但还是要扯一扯,要不没人点赞~~

  • 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时为了减少构建日志信息的开销,通常的做法是

    if(log.isDebugEnabled()){
      log.debug("User name: " +
        user.getName() + " buy goods id :" + good.getId());
    }

    在 Slf4j 阵营,你只需这么做:

    log.debug("User name:{} ,buy goods id :{}", user.getName(),good.getId());

    也就是说,Slf4j 把构建日志的开销放在了它确认需要显示这条日志之后,减少内存和 cup 的开销,使用占位符号,代码也更为简洁

  • Logback 文档免费。Logback 的所有文档是全面免费提供的,不像 Log4J 那样只提供部分免费文档而需要用户去购买付费文档。

SLF4J 绑定日志框架

来源:slf4j.org

阿里Java开发手册——日志规约

  1. 【强制】日志文件至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。

  2. 【强制】应用中的扩展日志(如打点、临时监控、访问日志等)命名方式: appName_logType_logName.log。 logType:日志类型,如 stats/monitor/access 等;logName:日志描述。这种命名的好处: 通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。 正例:mppserver 应用中单独监控时区转换异常,如: mppserver_monitor_timeZoneConvert.log 说明:推荐对日志进行分类,如将错误日志和业务日志分开存放,便于开发人员查看,也便于 通过日志对系统进行及时监控。

  3. 【强制】对 trace/debug/info 级别的日志输出,必须使用条件输出形式或者使用占位符的方 式。 说明:logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); 如果日志级别是 warn,上述日志不会打印,但是会执行字符串拼接操作,如果 symbol 是对象, 会执行 toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。

    正例:(条件)建设采用如下方式

    if (logger.isDebugEnabled()) {
        logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); 
    } 

    正例:(占位符)

     logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol); 
  4. 【强制】避免重复打印日志,浪费磁盘空间,务必在 log4j.xml 中设置 additivity=false。 正例:

  5. 【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过 关键字 throws 往上抛出。 正例:logger.error(各类参数或者对象 toString() + "_" + e.getMessage(), e);

  6. 【推荐】谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使 用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘 撑爆,并记得及时删除这些观察日志。 说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请 思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?

  7. 【推荐】可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适 从。如非必要,请不要在此场景打出 error 级别,避免频繁报警。 说明:注意日志输出的级别,error 级别只记录系统逻辑出错、异常或者重要的错误信息。

  8. 【推荐】尽量用英文来描述日志错误信息,如果日志中的错误信息用英文描述不清楚的话使用 中文描述即可,否则容易产生歧义。国际化团队或海外部署的服务器由于字符集问题,【强制】 使用全英文来注释和描述日志错误信息。

Ultimate Guide to Logging

《Java常用日志框架介绍》

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

X Tutup