Java常用的日志框架对比
作为Java开发人员,对于日志记录框架一定非常熟悉。而且几乎在所有应用里面,一定会用到各种各样的日志框架用来记录程序的运行信息。而对于一个成熟的Java应用,这个是必不可少的。在开发和调试阶段,日志可以帮助我们更快的定位问题;而在应用的运维过程中,日志系统又可以帮助我们记录大部分的异常信息,通常很多企业会通过收集日志信息来对系统的运行状态进行实时监控预警。
总体概览
image.png目前的日志框架有JDK自带的logging
,log4j1
、log4j2
、logback
,这些框架都自己定制了日志 API ,并且有相应的实现;目前用于实现日志统一的框架 Apache commons-logging
、slf4j
,遵循面向接口编程的原则,这两大框架可以让用户在程序运行期间去选择具体的日志实现系统(log4j1\log4j2\logback
等)来记录日志,是统一抽象出来的一些接口。
日志级别
log4j
定义了8个级别的log(除去OFF和ALL,可以说分为6个级别),
优先级从高到低依次为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。
ALL
最低等级的,用于打开所有日志记录。
TRACE
很低的日志级别,一般不会使用。
DEBUG
指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
INFO
消息在粗粒度级别上突出强调应用程序的运行过程。这个可以用于生产环境中输出程序运行的一些重要信息。
WARN
表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给开发者的一些提示。
ERROR
指出发生错误的信息,可能会导致系统出错或是宕机等,必须要避免
FATAL
指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
OFF
最高等级,用于关闭所有日志记录。
Log4j
官网地址:https://logging.apache.org/log4j/1.2/
简介:
Apache 的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;用户也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,用户能够更加细致地控制日志的生成过程。这些可以通过一个 配置文件来灵活地进行配置,而不需要修改程序代码。
在JDK 1.3及以前,Java打日志依赖System.out.println()
, System.err.println()
或者e.printStackTrace()
,Debug日志被写到STDOUT
流,错误日志被写到STDERR
流。这样打日志有一个非常大的缺陷,即无法定制化,且日志粒度不够细。log4j是在这样的环境下诞生的,它是一个里程碑式的框架,它定义的Logger
、Appender
、Level
等概念如今已经被广泛使用。
在https://mvnrepository.com/中可以查到,log4j1从2005年11月更新到2012年3月,后面就没再更新了
最新的依赖(May 26, 2012)
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2015年8月5日,项目管理委员会宣布Log4j 1.x
已达到使用寿命。建议用户使用Log4j 1
升级到Apache Log4j 2
Log4j2
官网地址:https://logging.apache.org/log4j/2.x/
Log4j2
是Log4j1
的升级版本。Log4j2
基本上把Log4j1
版本的核心全部重构掉了,而且基于Log4j1
做了很多优化和改变。并提供了Logback
中可用的许多改进,同时修复了Logback
架构中的一些固有问题。
Log4j2最新的依赖(Mar 11, 2018)
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.0</version>
</dependency>
SpringBoot也有Log4j2相关的依赖
不过SpringBoot
自带的jar
包已经够用了
引入依赖(Jun 14, 2018)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
引入之后可以看到外部jar包多了三个关于log4j2的
image.png
关于上面的包
log4j-to-slf4j
将log4j2
的接口适配到slf4j
上,不能和log4j-slf4j-impl
同时存在
log4j-api
包含.class
但是只是一堆接口而已,实际使用需要log4j
log4j-core
包含.class
与.java
也就是源码
jul
指的是java.util.logging
,是 java
内置的日志模块
简介:受Log4j
启发,Sun在Java1.4
版本中引入了java.util.logging
,但是jul
功能远不如log4j
完善,开发者需要自己编写Appenders
(Sun称之为Handlers
),且只有两个Handlers
可用(Console
和File
),jul
在Java1.5
以后性能和可用性才有所提升。
不是SpringBoot项目需要引用jul
的话可以加
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
<version>2.11.0</version>
</dependency>
Log4j2的使用
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class SpringcloudEurekaApplication {
static Logger logger = LogManager.getLogger(SpringcloudEurekaApplication.class);
public static void main(String[] args) {
logger.info("Current Time: {}", System.currentTimeMillis());
logger.info("Current Time: " + System.currentTimeMillis());
logger.info("Current Time: {}", System.currentTimeMillis());
logger.trace("trace log");
logger.warn("warn log");
logger.debug("debug log");
logger.info("info log");
logger.error("error log");
}
}
启动项目后控制台输出为
SLF4J
官网地址:https://www.slf4j.org/
SLF4J(Simple Logging Facade for Java)用作各种日志框架(java.util.logging,logback,log4j)的简单外观或抽象,允许最终用户在部署 时插入所需的日志框架。
最新依赖(Mar 21, 2018)
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.8.0-beta2</version>
</dependency>
Springboot项目不需要引入任何依赖都可以使用
用法
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SpringcloudEurekaApplication{
private static final Logger logger = LoggerFactory.getLogger(SpringcloudEurekaApplication.class);
public static void main(String[] args) {
logger.info("Current Time: {}", System.currentTimeMillis());
logger.info("Current Time: " + System.currentTimeMillis());
logger.info("Current Time: {}", System.currentTimeMillis());
logger.trace("trace log");
logger.warn("warn log");
logger.debug("debug log");
logger.info("info log");
logger.error("error log");
}
}
启动项目后控制台输出为
通常输出日志开销非常大,SLF4J
通过{}
作为占位符的方式输出字符串,相比字符串拼接的方式,效率有显著的提升。
logback
官网地址:https://logback.qos.ch/
logback
和log4j
是同一个作者创作,它是log4j
的升级版
Logback的体系结构足够通用,以便在不同情况下应用。
logback分为三个模块:logback-core
,logback-classic
和logback-access
。
logback-core
模块为其他两个模块奠定了基础。
logback-classic
模块可以被同化为log4j
的显着改进版本。logback-classic
本身实现了SLF4J API
,因此您可以在logback
和其他日志框架(如log4j
或java.util.logging(JUL)
)之间来回切换。
logback-access
模块与Servlet
容器(如Tomcat和Jetty)集成,以提供HTTP
访问日志功能。可以在logback-core
之上轻松构建自己的模块。
Logback的核心对象:Logger、Appender、Layout
Logback主要建立于Logger
、Appender
和 Layout
这三个类之上。
Logger
:日志的记录器,把它关联到应用的对应的context
上后,主要用于存放日志对象,也可以定义日志类型、级别。Logger
对象一般多定义为静态常量.
Appender
:用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL
、 PostreSQL
、Oracle
和其他数据库、 JMS
和远程UNIX Syslog
守护进程等。
Layout
:负责把事件转换成字符串,格式化的日志信息的输出。
具体使用
引入依赖(Feb 11, 2018),分别对应logback
上的三个模块
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.0-alpha4</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.3.0-alpha4</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.3.0-alpha4</version>
</dependency>
注:如果在SpringBoot下是不需要引入的
Spring Boot内部日志系统使用的是Commons Logging
,但开放底层的日志实现。默认为会Java Util Logging, Log4J, Log4J2和Logback
提供配置。每种情况下都会预先配置使用控制台输出,也可以使用可选的文件输出。
因为在SpringBoot中本身就内置了日志功能,在spring-boot-starter
依赖中
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
logback的配置介绍
如果没有配置文件,那么logback
默认地会调用BasicConfigurator
,创建一个最小化配置。最小化配置由一个关联到根 logger
的ConsoleAppender
组成。输出用模式为%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
的 PatternLayoutEncoder
进行格式化。root
logger
默认级别是 DEBUG
。
官方推荐
官方推荐使用的xml
名字的格式为:logback-spring.xml
而不是logback.xml
,因为带spring
后缀的可以使用<springProfile>
这个标签。
Logback配置文件的基本结构
以<configuration>
开头,后面有任意个<appender>
元素,有任意个<logger>
元素,有最多一个<root>
元素。
Logback
配置文件的语法非常灵活。正因为灵活,所以无法用 DTD 或 XML schema进行定义。
1、根节点<configuration>
,包含下面三个属性:
scan
: 当此属性设置为true
时,配置文件如果发生改变,将会被重新加载,默认值为true
。
scanPeriod
: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan
为true
时,此属性生效。默认的时间间隔为1分钟。
debug
: 当此属性设置为true
时,将打印出logback
内部日志信息,实时查看logback
运行状态。默认值为false
。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--省略其他配置-->
</configuration>
2.子节点,分别有<appender>,<root>,<logger>,<property>,<contextName>,<conversionRule>,<springProfile>
1.子节点<appender>
:Logback将执行日志事件输出的组件称为Appender,实现的Appender
必须继承 ch.qos.logback.core.Appender
接口
它有两个必要属性name
和class
。name
指定appender
名称,class
指定appender
的全限定名
注:class="ch.qos.logback.core.rolling.RollingFileAppender"
常见的日志输出到文件,随着应用的运行时间越来越长,日志也会增长的越来越多,将他们输出到同一个文件并非一个好办法。RollingFileAppender
用于切分文件日志
在<appender>
有四个子节点
<encoder>
:对日志进行格式化。必须指定,否则不会往文件输出内容
%d{HH: mm:ss.SSS}
——日志输出时间
%thread
——输出日志的进程名字,这在Web应用以及异步任务处理中很有用
%-5level
——日志级别,并且使用5个字符靠左对齐
%logger{36}
——日志输出者的名字
%msg
——日志消息
%n
——平台的换行符
<rollingPolicy>
:循环政策:基于时间创建日志文件。当发生日志切换时,RollingFileAppender
的切换行为。例如日志文件名的修改
常用子节点
<maxHistory>
表示只保留最近天数的日志,最好设置下,以防止日志填满整个磁盘空间。
<timeBasedFileNamingAndTriggeringPolicy>
中<maxFileSize>
是对日志大小进行切割,设置每个日志文件的最大值
<filter>
:过滤器,执行一个过滤器会有返回个枚举值。
返回DENY
,日志将立即被抛弃不再经过其他过滤器;
返回NEUTRAL
,有序列表里的下个过滤器过接着处理日志;
返回ACCEPT
,日志会被立即处理,不再经过剩余过滤器。
为<Appender>
添加一个或多个过滤器后,可以用任意条件对日志进行过滤。<Appender>
有多个过滤器时,按照配置顺序执行。
最常用的过滤器
LevelFilter
: 级别过滤器,根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据onMath
和 onMismatch
接收或拒绝日志。
有以下子节点:
<level>
:设置过滤级别
<onMatch>
:用于配置符合过滤条件的操作
<onMismatch>
:用于配置不符合过滤条件的操作
<file>
:指定正在记录的日志文件的路径及文件名。
注意在windows
当中,反斜杠\
需要转义,或直接使用/
也可以。例如 c:/temp/test.log
或c:\\temp\\test.log
都可以。可以是相对目录,也可以是绝对目录,没有默认值,如果上层目录不存在,FileAppender
会自动创建。
我测试时放在日志文件是放在E盘下log文件夹(目录设置下文有提到)
<appender>
节点定义示例
<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
2.子节点<property>
:用来定义变量值,它有两个属性name
和value
,通过<property>
定义的值会被插入到logger
上下文中,可以使“${}”来使用变量。
<property name="log.path" value="E:/log" />
在上面定义文件路径中有使用到${log.path}
3.子节点<contextName>
:用来设置上下文名称,每个logger
都关联到logger
上下文,默认上下文名称为default
。但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改。
<contextName>myAppLogBack</contextName>
4.子节点<logger>
:用来设置某一个包或具体的某一个类的日志打印级别、以及指定<appender>
。
<logger>
仅有一个name
属性,一个可选的level
和一个可选的addtivity
属性。
name
:用来指定受此logger
约束的某一个包或者具体的某一个类。
level
:用来设置打印级别,大小写无关:TRACE
, DEBUG
, INFO
, WARN
, ERROR
, ALL
和 OFF
,
addtivity
: 是否向上级logger
传递打印信息。默认是true
。
<logger name="org.springframework.web" level="info" addtivity="true"/>
5.子节点<root>
:它也是<logger>
元素,但是它是根logger
,是所有<logger>
的上级。
root
节点是必选节点,用来指定最基础的日志输出级别,只有一个level
属性,因为name
已经被命名为root
,且已经是最上级了。
level
:用来设置打印级别,不能设置为INHERITED
或者同义词NULL
。默认是DEBUG
可以包含零个或多个元素,标识这个appender
将会添加到这个logger
。
<root level="all">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
6.子节点<springProfile>
:Spring profile
是Spring 3
引入的概念,主要用在项目多环境运行的情况下,通过激活方式实现多环境切换,省去多环境切换时配置参数和文件的修改,相比较Maven profile
简单实用,易于上手。并且Spring profile
提供了多种激活方法,例如配置文件,注解,jvm
参数设置等等
据不同环境(prod
:生产环境,test
:测试环境,dev
:开发环境)来定义不同的日志输出,在 logback-spring.xml
中使用 springProfile
节点来定义,方法如下:
<!-- 测试环境+开发环境. 多个使用逗号隔开. -->
<springProfile name="test,dev">
<logger name="com.example.springcloudeureka" level="info" />
</springProfile>
<!-- 生产环境. -->
<springProfile name="prod">
<logger name="com.example.springcloudeureka" level="ERROR" />
</springProfile>
可以启动服务的时候指定 profile
,springboot的话可以在配置文件yaml
中设置spring.profiles.active
7.子节点<conversionRule>
:logback 自定义Pattern模板
例如需要在每条日志都输出logback output
字符串,可以这样做
写一个转换器类,继承ClassicConvert
public class LogbackConvert extends ClassicConverter {
@Override
public String convert(ILoggingEvent iLoggingEvent) {
return "logback output";
}
}
实现里面的方法,返回的都是String
类型
在logback
配置文件中中注册该转换器,并自定义转换符
<conversionRule conversionWord="logback"
converterClass="com.example.springcloudeureka.LogbackConvert"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender" >
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %logback %n</pattern>
</appender>
在<appender>
中自定义Pattern
模板,用%转换器名
即可
效果
都打印出
logback output
字符串
Apache Commons Logging
官方地址:https://commons.apache.org/proper/commons-logging/
Jakarta Commons-logging(JCL)是apache
最早提供的日志的门面接口。提供简单的日志实现以及日志解耦功能。
commons-logging
是Apache commons
类库中的一员。Apache commons
类库是一个通用的类库,提供了基础的功能,比如说commons-fileupload
,commons-httpclient
,commons-io
,commons-codes
等。
commons-logging
能够选择使用Log4j
还是JDK Logging
,但是不依赖Log4j
,JDK Logging
的API
。如果项目的classpath
中包含了log4j
的类库,就会使用log4j
,否则就使用JDK Logging
。使用commons-logging
能够灵活的选择使用那些日志方式,而且不需要修改源代码。
不过现在Apache Commons Logging
也不更新了,最新的依赖(Jul 05, 2014)
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
具体实现
JCL有两个基本的抽象类:Log( 基本记录器 ) 和 LogFactory( 负责创建 Log 实例 )
public class SpringbootApplication {
public static Log LOG= LogFactory.getLog(SpringbootApplication.class);
public static void main(String[] args) {
LOG.debug("debug()...");
LOG.info("info()...");
LOG.error("error()...");
}
}
控制台显示
SpringBoot已经默认集成了
log4j
关于commons-logging日志解耦可以参考文章:https://blog.csdn.net/sakurainluojia/article/details/53534949
总结:
commons-logging
和slf4j
都是日志的接口,供用户使用,而没有提供实现。log4j
,logback
等才是日志的真正实现,日志是接口+具体实现的方式来使用。
目前应用比较广泛的是Log4j2
和logback
,而logback
作为后起之秀,以替代log4j
为目的,整体性能比log4j
较佳,log4j
的升级版log4j2
也是有诸多亮点
选择使用
logback
是Spring Boot
默认的日志系统,假如对日志没有特殊要求,可以完全零配置(当然也可以自定义logback-spring.xml
)使用 SLF4J(Simple Logging Facade For Java)
的logback
来输出日志。
个人推荐使用log4j2
,Log4j2
是Log4j
的升级版,与之前的版本Log4j 1.x
相比、有重大的改进,在修正了Logback
固有的架构问题的同时,改进了许多Logback
所具有的功能。关于Log4j2
的新特性可以在其官网首页查看
关于log4j2
的性能使用可以参考
https://www.jianshu.com/p/570b406bddcd
https://blog.csdn.net/u011054333/article/details/54412360
https://blog.csdn.net/yjh1271845364/article/details/70888262