彻底搞懂混而不乱的Java日志体系

1 混而不乱的Java日志体系

1.1 Java日志发展史

在这里插入图片描述

  • 1999年Ceki推出log4j日志框架,并捐给Apache。Ceki也加入Apache组织。据说Apache基金会还曾经建议Sun引入Log4j到Java的标准库中,但Sun拒绝了。
  • 2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。在JUL出来以前,Log4j就已经成为一项成熟的技术,使得Log4j在选择上占据了一定的优势;
  • 2003年Apache推出了JCL(Jakarta Commons Logging)。JCL只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现,也就是说,在你应用代码里,只需调用Commons Logging的接口,底层实现可以是Log4j,也可以是Java Util Logging;
  • 2006年,Ceki离开了Apache,回瑞典创建了QOS公司,然后先后创建了Slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目;
  • 2012年,Apache眼看有被Logback反超的势头,于2012-07重写了Log4j 1.x,成立了新的项目Log4j 2,2014年7月其GA版本(正式发布版)发布。

1.2 JUL

Sun公司在 jdk1.4版本增加了一个日志包java.util.logging,简称为jul,用以对抗log4j。

  • JUL控制台输出使用System.err 进行日志输出

在这里插入图片描述
在这里插入图片描述

  • JUL日志输出级别

    日志级别从小到大,分别为:ALL<FINEST<FINER<FINE<CONFIG<INFO<WARNING<SEVERE<OFF
    在这里插入图片描述

    输出所有:ALL

    非常详细: FINEST

    较详细: FINER

    详细: FINE

    配置: CONFIG

    信息: INFO

    警告: WARNING

    严重: SEVERE

    所有都不输出:OFF

    jul默认日志级别为INFO。默认配置文件在 %JAVA_HOME%/jre/lib/logging.properties

  • 使用方式

    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    //--------省略其他代码--------
    
    Logger logger=Logger.getLogger(JULService.class.getName());
    //方式1
    logger.log(Level.FINEST,"FINEST LOG");
    
    //方式2 简写
    logger.finest("finest log ");
    
    //--------省略其他代码--------
    
  • 配置文件

    默认配置文件在 %JAVA_HOME%/jre/lib/logging.properties

1.3 log4j

log4j最后一次更新时间是2012年。apache已不在维护,建议使用log4j2😂

1.3 .1 日志级别

级别描述
OFF最高级别,用于关闭日志记录。
FATAL导致应用程序提前终止的严重错误。一般这些信息将立即呈现在状态控制台上。
ERROR其他运行时错误或意外情况。一般这些信息将立即呈现在状态控制台上。
WARN使用已过时的API,API的滥用,潜在错误,其他不良的或意外的运行时的状况(但不一定是错误的)。一般这些信息将立即呈现在状态控制台上。
INFO令人感兴趣的运行时事件(启动/关闭)。一般这些信息将立即呈现在状态控制台上,因而要保守使用,并保持到最低限度。
DEBUG流经系统的详细信息。一般这些信息只记录到日志文件中。
TRACE最详细的信息。一般这些信息只记录到日志文件中

1.3.2 配置文件

  • 自定义输出格式说明

    %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
    %r 输出自应用启动到输出该log信息耗费的毫秒数
    %c 输出所属的类目,通常就是所在类的全名
    %t 输出产生该日志事件的线程名

    %m 用于输出与日志记录事件相关联的应用程序提供的消息。

    %n 输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
    %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
    %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。

  • Log4j提供的appender有以下几种:

    org.apache.log4j.ConsoleAppender(控制台),
    org.apache.log4j.FileAppender(文件),
    org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
    org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),
    org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

  • log4j.properties 文件

    # 把logger和具体的appender关联起来
    log4j.rootLogger=INFO,stdout,R,error
    
    # stdout 输出到控台
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    # 日志输出级别
    log4j.appender.stdout.Threshold = TRACE 
    # stdout 输出格式
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    # %d{yyyy-MM-dd HH:mm:ss} [Thread: %t] %-5p %20c %L:%m %n   
    log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [Thread: %t] %-5p %20c %L:%m %n   
    
    # R 输出到文件 (文件大小到达指定尺寸的时候产生一个新的文件)
    log4j.appender.R=org.apache.log4j.RollingFileAppender
    log4j.appender.R.File=/log/example.log
    log4j.appender.R.Append = true
    # 日志输出级别
    log4j.appender.R.Threshold = ERROR 
    # 日志文件最大大小
    log4j.appender.R.MaxFileSize=100MB
    #保留最近的7个日志文件
    log4j.appender.R.MaxBackupIndex=7
    log4j.appender.R.layout=org.apache.log4j.PatternLayout
    log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [Thread: %t] %-5p %20c %L:%m %n
    
    #  输出到文件,每天产生一个日志文件,不会自动清除日志文件
    log4j.logger.error=error
    log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.error.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.error.File = /log/error.log 
    log4j.appender.error.Append = true
    # 日志输出级别
    log4j.appender.error.Threshold = ERROR 
    log4j.appender.error.layout = org.apache.log4j.PatternLayout
    log4j.appender.error.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [Thread: %t] %-5p %20c %L:%m %n  
    
    
    log4j.logger.com.warybee=INFO
    
  • log4j.xml 文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE log4j:configuration PUBLIC "-//LOGGER" "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
    <log4j:configuration >
    
        <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [Thread: %t] %-5p %20c %L:%m %n "/>
            </layout>
        </appender>
    
        <!-- 输出到文件   -->
        <appender name="log4jFile"  class="org.apache.log4j.rolling.RollingFileAppender">
            <param name="Append" value="true"/>
            <rollingPolicy  class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
                <param name="FileNamePattern" value="./log/log_%d{yyyy-MM-dd}.log" />
            </rollingPolicy>
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [Thread: %t] %-5p %20c %L:%m %n "/>
            </layout>
            <filter class="org.apache.log4j.varia.LevelRangeFilter">
                <param name="LevelMin" value="DEBUG"/>
                <param name="LevelMax" value="DEBUG"/>
            </filter>
        </appender>
    
        <!--
           category(类别)为'org.springframework'的logger只记录level为“info”或更高级别的消息;
           即:如果您使用的类名获取logger(如Logger.getLogger(AClass.class))
           而且AClass是org.springframework包的一部分,则它属于这一category
      -->
        <logger name="org.springframework">
            <level value="info"/>
        </logger>
    
        <root>
            <!--
                所有日志消息的级别为“debug”或更高的将被记录,除非另有定义
                所有日志消息将都记录到appender “stdout”中,除非另有定义
            -->
            <level value="debug" />
            <appender-ref ref="stdout" />
            <appender-ref ref="log4jFile" />
        </root>
    </log4j:configuration>
    
  • 使用

    添加依赖

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.16</version>
    </dependency>
    
package com.warybee.service;

import org.apache.log4j.Logger;

public class Log4jTestService {

      private static Logger logger=Logger.getLogger(Log4jTestService.class);

      public void test1(){

            logger.trace("trace");
            logger.debug("logger");
            logger.info("info");
            logger.warn("warn");
            logger.error("error");
            logger.fatal("fatal");
      }
}

1.4 JCL

JCL,全称为"Jakarta Commons Logging"。最后一次更新2014年,差不多已经退出历史舞台。

commons-logging的目的是为“所有的Java日志实现”提供一个统一的接口,使项目与日志实现工具解耦,具体的日志实现可以是Log4j,也可以是Java Util Logging

  • 添加依赖包

    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    
  • 使用

    package com.warybee.service;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    public class JCLService {
    
          private static Log log= LogFactory.getLog(JCLService.class);
          
          public void test1(){
              log.trace("trace");
              log.debug("log");
              log.info("info");
              log.warn("warn");
              log.error("error");
              log.fatal("fatal");
          }
    }
    

JCL默认使用JUL(Java Util Logging)进行日志输出

  • commons-logging+log4j

    • 添加log4j依赖

      <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.16</version>
      </dependency>
      
    • 添加log4j配置文件

      参考上一节log4j配置

1.5 Slf4j+logback

JAVA简易日志门面(Simple Logging Facade for Java,缩写SLF4J)

1.5.1 依赖

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.32</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.6</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.6</version>
</dependency>

1.5.2 使用

package com.warybee;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;

public class Slf4jService {

    final Logger logger = LoggerFactory.getLogger(Slf4jService.class);

    public void test1(String name){

        logger.info("param is {}",name);
    }
}

1.5.3 日志级别

SLF4J相比log4j去除了FATAL 级别。其他与log4j一样

级别描述
ERROR其他运行时错误或意外情况。一般这些信息将立即呈现在状态控制台上。
WARN使用已过时的API,API的滥用,潜在错误,其他不良的或意外的运行时的状况(但不一定是错误的)。一般这些信息将立即呈现在状态控制台上。
INFO令人感兴趣的运行时事件(启动/关闭)。一般这些信息将立即呈现在状态控制台上,因而要保守使用,并保持到最低限度。
DEBUG流经系统的详细信息。一般这些信息只记录到日志文件中。
TRACE最详细的信息。一般这些信息只记录到日志文件中

1.5.4 logback配置文件

① 根节点

包含下面三个属性:

  • scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
  • scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
  • debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false

示例:

<configuration scan="true" scanPeriod="60*1000" debug="true">

    <!--省略其他-->
</configuration>
② property

可以用来设置变量,可以通过${name}来访问
示例:

<configuration scan="true" scanPeriod="60*1000" debug="true">
   <!--定义日志输出目录-->
    <property name="log.path" value="/logs/logback.log" />
</configuration>
③ 子节点 appender

负责写日志的组件,它有两个必要属性name和class。name指定appender名称,class指定appender的全限定名。下面只介绍常见的appder

Ⅰ ConsoleAppender

把日志输出到控制台,有以下子节点

  • :对日志进行格式化。
  • :字符串System.out(默认)或者System.err
<configuration scan="true" scanPeriod="60" debug="true">
    <!--定义日志输出目录-->
    <property name="log.path" value="/logs/logback.log" />
    <!--输出到控制台-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <root level="debug">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>
Ⅱ FileAppender

把日志添加到文件,有以下子节点

  • :被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
  • :如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
  • :对记录事件进行格式化。
  • :如果是 true,日志会被安全的写入文件,即使其他的FileAppender也在向此文件做写入操作,效率低,默认是 false。
<configuration scan="true" scanPeriod="60" debug="true">
    <!--定义日志输出目录-->
    <property name="log.path" value="/logs/logback.log" />
    <!--输出到文件-->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
         <file>${log.path}</file>
         <append>true</append>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="FILE" />
    </root>
</configuration>
RollingFileAppender

滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。有以下子节点:

  • :被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。

  • :如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true

  • :当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名。属性class定义具体的滚动策略类

  • ch.qos.logback.core.rolling.TimeBasedRollingPolicy

    最常用的滚动策略,它根据时间来制定滚动策略,有如下子节点:

    • 文件名称生成规则,默认格式是 yyyy-MM-dd
    • 控制保留的归档文件的最大数量,超出数量就删除旧文件
  • ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy

    根据当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动。

<configuration scan="true" scanPeriod="60" debug="true">
    <!--定义日志输出目录-->
    <property name="log.path" value="/logs/logback.log" />
    
    <!--每天生成一个日志文件-->
    <appender name="RFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/debug.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/debug.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <!--最多保留30天的日志文件-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="RFILE" />
    </root>
</configuration>
④ 子节点 logger

用来设置某一个包或具体的某一个类的日志打印级别、以及指定

包含的属性有:

  • name属性:用来指定受此loger约束的某一个包或者具体的某一个类
  • level属性:用来设置打印级别,大小写无关:ALL,TRACE, DEBUG, INFO, WARN, ERROR,和OFF, 如果未设置此属性,那么当前loger将会继承上级的级别
  • addtivity属性:是否向上级logger传递打印信息。默认是true
  • 可以包含零个或多个元素,标识这个appender将会添加到这个logger。
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
⑤ 子节点Root
  • level属性:用来设置打印级别,大小写无关:ALL,TRACE, DEBUG, INFO, WARN, ERROR,和OFF, 如果未设置此属性,那么当前loger将会继承上级的级别
  • 可以包含零个或多个元素,标识这个appender将会添加到这个logger。
<root level="debug">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
</root>
⑥ logback配置实例
<configuration scan="true" scanPeriod="60" debug="true">
    <!--定义日志输出目录-->
    <property name="log.path" value="/logs/logback.log" />
    <!--输出到控制台-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
        </encoder>
    </appender>

    <!--输出到文件-->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
         <file>${log.path}</file>
         <append>true</append>
        <encoder>
            <pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
        </encoder>
    </appender>
    <!--每天生成一个日志文件-->
    <appender name="RFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/debug.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/debug.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <!--最多保留30天的日志文件-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- All < Trace < Debug < Info < Warn < Error < Fatal < OFF. -->
    <root level="Info">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
        <appender-ref ref="RFILE" />
    </root>
</configuration>

1.6 slf4j+log4j2

         <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.32</version>
        </dependency>

        <!--slf4j对应log4j2的中间件,即桥接,告诉slf4j使用log4j2-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.14.1</version>
        </dependency>

        <!--log4j2核心包-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.14.1</version>
        </dependency>

log4j2配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration status="WARN">

    <Properties> <!-- 配置日志文件输出目录,此配置将日志输出到工程目录下的log4j2_logs文件夹 -->
        <Property name="LOG_HOME">
            log4j2_logs
        </Property>
    </Properties>

    <Appenders>
    <!--这个输出控制台的配置,即System.out -->
    <Console name="console_out_appender" target="SYSTEM_OUT">
        <!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) . -->
        <ThresholdFilter level="INFO" onMatch="ACCEPT"
                         onMismatch="DENY" />
        <!-- 输出日志的格式 -->
        <PatternLayout pattern="%5p [%t] %d{yyyy-MM-dd HH:mm:ss} (%F:%L) %m%n" />
    </Console>
        
    <!-- 这个输出控制台的配置,这里输出error级别的信息到System.err -->
    <Console name="console_err_appender" target="SYSTEM_ERR">
        <ThresholdFilter level="ERROR" onMatch="ACCEPT"
                         onMismatch="DENY" />
        <PatternLayout pattern="%5p [%t] %d{yyyy-MM-dd HH:mm:ss} (%F:%L) %m%n" />
    </Console>


    <!-- TRACE级别日志 ; 设置日志格式并配置日志压缩格式,压缩文件独立放在一个文件夹内, 日期格式不能为冒号,否则无法生成,因为文件名不允许有冒号,此appender只输出trace级别的数据到trace.log -->
    <RollingFile name="trace_appender" immediateFlush="true"
                 fileName="${LOG_HOME}/trace.log" filePattern="${LOG_HOME}/trace/trace - %d{yyyy-MM-dd HH:mm:ss}.log.gz">
        <PatternLayout>
            <pattern>%5p [%t] %d{yyyy-MM-dd HH:mm:ss} (%F:%L) %m%n</pattern>
        </PatternLayout>
        <Policies>
            <!-- 每个日志文件最大2MB -->
            <SizeBasedTriggeringPolicy size="2MB" />
        </Policies>
        <Filters>
            <!-- 此Filter意思是,只输出TRACE级别的数据 DENY,日志将立即被抛弃不再经过其他过滤器; NEUTRAL,有序列表里的下个过滤器过接着处理日志;
                ACCEPT,日志会被立即处理,不再经过剩余过滤器。 -->
            <ThresholdFilter level="debug" onMatch="DENY"
                             onMismatch="NEUTRAL" />
            <ThresholdFilter level="trace" onMatch="ACCEPT"
                             onMismatch="DENY" />
        </Filters>
    </RollingFile>

    <!-- DEBUG级别日志 设置日志格式并配置日志压缩格式,压缩文件独立放在一个文件夹内, 日期格式不能为冒号,否则无法生成,因为文件名不允许有冒号,此appender只输出debug级别的数据到debug.log; -->
    <RollingFile name="debug_appender" immediateFlush="true"
                 fileName="${LOG_HOME}/debug.log" filePattern="${LOG_HOME}/debug/debug - %d{yyyy-MM-dd HH:mm:ss}.log.gz">
        <PatternLayout>
            <pattern>%5p [%t] %d{yyyy-MM-dd HH:mm:ss} (%F:%L) %m%n</pattern>
        </PatternLayout>
        <Policies><!-- 每个日志文件最大2MB ; -->
            <SizeBasedTriggeringPolicy size="2MB" />

            <!-- 如果启用此配置,则日志会按文件名生成新压缩文件, 即如果filePattern配置的日期格式为 %d{yyyy-MM-dd HH}
                ,则每小时生成一个压缩文件, 如果filePattern配置的日期格式为 %d{yyyy-MM-dd} ,则天生成一个压缩文件 -->
            <TimeBasedTriggeringPolicy interval="1"
                                       modulate="true" />

        </Policies>
        <Filters><!-- 此Filter意思是,只输出debug级别的数据 -->
            <ThresholdFilter level="info" onMatch="DENY"
                             onMismatch="NEUTRAL" />
            <ThresholdFilter level="debug" onMatch="ACCEPT"
                             onMismatch="DENY" />
        </Filters>
    </RollingFile>

    <!-- INFO级别日志 -->
    <RollingFile name="info_appender" immediateFlush="true"
                 fileName="${LOG_HOME}/info.log" filePattern="${LOG_HOME}/info/info - %d{yyyy-MM-dd HH:mm:ss}.log.gz">
        <PatternLayout>
            <pattern>%5p [%t] %d{yyyy-MM-dd HH:mm:ss} (%F:%L) %m%n</pattern>
        </PatternLayout>
        <Policies>
            <SizeBasedTriggeringPolicy size="2MB" />
        </Policies>
        <Filters>
            <ThresholdFilter level="warn" onMatch="DENY"
                             onMismatch="NEUTRAL" />
            <ThresholdFilter level="info" onMatch="ACCEPT"
                             onMismatch="DENY" />
        </Filters>
    </RollingFile>

    <!-- WARN级别日志 -->
    <RollingFile name="warn_appender" immediateFlush="true"
                 fileName="${LOG_HOME}/warn.log" filePattern="${LOG_HOME}/warn/warn - %d{yyyy-MM-dd HH:mm:ss}.log.gz">
        <PatternLayout>
            <pattern>%5p [%t] %d{yyyy-MM-dd HH:mm:ss} (%F:%L) %m%n</pattern>
        </PatternLayout>
        <Policies>
            <SizeBasedTriggeringPolicy size="2MB" />
        </Policies>
        <Filters>
            <ThresholdFilter level="error" onMatch="DENY"
                             onMismatch="NEUTRAL" />
            <ThresholdFilter level="warn" onMatch="ACCEPT"
                             onMismatch="DENY" />
        </Filters>
    </RollingFile>

    <!-- ERROR级别日志 -->
    <RollingFile name="error_appender" immediateFlush="true"
                 fileName="${LOG_HOME}/error.log" filePattern="${LOG_HOME}/error/error - %d{yyyy-MM-dd HH:mm:ss}.log.gz">
        <PatternLayout>
            <pattern>%5p [%t] %d{yyyy-MM-dd HH:mm:ss} (%F:%L) %m%n</pattern>
        </PatternLayout>
        <Policies>
            <SizeBasedTriggeringPolicy size="2MB" />
        </Policies>
        <Filters>
            <ThresholdFilter level="error" onMatch="ACCEPT"
                             onMismatch="DENY" />
        </Filters>
    </RollingFile>
</Appenders>

    <loggers>
        <!--使appender生效-->
        <!-- 配置日志的根节点 -->
        <!-- 定义logger,只有定义了logger并引入了appender,appender才会生效 -->
        <root level="trace">
            <appender-ref ref="console_out_appender" />
            <appender-ref ref="console_err_appender" />
            <appender-ref ref="trace_appender" />
            <appender-ref ref="debug_appender" />
            <appender-ref ref="info_appender" />
            <appender-ref ref="warn_appender" />
            <appender-ref ref="error_appender" />
        </root>

    </loggers>
</configuration>

2 统一日志输出

2.1 Slf4j适配器

在这里插入图片描述

图片来自官网:http://www.slf4j.org/manual.html

如果你想用slf4j作为日志门面的话,你如何去配合使用其他日志实现组件

  • slf4j + logback
    slf4j-api.jar + logback-classic.jar + logback-core.jar
  • slf4j + log4j
    slf4j-api.jar + slf4j-log4j12.jar + log4j.jar
  • slf4j + jul
    slf4j-api.jar + slf4j-jdk14.jar
  • 也可以只用slf4j无日志实现
    slf4j-api.jar + slf4j-nop.jar

2.2 Slf4j桥接器

在这里插入图片描述

图片来自官网文档:http://www.slf4j.org/legacy.html

  • jcl-over-slf4j.jar

    简化从 JCL 到 SLF4J 的迁移

  • log4j-over-slf4j

    简化从log4j 到 SLF4J 的迁移

  • jul-over-slf4j.jar
    简化从 JUL 到 SLF4J 的迁移

场景应用

自己的应用使用了slf4j+logback,引入的第三方框架使用的是log4j,此时如何桥接到slf4j进行统一管理?方法如下:

  1. 排除掉第三方框架的日志实现,第三框框架(log4j-demo)使用的log4j,要先排除掉。

    <dependency>
        <groupId>com.warybee</groupId>
        <artifactId>log4j-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
        <exclusions>
            <exclusion>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
  2. 引入桥接器

    <!-- 引入log4j桥接器 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>log4j-over-slf4j</artifactId>
        <version>1.7.32</version>
    </dependency>
    
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

warybee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值