参考文献:

Java 常用日志框架对比

总述

image

日志接口有:commons-logging、slf4j 等

实现日志的框架有:log4j、logging(JDK 自带)、logback、log4j2 等

日志级别

log4j 定义了8个级别的log(除去 OFF 和 ALL,可以说分为6个级别),
优先级从高到低依次为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL

ALL 最低等级的,用于打开所有日志记录。
TRACE 很低的日志级别,一般不会使用。
DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
INFO 消息在粗粒度级别上突出强调应用程序的运行过程,这个可以用于生产环境中输出程序运行的一些重要信息。
WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给开发者的一些提示。
ERROR 指出发生错误的信息,可能会导致系统出错或是宕机等,必须要避免
FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
OFF 最高等级,用于关闭所有日志记录。

commons-logging

Apache Commons Logging

官方地址: https://commons.apache.org/proper/commons-logging/

commons-logging 能够选择使用 log4j 还是 JDK logging。如果项目的 classpath 中包含了 log4j 的类库,就会使用 log4j,否则就使用 JDK logging。使用 commons-logging 能够灵活的选择使用那些日志方式,而且不需要修改源代码。不过现在 Apache Commons Logging 也不更新了

依赖

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

使用方法

public class Test {
    public static Log LOG= LogFactory.getLog(Test.class);
    public static void main(String[] args) {
        LOG.debug("debug()...");
        LOG.info("info()...");
        LOG.error("error()...");
    }
}

slf4j

官网地址:https://www.slf4j.org/

SLF4J(Simple Logging Facade for Java)用作各种日志框架(java.util.logging,logback,log4j)的抽象,允许最终用户在部署时插入所需的日志框架。

依赖

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.30</version>
    <scope>test</scope>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>

Springboot 项目不需要引入任何依赖都可以使用

使用方法:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test{
    private static final Logger logger = LoggerFactory.getLogger(Test.class);
    public static void main(String[] args) {
        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.error("error log");
    }
}

通常输出日志开销非常大,SLF4J 通过 {} 作为占位符的方式输出字符串,相比字符串拼接的方式,效率有显著的提升。

打印信息:

INFO pers.rainsheep.Test - Current Time: 1531731149036
INFO pers.rainsheep.Test - Current Time: 1531731149040

WARN pers.rainsheep.Test - warn log
DEBUG pers.rainsheep.Test - debug log
ERROR pers.rainsheep.Test - error log

log4j

已过时,不深究

官网地址:https://logging.apache.org/log4j/1.2/

依赖

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

log4j2

官网地址:https://logging.apache.org/log4j/2.x/

Log4j 的升级版,重构 log4j 做了很多优化,提供了 logback 中可用的许多改进,同时修复了 logback 架构中的一些固有问题。

依赖

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.12.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.12.1</version>
</dependency>

Spring boot 中自带 log4j2 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
    <version>2.3.4.RELEASE</version>
</dependency>

logback

官网地址:https://logback.qos.ch/

logback 和 log4j 是同一个作者创作,它是 log4j 的升级版

依赖

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-access</artifactId>
    <version>1.2.3</version>
</dependency>

springboot 不需要引入,引入

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
</dependency>

配置简介

如果没有配置文件,那么 logback 默认地会调用 BasicConfigurator ,创建一个最小化配置。最小化配置由一个关联到根 logger 的 ConsoleAppender 组成。输出用模式为 %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 的 PatternLayoutEncoder 进行格式化。

官方推荐使用的 xml 名字的格式为:logback-spring.xml 而不是 logback.xml,因为带 spring 后缀的可以使用 <springProfile> 这个标签。

选择使用

logback 是 Spring Boot 默认的日志系统,假如对日志没有特殊要求,可以完全零配置(当然也可以自定义 logback-spring.xml 使用 SLF4J 的 logback 来输出日志)。

本人使用slf4j + log4j2

使用 slf4j2

maven 坐标

<properties>
    <slf4j.version>1.7.30</slf4j.version>
    <log4j.version>2.12.1</log4j.version>
</properties>
<!-- slf4j 依赖 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
</dependency>
 <!-- log4j2 和 slf4j 桥接依赖 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>${log4j.version}</version>
</dependency>
<!-- log4j2 依赖 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>${log4j.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${log4j.version}</version>
</dependency>

测试类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Test {
    private static final Logger logger = LoggerFactory.getLogger(Test.class);

    public void fun(){
        logger.info("{} level", "info");
    }
}

配置文件命名

系统选择配置文件的优先级(从先到后)如下:

  • classpath 下的名为log4j2-test.json 或者log4j2-test.jsn 的文件.
  • classpath 下的名为log4j2-test.xml 的文件.
  • classpath 下名为log4j2.json 或者log4j2.jsn 的文件.
  • classpath 下名为log4j2.xml 的文件.

我们一般默认使用 log4j2.xml 进行命名。如果本地要测试,可以把 log4j2-test.xml 放到 classpath,而正式环境使用 log4j2.xml,则在打包部署的时候不要打包 log4j2-test.xml即可。

配置文件结点解析

  1. 根节点 Configuration

    属性:

    • status:用来指定 log4j 本身的打印日志的级别。
    • monitorinterval:用于指定 log4j 自动重新配置的监测间隔时间,单位是 s,最小是 5s

    子节点:

    • Appenders
    • Loggers (可以定义多个 Appender 和 Logger)
  2. Appenders 节点

    子节点:

    • Console :用来定义输出到控制台的 Appender
      (1)name:指定 Appender 的名字
      (2)target:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT
      (3)PatternLayout:输出格式,不设置默认为%m%n
    • File:用来定义输出到指定位置的文件的 Appender
      (1)name:指定 Appender 的名字
      (2)fileName:指定输出日志的目的文件,带全路径的文件名
      (3)PatternLayout:输出格式,不设置默认为%m%n
    • RollingFile:用来定义超过指定大小自动删除旧的并创建新的的 Appender
      (1)name:指定 Appender 的名字
      (2)fileName:指定输出日志的目的文件带全路径的文件名
      (3)PatternLayout:输出格式,不设置默认为%m%n
      (4)filePattern:指定新建日志文件的名称格式
      (5)Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志
      (6)TimeBasedTriggeringPolicy:Policies 子节点,基于时间的滚动策略,interval 属性用来指定多久滚动一次,默认是 1 hour。modulate=true 用来调整时间:比如现在是早上3am, interval 是4,那么第一次滚动是在 4am,接着是8am,12am...而不是 7am
      (7)SizeBasedTriggeringPolicy:Policies 子节点,基于指定文件大小的滚动策略,size 属性用来定义每个日志文件的大小.
      (8)DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过 max 属性)。
  3. Loggers 节点

    子节点:

    • Root :用来指定项目的根日志,如果没有单独指定 Logger,那么就会默认使用该 Root 日志输出
       (1)level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF
       (2)AppenderRef:Root的子节点,用来指定该日志输出到哪个 Appender
    • Logger:用来单独指定日志的形式,比如要为指定包下的 class 指定不同的日志级别等。
       (1)level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF
       (2)name:用来指定该 Logger 所适用的类或者类所在的包全路径,继承自 Root 节点.
       (3)AppenderRef:Logger 的子节点,用来指定该日志输出到哪个 Appender,如果没有指定,就会默认继承自 Root。如果指定了,那么会在指定的这个 Appender 和 Root 的 Appender 中都会输出,此时我们可以设置 Logger 的additivity="false" 只在自定义的 Appender 中进行输出。
  4. 关于日志 level

  • 共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF
  • All:最低等级的,用于打开所有日志记录.
  • Trace:是追踪,就是程序推进以下,你就可以写个 trace 输出,所以 trace 应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出.
  • Debug:指出细粒度信息事件对调试应用程序是非常有帮助的.
  • Info:消息在粗粒度级别上突出强调应用程序的运行过程.
  • Warn:输出警告及warn以下级别的日志.
  • Error:输出错误信息日志.
  • Fatal:输出每个严重的错误事件将会导致应用程序的退出的日志.
  • OFF:最高等级的,用于关闭所有日志记录.
  • 程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。

PatternLayout

参数:

charset #指定字符集
pattern #指定格式
alwaysWriteExceptions #默认为true,输出异常
header #可选项。包含在每个日志文件的顶部
footer #可选项。包含在每个日志文件的尾部。

格式:

######### 常见参数 #########
%c{参数} 或 %logger{参数}  ##输出日志名称
%C{参数} 或 %class{参数}   ##输出类型
%d{参数}                  ##输出时间
%F|%file                 ##输出文件名
highlight{pattern}{style}##高亮显示
%l  ##输出错误的完整位置
%L  ##输出错误行号
%m 或 %msg 或 %message ##输出错误信息
%M 或 %method ##输出方法名
%n            ##输出换行符
%level{参数1}{参数2}{参数3} ##输出日志的级别
%t 或 %thread              ##创建logging事件的线程名
%p  # 显示该日志的等级
*/

######### 特殊符号 ############
#有些特殊符号不能直接打印,需要使用实体名称或者编号
//
& —— & 或者 &
< —— <  或者 <
> —— >  或者 >
“ —— " 或者 "
‘ —— ' 或者 '
*/

######## pattern对齐修饰 ##########

// 对齐修饰,可以指定信息的输出格式,如是否左对齐,是否留空格等。
## 编写格式为在任何pattern和%之间加入一个小数,可以是正数,也可以是负数。
## 整数表示右对齐,负数表示左对齐;
## 整数位表示输出信息的最小n个字符,如果输出信息不够n个字符,将用空格补齐;
## 小数位表示输出信息的最大字符数,如果超过n个字符,则只保留最后n个字符的信息
## (注意:保留的是后20个字符,而不是前20个字符)
*/

#示例如下
//

+ —— 右对齐,不足20个字符则在信息前面用空格补足,超过20个字符则保留原信息
%-20 —— 左对齐,不足20个字符则在信息后面用空格补足,超过20个字符则保留原信息
%.30 —— 如果信息超过30个字符,则只保留最后30个字符
+.30 —— 右对齐,不足20个字符则在信息前面用空格补足,超过30个字符则只保留最后30个字符
%-20.30 —— 左对齐,不足20个字符则在信息后面用空格补足,超过30个字符则只保留最后30个字符


模板

<?xml version="1.0" encoding="UTF-8"?>
 <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
 <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
 <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
 <configuration status="WARN" monitorInterval="30">
     <!--先定义所有的appender-->
     <appenders>
     <!--这个输出控制台的配置-->
         <console name="Console" target="SYSTEM_OUT">
         <!--输出日志的格式-->
             <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
         </console>
         <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
         <File name="log" fileName="log/test.log" append="false">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
         </File>
         <!-- 这个会打印出所有的info及以上级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
         <RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log"
                      filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
             <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->  
             <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
             <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
             <Policies>
                 <TimeBasedTriggeringPolicy/>
                 <SizeBasedTriggeringPolicy size="100 MB"/>
             </Policies>
         </RollingFile>
         <RollingFile name="RollingFileWarn" fileName="${sys:user.home}/logs/warn.log"
                      filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
             <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
             <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
             <Policies>
                 <TimeBasedTriggeringPolicy/>
                 <SizeBasedTriggeringPolicy size="100 MB"/>
             </Policies>
         <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
             <DefaultRolloverStrategy max="20"/>
         </RollingFile>
         <RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log"
                      filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
             <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
             <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
             <Policies>
                 <TimeBasedTriggeringPolicy/>
                 <SizeBasedTriggeringPolicy size="100 MB"/>
             </Policies>
         </RollingFile>
     </appenders>
     <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
     <loggers>
         <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
         <logger name="org.springframework" level="INFO"></logger>
         <logger name="org.mybatis" level="INFO"></logger>
         <root level="all">
             <appender-ref ref="Console"/>
             <appender-ref ref="RollingFileInfo"/>
             <appender-ref ref="RollingFileWarn"/>
             <appender-ref ref="RollingFileError"/>
         </root>
     </loggers>
 </configuration>