日志就是记录程序的运行轨迹,方便查找关键信息,也方便快速定位解决问题。
谁不知道日志呀,下面我们看看世界上最好的语言 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");我**,这么多,怎么记得住,我要用哪个?
项目中有一堆日志相关的 Jar 包,到底应该引入哪个排除哪个?
这两个 Jar 包冲突了? 这个包需要依赖这个包?
这类问题有时候容易让人崩溃,所以就来缕一缕 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
- SLF4J:
Simple 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 的所有特性。
不同的日志框架,级别也会有些差异
-
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 是通过动态查找机制,在程序运行时,使用自己的 ClassLoader 寻找和载入本地具体的实现。详细策略可以查看 commons-logging-*.jar 包中的org.apache.commons.logging.impl.LogFactoryImpl.java 文件。由于 Osgi 不同的插件使用独立的ClassLoader,Osgi 的这种机制保证了插件互相独立,其机制限制了 Commons Logging 在 Osgi 中的正常使用。
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 那样只提供部分免费文档而需要用户去购买付费文档。
-
【强制】日志文件至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。
-
【强制】应用中的扩展日志(如打点、临时监控、访问日志等)命名方式: appName_logType_logName.log。 logType:日志类型,如 stats/monitor/access 等;logName:日志描述。这种命名的好处: 通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。 正例:mppserver 应用中单独监控时区转换异常,如: mppserver_monitor_timeZoneConvert.log 说明:推荐对日志进行分类,如将错误日志和业务日志分开存放,便于开发人员查看,也便于 通过日志对系统进行及时监控。
-
【强制】对 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);
-
【强制】避免重复打印日志,浪费磁盘空间,务必在 log4j.xml 中设置 additivity=false。 正例:
-
【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过 关键字 throws 往上抛出。 正例:logger.error(各类参数或者对象 toString() + "_" + e.getMessage(), e);
-
【推荐】谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使 用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘 撑爆,并记得及时删除这些观察日志。 说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请 思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?
-
【推荐】可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适 从。如非必要,请不要在此场景打出 error 级别,避免频繁报警。 说明:注意日志输出的级别,error 级别只记录系统逻辑出错、异常或者重要的错误信息。
-
【推荐】尽量用英文来描述日志错误信息,如果日志中的错误信息用英文描述不清楚的话使用 中文描述即可,否则容易产生歧义。国际化团队或海外部署的服务器由于字符集问题,【强制】 使用全英文来注释和描述日志错误信息。
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



