日志系统
java.util.logging (JUL)
JDK1.4
开始,通过 java.util.logging
提供日志功能。虽然是官方自带的log lib
,JUL
的使用确不广泛。
JUL
从JDK1.4
才开始加入(2002年),当时各种第三方log lib
已经被广泛使用了JUL
早期存在性能问题,到JDK1.5
上才有了不错的进步,但现在和Logback/Log4j2
相比还是有所不如JUL
的功能不如Logback/Log4j2
等完善,比如Output Handler
就没有Logback/Log4j2
的丰富,有时候需要自己来继承定制,又比如默认没有从ClassPath
里加载配置文件的功能
Log4j
Log4j
是 apache
的一个开源项目,创始人 Ceki Gulcu
。Log4j
应该说是 Java
领域资格最老,应用最广的日志工具。Log4j
是高度可配置的,并可通过在运行时的外部文件配置。它根据记录的优先级别,并提供机制,以指示记录信息到许多的目的地,诸如:数据库,文件,控制台,UNIX
系统日志等。
Log4j
中有三个主要组成部分:loggers
- 负责捕获记录信息。appenders
- 负责发布日志信息,以不同的首选目的地。layouts
- 负责格式化不同风格的日志信息。
Log4j
的短板在于性能,在Logback
和 Log4j2
出来之后,Log4j
的使用也减少了。
LogbackLogback
是由 log4j
创始人 Ceki Gulcu
设计的又一个开源日志组件,是作为 Log4j
的继承者来开发的,提供了性能更好的实现,异步 logger
,Filter
等更多的特性。logback
当前分成三个模块:logback-core
、logback-classic
和 logback-access
。
logback-core
- 是其它两个模块的基础模块。logback-classic
- 是 log4j
的一个 改良版本。此外 logback-classic
完整实现 SLF4J API
使你可以很方便地更换成其它日志系统如 log4j
或 JDK14 Logging
。
logback-access
- 访问模块与 Servlet
容器集成提供通过 Http
来访问日志的功能。
Log4j2
维护 Log4j
的人为了性能又搞出了 Log4j2
。Log4j2
和 Log4j1.x
并不兼容,设计上很大程度上模仿了 SLF4J/Logback
,性能上也获得了很大的提升。Log4j2
也做了 Facade/Implementation
分离的设计,分成了 log4j-api
和 log4j-core
。
Log4j vs Logback vs Log4j2
按照官方的说法,Log4j2
大大优于 Log4j
和 Logback
。
那么,Log4j2
相比于先问世的 Log4j
和 Logback
,它具有哪些优势呢?
-
Log4j2
旨在用作审计日志记录框架。Log4j 1.x
和Logback
都会在重新配置时丢失事件。Log4j 2
不会。在Logback
中,Appender
中的异常永远不会对应用程序可见。在Log4j
中,可以将Appender
配置为允许异常渗透到应用程序。 -
Log4j2
在多线程场景中,异步Loggers
的吞吐量比Log4j 1.x
和Logback
高 10 倍,延迟低几个数量级。 -
Log4j2
对于独立应用程序是无垃圾的,对于稳定状态日志记录期间的Web
应用程序来说是低垃圾。这减少了垃圾收集器的压力,并且可以提供更好的响应时间性能。 -
Log4j2
使用插件系统,通过添加新的Appender
、Filter
、Layout
、Lookup
和Pattern Converter
,可以非常轻松地扩展框架,而无需对Log4j
进行任何更改。 -
由于插件系统配置更简单。配置中的条目不需要指定类名。
-
支持自定义日志等级。
-
支持
lambda
表达式。 -
支持消息对象。
-
Log4j
和Logback
的Layout
返回的是字符串,而Log4j2
返回的是二进制数组,这使得它能被各种Appender
使用。 -
Syslog Appender
支持TCP
和UDP
并且支持BSD
系统日志。 -
Log4j2
利用Java5
并发特性,尽量小粒度的使用锁,减少锁的开销
日志门面
日志门面是对不同日志框架提供的一个 API
封装,可以在部署的时候不修改任何配置即可接入一种日志实现方案。
common-logging
common-logging
是apache
的一个开源项目。也称Jakarta Commons Logging
,缩写 JCL
。common-logging
的功能是提供日志功能的 API
接口,本身并不提供日志的具体实现(当然,common-logging
内部有一个 Simple logger
的简单实现,但是功能很弱,直接忽略),而是在运行时动态的绑定日志实现组件来工作(如 log4j
、java.util.loggin
)。
slf4j
全称为 Simple Logging Facade for Java
,即 java
简单日志门面。类似于 Common-Logging
,slf4j
是对不同日志框架提供的一个 API
封装,可以在部署的时候不修改任何配置即可接入一种日志实现方案。但是,slf4j
在编译时静态绑定真正的 Log
库。使用 SLF4J
时,如果你需要使用某一种日志实现,那么你必须选择正确的 SLF4J
的 jar
包的集合(各种桥接包)
common-logging vs slf4j
slf4j
库类似于 Apache Common-Logging
。但是,他在编译时静态绑定真正的日志库。这点似乎很麻烦,其实也不过是导入桥接 jar
包而已。
slf4j
一大亮点是提供了更方便的日志记录方式:
不需要使用logger.isDebugEnabled()
来解决日志因为字符拼接产生的性能问题。slf4j
的方式是使用{}
作为字符串替换符,形式如下:
logger.debug("id: {}, name: {} ", id, name);
总结 使用 slf4j + Logback 可谓是目前最理想的日志解决方案了。
slf4j + Logback
添加依赖到 pom.xml
中即可。logback-classic-1.0.13.jar
会自动将 slf4j-api-1.7.21.jar
和 logback-core-1.0.13.jar
也添加到你的项目中。
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="/home" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>