Logback日志框架

Logback日志框架

1、Logback入门案例

1、Logback简介

官方网站:https://logback.qos.ch/index.html、Maven 仓库地址:https://search.maven.org/artifact/ch.qos.logback/logback-classic

Logback日志框架的优势:

  • Logback 是 log4j 框架的作者开发的新一代日志框架(性能比Log4j要好),它效率更高、能够适应诸多的运行环境,同时天然支持SLF4J
  • Logback的定制性更加灵活,同时也是SpringBoot的内置日志框架

Logback主要分为三个模块:

  • logback-core:其它两个模块的基础模块,也是最核心的模块
  • logback-classic:它是Log4j的一个改良版本,同时它完整实现了SLF4J API。使你可以方便的更换成其它日志框架(Log4j、JUL)
  • logback-access:访问模块与Servlet容器集成提供通过HTTP来访问日志的功能

2、Logback示例


<dependency>
    <groupId>org.slf4jgroupId>
    <artifactId>slf4j-apiartifactId>
    <version>1.7.32version>
dependency>

<dependency>
    <groupId>ch.qos.logbackgroupId>
    <artifactId>logback-coreartifactId>
    <version>1.2.3version>
dependency>



<dependency>
    <groupId>ch.qos.logbackgroupId>
    <artifactId>logback-classicartifactId>
    <version>1.2.3version>
dependency>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogbackTest {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(LogbackTest.class);
        logger.error("error test");
        logger.warn("warn test");
        logger.info("info {}", "test");
        logger.debug("debug test ");
        logger.trace("trace test");
    }
}
17:12:38.837 [main] ERROR LogbackTest - error test
17:12:38.840 [main] WARN LogbackTest - warn test
17:12:38.840 [main] INFO LogbackTest - info test
17:12:38.841 [main] DEBUG LogbackTest - debug test 

源码分析:其实我们发现即使项目中没有引入slf4j我们这里也是用的slf4j门面进行编程,下面我们查看源码及依赖传递:

1、可以查看到Logback中的Logger继承了org.slf4j.Logger

package ch.qos.logback.classic;
public final class Logger implements org.slf4j.Logger, LocationAwareLogger, AppenderAttachable<ILoggingEvent>, Serializable {}

2、从logback的pom依赖中我们看到slf4-api及logback-core,依赖会进行传递

<
parent>
    <groupId>ch.qos.logbackgroupId>
    <artifactId>logback-parentartifactId>
    <version>1.2.3version>
parent>
<artifactId>logback-classicartifactId>
<dependencies>
    <dependency>
        <groupId>ch.qos.logbackgroupId>
        <artifactId>logback-coreartifactId>
        <scope>compilescope>
    dependency>
    <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>slf4j-apiartifactId>
        <version>${slf4j.version}version>
        <scope>compilescope>
    dependency>
dependencies>

2、组件介绍及配置

1、几大组件介绍

  1. Logger:日志的记录器,主要用于存放日志对象,也可以定义日志类型、级别
  2. Appender:输出源,用于指定日志输出的目的地(可以是控制台、文件、数据库 等等)
  3. Encoder:与Layout一样,用来格式化日志信息输出,把事件转换成字符串。注意:在logback 0.9.19 版之前没有 encoder
  4. Layout:在Logback中Layout对象被封装在Encoder中,Encoder等于Layout。所以一般使用的都是encoder
  5. Level:是用来定义日志级别的(默认是:DEBUG)
  6. Filter:过滤器,根据需要定制哪些信息会被记录,哪些信息会被放过
  7. LoggerContext:各个logger都被关联到一个LoggerContext,LoggerContext负责制造logger,也负责以树结构排列各logger。其他所有logger也通过org.slf4j.LoggerFactory 类的静态方法getLogger取得。 getLogger方法以 logger名称为参数。用同一名字调用LoggerFactory.getLogger 方法所得到的永远都是同一个logger对象的引用

Appender :Logback 将写入日志事件的任务委托给一个名为 Appender 的组件。Appender 必须实现 ch.qos.logback.core.Appender 接口,Appender组件用来定义日志输出格式,日志如何过滤以及日志文件的处理。appender元素可以包含零个或一个layout元素,零个或多个encoder元素以及零个或多个filter元素。

Encoder:一个appender有一个encoder,负责将一个event事件转换成一组byte数组,并将转换后的字节数据输出到文件中。Encoder负责把事件转换为字节数组,并把字节数组写到合适的输出流。因此,encoder可以控制在什么时候、把什么样的字节数组写入到其拥有者维护的输出流中。Encoder接口有两个实现类,LayoutWrappingEncoder与PatternLayoutEncoder。注意:在logback 0.9.19 版之前没有 encoder。在之前的版本里,多数 appender 依靠 layout 来把事件转换成字符串并用java.io.Writer 把字符串输出。在之前的版本里,用户需要在FileAppender里嵌入一个 PatternLayout。

Level:Logback日志级别如下(默认级别:DEBUG):

// ERROR(错误信息) > WARN(警告信息) > INFO(重要信息) > DEBUG(普通信息) > TRACE(追踪信息) DEBUG为默认的打印级别
public static final Integer OFF_INTEGER = 2147483647;  // OFF:最高等级的而级别,用于关闭所有的日志记录
public static final Integer ERROR_INTEGER = 40000;     // ERROR:记录错误信息,不会影响系统运行。一般不想输出太多日志,则使用该级别即可
public static final Integer WARN_INTEGER = 30000;      // WARN:记录警告信息
public static final Integer INFO_INTEGER = 20000;      // INFO:记录运行信息
public static final Integer DEBUG_INTEGER = 10000;     // DEBUG:(默认)记录调式信息,一般在开发中使用
public static final Integer TRACE_INTEGER = 5000;      // TRACE:记录追踪信息,记录程序的流程信息,一般情况不会使用
public static final Integer ALL_INTEGER = -2147483648; // ALL:最低等级,用于打开所有级别的日志记录

LoggerContext:可以在代码中直接获取LoggerContext,通过LoggerContext可以动态修改Logback的配置

import org.sflf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;

LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
// 根据包路径或类路径获取日志记录器,"ROOT" 表示根记录器: Logger getLogger(final String name);
loggerContext.getLogger(Logger.ROOT_LOGGER_NAME).setLevel(Level.toLevel("error"));
// 停止logback-classic,也就是停止Logback
loggerContext.stop();

2、配置文件加载

Logback提供了三种种配置文件:logback.groovy、logback-test.xml、logback.xml(位于src/main/resources目录下)如果都不存在则采用默认的配置

  1. Logback首先会试着查找logback.groovy文件
  2. 当没有找到时,继续试着查找logback-test.xml文件
  3. 当没有找到时,继续试着查找logback.xml文件
  4. 如果仍然没有找到,则使用默认配置(打印到控制台)
  5. 其加载顺序为(优先级从高到低):logback.groovy =》 logback-test.xml =》 logback.xml

对XML日志文件的配置,大多数人第一次接触时有一种望而生畏的感觉,其实如果仔细分析,会发现核心的部分只有三个元素:appender、logger、root

                              ┌── 日志输出格式
               ┌───appender───┼── 日志过滤
               │              └── 日志文件处理
               │              ┌── 获取哪些(包)的日志
               ├────logger────┤                     	──┐
               │              └── 日志的输出级别            ├ 日志组件(root,logger)
               │              ┌── 根节点                 ──┘
configuration──┼─────root─────┤
               │              └── 只有level属性
               │
               │─────property──── 定义变量(非必须)
               │
               └───contextName─── 应用上下文名称(非必须)

3、XML配置模板

模板 1:







<configuration scan="true" scanPeriod="10 seconds">
    
    <contextName>logback-springcontextName>
    
    <property name="logging.path" value="myLogs"/>

    
    
    <conversionRule conversionWord="clr"
                    converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
    
    <property name="CONSOLE_LOG_PATTERN"
              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debuglevel>
        filter>

        
        <encoder>
            
            <Pattern>${CONSOLE_LOG_PATTERN}Pattern>
            
            <charset>UTF-8charset>
        encoder>
    appender>

    
    
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${logging.path}/web_debug.logfile>

        
        <encoder>
            
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            
            <charset>UTF-8charset>
        encoder>

        
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            
            <fileNamePattern>${logging.path}/web-debug-%d{yyyy-MM-dd}.%i.logfileNamePattern>

            
            <timeBasedFileNamingAndTriggeringPolicy
                                                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>

            
            <maxHistory>15maxHistory>
        rollingPolicy>

        
        
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            
            <level>debuglevel>
            
            <onMatch>ACCEPTonMatch>
            
            <onMismatch>DENYonMismatch>
        filter>
    appender>


    
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${logging.path}/web_info.logfile>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            <charset>UTF-8charset>
        encoder>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <fileNamePattern>${logging.path}/web-info-%d{yyyy-MM-dd}.%i.logfileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                                                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
            
            <maxHistory>15maxHistory>
        rollingPolicy>
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>infolevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>

    
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${logging.path}/web_warn.logfile>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            <charset>UTF-8charset> 
        encoder>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logging.path}/web-warn-%d{yyyy-MM-dd}.%i.logfileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                                                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
            
            <maxHistory>15maxHistory>
        rollingPolicy>
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warnlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>

    
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${logging.path}/web_error.logfile>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            <charset>UTF-8charset> 
        encoder>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logging.path}/web-error-%d{yyyy-MM-dd}.%i.logfileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                                                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
            
            <maxHistory>15maxHistory>
        rollingPolicy>
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERRORlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>

    

    

    

    
    
    

    
    <root level="info">
        <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>

    

configuration>

模板 2:



<configuration scan="true" scanPeriod="60 seconds" debug="false">
    
    <property name="log_dir" value="logs/" />
    
    <property name="maxHistory" value="30"/>

    
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%npattern>
        encoder>
    appender>

    
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERRORlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/error-log.logfileNamePattern>
            
            <maxHistory>${maxHistory}maxHistory>
        rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
        encoder>
    appender>

    
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARNlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/warn-log.log
            fileNamePattern>
            
            <maxHistory>${maxHistory}maxHistory>
        rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
        encoder>
    appender>

    
    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFOlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/info-log.log
            fileNamePattern>
            
            <maxHistory>${maxHistory}maxHistory>
        rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
        encoder>
    appender>

    <appender name="DruidFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <FileNamePattern>${log_dir}/settle-query.log-druid-%d{yyyy-MM-dd}FileNamePattern>
            
            <MaxHistory>90MaxHistory>
        rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            
            <pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
            pattern>
        encoder>
    appender>

    
    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUGlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/debug-log.log
            fileNamePattern>
            
            <maxHistory>${maxHistory}maxHistory>
        rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
        encoder>
    appender>

    
    <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>TRACElevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/trace-log.log
            fileNamePattern>
            
            <maxHistory>${maxHistory}maxHistory>
        rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%npattern>
        encoder>
    appender>

    
    <logger name="org.springframework" value="WARN" />
    <logger name="org.apache" value="WARN" />
    <logger name="com.netflix" value="WARN" />
    <logger name="me.chanjar" value="WARN" />
    <logger name="com.ulisesbocchio" value="WARN" />
    <logger name="org.hibernate" value="WARN" />
    <logger name="com.github.liuweijw" value="INFO" />
    <logger name="c.n.discovery" value="WARN" />
    <logger name="o.s.c.s" value="WARN" />
    <logger name="c.u.j.encryptor" value="WARN" />
    <logger name="o.s.boot" value="WARN" />
    
    <logger name="druid" level="DEBUG">
        <appender-ref ref="DruidFILE" />
    logger>
    
    <root level="INFO">
        
        <appender-ref ref="STDOUT" />
        
        <appender-ref ref="ERROR" />
        <appender-ref ref="INFO" />
    root>
configuration>

3、配置文件结构详解

Logback的配置,需要配置输出源Appender,打日志的Logger(子节点)和Root(根节点)实际上,它输出日志是从子节点开始,子节点如果有输出源直接输出,如果无,判断配置的additivity,是否向上级传递,即是否向root传递,传递则采用Root的输出源,否则不输出日志。

logback.xml配置文件根结点为configuration,内主要包含contextName、property、appender、filter、pattern、logger、root 等结点。基本结构可以描述为1个configuration元素,包含零个或多个appender元素,后跟零个或多个logger元素,后跟最多1个root元素(也可以没有)

01、configuration 根元素

根元素configuration有三个属性:debug、 scan、scanPeriod,及一个特殊的属性:packagingData,示例及解释如下:

  • debug:默认为false,若设置为true,则打印出logback内部运行日志信息
  • scan:默认值为true,若设置为true,配置文件如果发生改变,将会自动重新加载配置文件
  • scanPeriod:与scan配合使用,当scan为true时,此属性生效,默认的时间间隔为1分钟,设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。可以设置为scanPeriod="30 seconds"每30秒检测一次。单位有:milliseconds、seconds、munites、hours,默认为milliseconds
    注意:如果是在本地 IDE 编辑器中测试,注意修改的是 classes 编译目录下的 logback.xml 文件,而不是 resources 目录下的源文件(一般不用)
  • packagingData:在堆栈跟踪中启用包数据。注意从版本1.1.4开始,包装数据默认为禁用




<configuration debug="true" scan="true" scanPeriod="60 seconds">
configuration>    

开启packagingDatas配置:可按如下配置开启包数据(配置文件或者代码形式取其一即可):

<configuration packagingData="true">
configuration>
import org.sflf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;

LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
loggerContext.setPackagingDataEnabled(true);

如果开启了,logback 会在输出的堆栈行中显示它是属于哪个 jar 或者哪个类的。此信息由 jar 文件的名称和版本组成,表明堆栈信息来源于此。此机制对于识别软件版本问题非常有用。但是,计算成本相当昂贵,尤其是在经常引发异常的应用程序中。以下演示开启的结果,即多了 [] 括号内的信息。

14:28:48.835 [btpool0-7] INFO  c.q.l.demo.prime.PrimeAction - 99 is not a valid value
java.lang.Exception: 99 is invalid
  at ch.qos.logback.demo.prime.PrimeAction.execute(PrimeAction.java:28) [classes/:na]
  at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431) [struts-1.2.9.jar:1.2.9]
  at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236) [struts-1.2.9.jar:1.2.9]
  at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432) [struts-1.2.9.jar:1.2.9]
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) [servlet-api-2.5-6.1.12.jar:6.1.12]
  at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502) [jetty-6.1.12.jar:6.1.12]
  at ch.qos.logback.demo.UserServletFilter.doFilter(UserServletFilter.java:44) [classes/:na]
  at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115) [jetty-6.1.12.jar:6.1.12]
  at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361) [jetty-6.1.12.jar:6.1.12]
  at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417) [jetty-6.1.12.jar:6.1.12]
  at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) [jetty-6.1.12.jar:6.1.12]

02、contextName 元素

日志上下文名称:contextName,每个日志组件(logger)都会关联到日志上下文,默认上下文名称是:default,用于标识应用,如果多个应用输出到同一个地方,就有必要使用%contextName来区别。contextName直接在configuration元素下:

<configuration>
    
    <contextName>HelloWorld-logcontextName>
configuration>

03、property 属性元素

1、用来定义变量值的标签,通过property定义的值会被插入到logger上下文中。property标签中有: name、value 两个属性,属性含义如下:

  • name:值是变量的名称
  • value:值是变量定义的值
  • 定义变量后,可以使${name}来使用变量
<configuration>
    
    <property name="logName" value="logbackStudy" />
    
    <property resource="logback.properties" />
    
    <property file="D:\\logback.properties" />
configuration>

2、如果是在Spring或SpringBoot项目当中,想让value值是通过配置文件获取,可使用springProperty来定义。这里是获取项目名称和运行的服务器IP

  • scope:作用域
  • name:名称,在下面引用的时候的名字
  • source:在application.properties文件中的key
  • defaultValue:默认值,该属性在application.properties中未设置时,会使用默认值

<springProperty scope="context" name="appName" source="spring.application.name" />
<springProperty scope="context" name="ip" source="spring.cloud.client.ipAddress" />

3、变量作用域(scope)

定义的变量是有作用域的,如本地作用域,上下文作用域,系统级作用域。默认是本地作用域。

  1. Local Scope(本地作用域):从配置文件中定义的本地变量即在本地配置文件使用。每次解析和执行配置文件时,都会重新定义本地作用域中的变量
  2. Context Scope(上下文作用域):一个拥有上下文作用域的变量存在于上下文中,于上下文共存,直到被清除。在所有记录事件中都可用到,包括那些通过序列化发送到远程主机的事件
  3. System Scope(系统级作用域):系统级作用域的变量被插入到JVM的系统属性中,生命周期和JVM一致,直到被清除
  4. 在进行属性替换时,查找变量的顺序为:local,context,system

04、timestamp 时间元素

获取时间戳字符串并格式化:timestamp。他有两个属性key和datePattern

  1. key:标识timestamp的名字
  2. datePattern:设置将当前时间(解析配置文件的时间)转换为字符串的模式,遵循java.txt.SimpleDateFormat的格式
<configuration>
    
    <timestamp key="nowDate" datePattern="yyyyMMdd" />
    <timestamp key="nowDateTime" datePattern="yyyyMMdd_HHmmss" />
    <contextName>${nowDateTime}contextName>  
configuration>

05、conversionRule 元素

主要用来配置转换器,可以自定义Pattern模板,也可以引入一些其他模板来解析Pattern,比如打印彩色日志,打印IP地址。conversionRule 元素中有两个参数,解释如下:

  • conversionWord:在Pattern中的关键字
  • converterClass:转换器类


<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />


<property name="COLOR_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%p) %clr(${PID}){magenta} %clr([%.10t]){yellow} %clr([%c{1}]){blue}%clr([%L]){faint}%X{traceId} %m%n"/>

上面%clr就是要用ColorConverter来解析,后面{blue}就是要展示的颜色。

06、appender 日志输出元素

Appender 的介绍

官方文档为:https://logback.qos.ch/manual/appenders.html

Appender 的组件有两个属性:name和class,并且需要强制赋值,解释如下:

  • name:定义写日志组件的唯一名称,可以随便定义,后面使用该appender是也是通过名称来指定
  • class:指定要实例化的appender类的完全限定名称

Appender种类有很多,常用的种类有:ConsoleAppender(输出到控制台)、FileAppender(输出到文件)、SMTPAppender(输出到邮件)、DBAppender(输出到数据库)、AsyncAppender(异步输出,包装其它具体的appender,不单独使用)等,如下介绍常用的

  • ConsoleAppender:日志输出到控制台,类名:ch.qos.logback.core.ConsoleAppender
  • FileAppender:日志输入到文件,类名:ch.qos.logback.core.FileAppender
  • RollingFileAppender:滚动记录文件(FileAppender的子类)当符合条件(大小、时间)日志进行切分处理。类名:ch.qos.logback.core.rolling.RollingFileAppender
  • 实战中ConsoleAppender及RollingFileAppender使用较多,若需要自定义如把日志输出到消息队列,可以自定义实现AppenderBase接口

除了上述Appender外,另外还有SocketAppender(输出到socket)、SMTPAppender(输出到邮件)、DBAppender(输出到数据库)等具体使用查文档

ConsoleAppender

ConsoleAppender 就跟名字显示的一样,是将日志事件附加到控制台,进一步说就是通过 System.out(默认) 或 System.err 来进行输出。ConsoleAppender 通过用户指定的 encoder,格式化日志事件。

属性名 类型 描述
target String System.out 或 System.err。默认为 System.out
encoder Encoder 决定通过哪种方式将事件写入 OutputStreamAppender
withJansi boolean 默认值为 false。设为 true 可以激活 Jansi 在 windows 使用 ANSI 彩色代码。
在 windows 上如果设置为 true,你应该将 org.fusesource.jansi:jansi:1.9 这个 jar 包放到 classpath 下。
基于 Unix 实现的操作系统,像 Linux、Max OS X 都默认支持 ANSI 才彩色代码。
<configuration>
    
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        
        <target>System.outtarget>
        
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d [%t] [%-5level] %c %M %L %m %npattern>
            
            <charset>UTF-8charset>
        encoder>
    appender>
    
    <root level="INFO">
        
        <appender-ref ref="consoleAppender"/>
    root>
configuration>
FileAppender

FileAppender是OutputStreamAppender的子类,将日志事件输出到文件中。通过file来指定目标文件。如果该文件存在,根据append的值,要么将日志追加到文件中,要么该文件被截断。

属性名 类型 描述
file String 要写入文件的名称。如果文件不存在,则新建
encoder Encoder 参见 ConsoleAppender 的属性
append boolean 如果为 true,日志事件会被追加到文件中,否则的话,清空现存文件。默认为 true
prudent boolean 在严格模式下,FileAppender会将日志安全的写入指定文件。即使在不同的 JVM 或者不同的主机上运行 FileAppender 实例。默认值为 false。严格模式可以与 RollingFileAppender 结合使用

1、将日志输出到文件:FileAppender。包含file(文件名)、encoder(格式化)元素

<configuration>
    
    <property name="pattern" value="%d [%t] [%-5level] %c %M %L %m %n">property>
    <property name="log_file" value="./logs">property>
    
    <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss" />

    
    <appender name="fileAppender" class="ch.qos.logback.core.FileAppender">
        
        <file>${log_file}/logback-${bySecond}.logfile>
        
        <immediateFlush>trueimmediateFlush>
        
        <encoder>
            <pattern>${pattern}pattern>
        encoder>
    appender>
    
    <root level="INFO">
        <appender-ref ref="fileAppender"/>
    root>
configuration>

2、输出到html格式的日志文件:appender设置为FileAppender,encoder设置为LayoutWrappingEncoder,layout设置为LayoutWrappingEncoder

<configuration>
    
    <property name="html_pattern" value="%d{yyyy-MM-dd HH:mm:ss}%t%-5level%c%M%L%m%n">property>
    <property name="log_file" value="./logs">property>

    
    <appender name="htmlFileAppender" class="ch.qos.logback.core.FileAppender">
        
        <file>${log_file}/logback.htmlfile>
        
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                <pattern>${html_pattern}pattern>
            layout>
        encoder>
    appender>

    <root level="INFO">
        <appender-ref ref="htmlFileAppender"/>
    root>
configuration>

注意:我们只能设置打印的日志信息内容,不能设置这个网页的打印格式以及样式。但是,当我们打印出logback.html文件后,我们可以人为的修改其中的样式以及格式这个html中包含 HTML+CSS。在实际的开发中,如果日志文件不是很大,我们可以考虑使用html进行日志打印,因为可读性强。

RollingFileAppender

RollingFileAppender是FileAppender的子类,扩展了FileAppender,具有翻转日志文件的功能。当满足某个特定的条件之后,将日志输出到另外一个文件。

属性名 类型 描述
file String 被写入文件名,可以是相对目录或绝对目录,如果上级目录不存在会自动创建,无默认值
rollingPolicy RollingPolicy 当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
triggeringPolicy TriggeringPolicy 告知 RollingFileAppender 合适激活滚动
encoder Encoder 参见 ConsoleAppender 的属性
append boolean 如果为 true,日志事件会被追加到文件中,否则的话,清空现存文件。默认为 true
prudent boolean 当为true时,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy,但是有两个限制,
1.不支持也不允许文件压缩,2.不能设置file属性,必须留空
1、RollingPolicy滚动策略

RollingPolicy用于配置滚动策略,支持TimeBasedRollingPolicy(基于时间滚动)、SizeAndTimeBasedRollingPolicy(基于大小和时间滚动)、FixedWindowRollingPolicy(固定窗口滚动和大小触发)、其中FixedWindowRollingPolicy和SizeBasedTriggeringPolicy一般同时使用

RollingPolicy滚动策略包括以下几种:

  • TimeBasedRollingPolicy:基于时间的滚动策略
  • SizeAndTimeBasedRollingPolicy:基于文件大小和时间的滚动策略
  • FixedWindowRollingPolicy:基于固定窗口大小的滚动策略,就是将归档日志文件到最大了就写到下一个文件里,而窗口大小就是最多允许日志文件数
  • SizeBasedTriggeringPolicy:FixedWindowRollingPolicy和SizeBasedTriggeringPolicy一般同时使用,用于触发FixedWindowRollingPolicy
2、TimeBasedRollingPolicy

TimeBasedRollingPolicy:它是基于时间来定义轮转策(最常用的轮转策略)例如按天或月。TimeBasedRollingPolicy 既负责轮转的行为,也负责触发轮转。实际上:TimeBasedRollingPolicy 同时实现了 RollingPolicy 与 TriggeringPolicy 接口。

TimeBasedRollingPolicy 的配置需要一个强制的属性 fileNamePattern 以及其它的可选属性:

属性名 类型 描述
fileNamePattern String 该属性的值应该由文件名加上一个 %d的占位符。%d 应包含 java.text.SimpleDateFormat 中规定的日期格式。如果省略日期格式,那么就默认为 yyyy-MM-dd。如果 fileNamePattern 以 .gz 或者 .zip 结尾,将会启动这个压缩特性
maxHistory int 这个可选的属性用来控制最多保留多少数量的归档文件,将会异步删除旧的文件。如单位按月轮转时maxHistory = 6,只会保留6个月的日志。单位根据时间格式维度来区分:按天(yyyy-MM-dd) 按月(yyyy-MM)
totalSizeCap int 在有 maxHistory 的限制下,进一步限制所有日志文件大小之和的上限,超过则从最旧的日志开始删除
cleanHistoryOnStart boolean 如果设置为 true,那么在 appender 启动的时候,归档文件将会被删除。默认的值为 false。归档文件的删除通常在轮转期间执行。但是,有些应用的存活时间可能等不到轮转触发。对于这种短期应用,可以通过设置该属性为 true,在 appender 启动的时候执行删除操作
<configuration>
    
    <appender name="rollingFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/logback.logfile>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <fileNamePattern>logs/logback_%d{yyyy-MM-dd_HH-mm-ss}.logfileNamePattern>
            
            <maxHistory>60maxHistory>
            
            <totalSizeCap>10MBtotalSizeCap>
            
            <cleanHistoryOnStart>truecleanHistoryOnStart>
        rollingPolicy>
        
        <encoder>
            <pattern>%date %-5level -[%thread] %class.%method/%line : %msg%npattern>
        encoder>
    appender>
    <root level="INFO">
        <appender-ref ref="rollingFileAppender"/>
    root>
configuration>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Timer;
import java.util.TimerTask;

public class LogbackTest {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(LogbackTest.class);
        // 1秒后启动,每秒跑1次
        new Timer().scheduleAtFixedRate(new TimerTask(){
            @Override
            public void run() {
                logger.error("error test");
                logger.warn("warn test");
                logger.info("info {}", "test");
                logger.debug("debug test ");
                logger.trace("trace test");
            }
        }, 1000, 1000);
    }
}

执行后可以发现1分钟后生成了61个文件。1个logback.log,60个logback_2022-04-03_12-12-xx.log。这是因为每秒生产一个文件,而maxHistory设置了保留最近一分钟的日志(并且每个日志文件都比较小,60个加起来也没超过totalSizeCap总日志大小的上限)。此时还可以发生另外一种情况,就是把totalSizeCap总文件大小设置比较小,才生成几个文件就达到totalSizeCap总日志大小的上限。

3、SizeAndTimeBasedRollingPolicy

SizeAndTimeBasedRollingPolicy:基于时间+大小进行滚动(既能按时轮转,又能限制每个日志文件的大小)是对于第一种的补充。避免单个日志文件过大。实际查看源码也可以看出SizeAndTimeBasedRollingPolicy继承了TimeBasedRollingPolicy,并增加了一个maxFileSize属性。

属性名 类型 描述
fileNamePattern String 该属性的值应该由文件名加上一个 %d的占位符。%d 应包含 java.text.SimpleDateFormat 中规定的日期格式。如果省略日期格式,那么就默认为 yyyy-MM-dd。并且需要包含一个 i% 的占位符,当文件大小超过maxFileSize大小时,则用下标新建文件。如果 fileNamePattern 以 .gz 或者 .zip 结尾,将会启动这个压缩特性
maxFileSize int 按照文件大小进行拆分,当文件大小达到1MB时就会将日志进行压缩
maxHistory int 这个可选的属性用来控制最多保留多少数量的归档文件,将会异步删除旧的文件。如单位按月轮转时maxHistory = 6,只会保留6个月的日志。单位根据时间格式维度来区分:按天(yyyy-MM-dd) 按月(yyyy-MM)
totalSizeCap int 在有 maxHistory 的限制下,进一步限制所有日志文件大小之和的上限,超过则从最旧的日志开始删除
cleanHistoryOnStart boolean 如果设置为 true,那么在 appender 启动的时候,归档文件将会被删除。默认的值为 false。归档文件的删除通常在轮转期间执行。但是,有些应用的存活时间可能等不到轮转触发。对于这种短期应用,可以通过设置该属性为 true,在 appender 启动的时候执行删除操作
<configuration>
    
    <appender name="rollingFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>logs/logback.logfile>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            
            
            <fileNamePattern>logs/logback_%d{yyyy-MM-dd_HH-mm-ss}_%i.log.zipfileNamePattern>
            
            
            <maxFileSize>1MBmaxFileSize>
            
            <maxHistory>60maxHistory>
            
            <totalSizeCap>200MBtotalSizeCap>
            
            <cleanHistoryOnStart>truecleanHistoryOnStart>
        rollingPolicy>
        
        <encoder>
            <pattern>%date %-5level -[%thread] %class.%method/%line : %msg%npattern>
        encoder>
    appender>
    
    <root level="INFO">
        <appender-ref ref="rollingFileAppender"/>
    root>
configuration>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Timer;
import java.util.TimerTask;

public class LogbackTest {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(LogbackTest.class);
        // 1秒后启动,每秒跑1次
        new Timer().scheduleAtFixedRate(new TimerTask(){
            @Override
            public void run() {
                logger.error("error test");
                logger.warn("warn test");
                logger.info("info {}", "test");
                logger.debug("debug test ");
                logger.trace("trace test");
            }
        }, 1000, 1000);
    }
}

执行后可以发现会生成文件logback.log与文件logback_2022-04-03_17-42-xx_0.log.zip若干个。若在同一个时间段内生成的单个文件超过了maxFileSize后,%i就会生效(默认是从0开始)

4、FixedWindowRollingPolicy

可以理解成自定义滚动规则,避免使用出现单个文件过大或者日志文件过多的情况。需要同时配置triggeringPolicy用于指定滚动触发规则。对以上的补充。

FixedWindowRollingPolicy 根据固定窗口算法重命名文件,filaNamePattern 表示归档文件的名字。这个属性是必选,并必须包含一个表示整形的占位符 i%

属性名 类型 描述
fileNamePattern String FixedWindowRollingPolicy 在重命名日志文件时将会根据这个属性来命名。它必须包含一个 i% 的占位符,该占位符指明了窗口索引的值应该插入的位置。 例如,当该属性的值为 MyLogFile%i.log,最小与最大的值分别为 13。将会产生的归档文件为 MyLogFile1.logMyLogFile2.logMyLogFile3.log。 文件压缩的方式也是通过该属性来指定。例如,设置该属性的值为 MyLogFile%i.log.zip,那么归档文件将会被压缩成 zip 格式。也可以选择压缩成 gz 格式。
minIndex int 表示窗口索引的下界
maxIndex int 表示窗口索引的上界
<configuration>
    <appender name="rollingFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>logs/logback.logfile>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>logs/logback_%i.log.zipfileNamePattern>
            <minIndex>1minIndex>
            <maxIndex>5maxIndex>
        rollingPolicy>
        
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>10KBmaxFileSize>
        triggeringPolicy>
        <encoder>
            <pattern>%date %-4relative [%thread] %-5level %logger{35} - %msg%npattern>
        encoder>
    appender>
    <root level="INFO">
        <appender-ref ref="rollingFileAppender" />
    root>
configuration>

TriggeringPolicy 用于通知何时触发滚动。实现类:SizeBasedTriggeringPolicy

  • SizeBasedTriggeringPolicy:观察当前活动文件的大小,如果大于了指定的值,它会给RollingFileAppender发一个信号触发对当前活动文件的轮转
  • SizeBasedTriggeringPolicy:只接收 maxFileSize 这一个参数,它的默认值是 10MB
  • maxFileSize:可以为字节 / 千字节 /兆字节 /千兆字节,数值 加 KB,MB 或 GB。例:5000000,5000KB,5MB(这3个大小一样) 及 2GB
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Timer;
import java.util.TimerTask;

public class LogbackTest {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(LogbackTest.class);
        // 1秒后启动,每秒跑1次
        new Timer().scheduleAtFixedRate(new TimerTask(){
            @Override
            public void run() {
                logger.error("error test");
                logger.warn("warn test");
                logger.info("info {}", "test");
                logger.debug("debug test ");
                logger.trace("trace test");
            }
        }, 1000, 1000);
    }
}

执行代码可以发现:最后生成文件:logback.log、logback_1.log.zip - logback_5.log.zip(zip解压后可以发现文件名:logback_2022-04-03_1754,具体可以参考源码:FixedWindowRollingPolicy)如果fileNamePattern中没有设置以.zip结尾的话,默认名称就是设定名称+Index

5、轮转周期示例 fileNamePattern

适用上面的 SizeAndTimeBasedRollingPolicy 和 TimeBasedRollingPolicy 滚动策略

fileNamePattern 格式 说明
app_%d.log 每天轮转。不指定%d日期格式时默认为 yyyy-MM-dd
app_%d{yyyy-MM}.log 每个月开始的时候轮转
app._%d{yyyy-ww}.log 每周的第一天(取决于时区)
app_%d{yyyy-MM-dd_HH}.log 每小时轮转。如:app_2020-10-24_10.log
app_%d{yyyy-MM-dd_HH-mm}.log 每分钟轮转;。如:app_2020-10-24_10-32.log
app_%d{yyyy-MM-dd_HH-mm, UTC}.log 每分钟轮转(时间格式是 UTC)
app/%d{yyyy-MM}/%d.log 每天轮转。第一个%d被辅助标记。第二个%d为主要标记。如:app/2020-10/2020-10-24.log

重点注意:fileNamePattern中设置的时间格式生产文件名不能使用空格已经冒号等特殊符号(不然不会生产新的滚动文件)

AsyncAppender 异步

上面的Appender日志输出到文件是同步输出的,即每次输出都会直接写IO到磁盘文件。对于高并发,会产生一定的阻塞,造成不必要的性能损耗。Logback提供了日志异步输出的AsyncAppender。处理方式较简单,添加一个基于异步写日志的appender,并指向原配置的appender即可。AsyncAppender 参数说明:

参数 默认值 说明
discardingThreshold 20 如果设置discardingThreshold=0,表示 queue 满了,不丢弃,block 线程。默认情况下,当阻塞队列剩余 20% 的容量时,它将丢弃级别跟踪、调试和信息事件,只保留级别警告和错误事件。要保留所有事件,请将 discardingThreshold 设置为0
queueSize 256 假设 IO 影响 30s,日志和 qps 比例是1:1,单容器压测值 1500 qps 则可以推算出 queueSize 的值,queueSize 的设置公式:30 * 1500=45000
neverBlock false 如果为 false(默认值),则追加程序将阻止追加到完整队列,而不是丢失消息。设置为 true 时,附加程序只会丢弃消息,不会阻止您的应用程序
includeCallerData false 提取呼叫者数据可能相当昂贵。 为了提高性能,默认情况下,当事件添加到事件队列时,不会提取与事件关联的调用者数据。 默认情况下,仅复制线程名称和 MDC 等“廉价”数据。 您可以通过将 includeCallerData 属性设置为 true 来指示此附加程序包含调用方数据。
<configuration>
    
    <appender name="fileAppender" class="ch.qos.logback.core.FileAppender">
        <file>logs/logback.logfile>
        
        <immediateFlush>falseimmediateFlush>
        <encoder>
            <pattern>${pattern}pattern>
        encoder>
    appender>
    
    
    <appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender">
        
        <discardingThreshold>0discardingThreshold>
        
        <queueSize>1024queueSize>
        
        <neverBlock>trueneverBlock>
        
        <includeCallerData>trueincludeCallerData>
        
        <appender-ref ref="fileAppender"/>
    appender>
    
    
    <root level="INFO">
        <appender-ref ref="asyncAppender" />
    root>
configuration>

这里有个需要注意的地方,那就是 AsyncAppender 必须在其引用的 Appender 配置的后面,否则会使配置不生效。

SMTPAppender 邮件

使用SpringBoot + Logback 配置程序异常自动发送邮件:https://mp.weixin.qq.com/s/N4OrKlrtCDeEd95XWGi9YA

现在想更要发生异常自动发送邮件的功能,需要使用到 SMTPAppender 输出日志到邮件组件

1、加入依赖(JavaMail)

<dependency>
    <groupId>javax.mailgroupId>
    <artifactId>mailartifactId>
    <version>1.4.7version>
dependency>

2、修改logback的xml的配置文件

<configuration debug="true">
    
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d [%t] [%-5level] %c %M %L %m %npattern>
        encoder>
    appender>

    
    <property name="smtpHost" value="smtp.qq.com"/>
    
    <property name="smtpPort" value="587"/>
    <property name="mailFrom" value="[email protected]"/>
    <property name="username" value="[email protected]"/>
    <property name="mailTo" value="[email protected],[email protected]"/>
    <property name="password" value="fxomimpmgpjgbhxx"/>
    <property name="SSL" value="false"/>
    <property name="mailSubject" value="Exception information reminder"/>
    <appender name="mailAppender" class="ch.qos.logback.classic.net.SMTPAppender">
        <smtpHost>${smtpHost}smtpHost>
        <smtpPort>${smtpPort}smtpPort>
        <username>${username}username>
        <password>${password}password>
        <SSL>${SSL}SSL>
        <asynchronousSending>falseasynchronousSending>
        <to>${mailTo}to>
        <from>${mailFrom}from>
        <subject>${mailSubject}subject>
        <layout class="ch.qos.logback.classic.html.HTMLLayout">
            
            <Pattern>%date%level%thread%logger{0}%line%messagePattern>
        layout>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERRORlevel>
        filter>
    appender>

    <root level="INFO">
        <appender-ref ref="consoleAppender"/>
        <appender-ref ref="mailAppender"/>
    root>
configuration>

3、测试代码,输出ERROR级别日志,会自动发送到邮件中

package com.xyz;

import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;

public class LogbackTest {
    public static void main(String[] args) {
        Logger logger = (Logger)LoggerFactory.getLogger(LogbackTest.class);

        String s = null;
        try {
            s.equals("");
        } catch (Exception e) {
            logger.error("error message: {}",e);
        }
    }
}

4、邮件中收到内容如下:

Date Level Thread Logger LineOfCaller Message
2022-04-06 11:37:18,549 ERROR main LogbackTest 14 error message: {}
java.lang.NullPointerException: null
at com.xyz.LogbackTest.main(LogbackTest.java:14)
Logback + ELK 配置

GitHub地址:https://github.com/logfellow/logstash-logback-encoder/blob/main/README.md

如果项目中的日志采用的是基于ELK(Elasticsearch、Logstash、Kibana)来进行日志管理。则可以在pom文件中引入logstash-logback-encoder依赖


<dependency>
    <groupId>net.logstash.logbackgroupId>
    <artifactId>logstash-logback-encoderartifactId>
    <version>5.1version>
dependency>

然后在logback-spring.xml中配置对应的appender:


<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
    
    <destination>192.168.0.11:5061destination>
    <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
        <customFields>{"project": "springboot-logback-elk"}customFields>
    encoder>
appender>

该appender的使用与其他appender的使用无异。主要使用了LogstashTcpSocketAppender类来完成与Logstash的通信。其中destination为Logstash提供的服务地址。customFields为自定义的参数,便于Logstash识别日志是从哪个业务系统传输过来的。

如下是参考一个详细(完整的logback配置示例ELK整合包含生成json日志:https://www.zhangshengrong.com/p/OgN5Dvvxan/)

<appender name="logstash" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logs/logback.jsonfile>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>logs/logback-%d{yyyy-MM-dd}.jsonfileNamePattern>
        <maxHistory>7maxHistory>
    rollingPolicy>
    <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
        <providers>
            <timestamp>
                <timeZone>UTCtimeZone>
            timestamp>
            <pattern>
                <pattern>
                    {
                    "ip": "${ip}",
                    "app": "${appName}",
                    "level": "%level",
                    "trace": "%X{X-B3-TraceId:-}",
                    "span": "%X{X-B3-SpanId:-}",
                    "parent": "%X{X-B3-ParentSpanId:-}",
                    "thread": "%thread",
                    "class": "%logger{40}",
                    "message": "%message",
                    "stack_trace": "%exception{10}"
                    }
                pattern>
            pattern>
        providers>
    encoder>
appender>

07、encoder & pattern元素

官网地址:

  • https://logback.qos.ch/manual/encoders.html
  • https://logback.qos.ch/manual/layouts.html
  • https://logback.qos.ch/manual/layouts.html#conversionWord

encoder和layout一样,用来格式化输出。encoder是在logback 0.9.19 版本之后引入的。在这个版本之前,大部分的appender使用layout来格式化输出,但之后FileAppender和他的子类推荐使用encoder来代替layout。常用的是PatternLayoutEncoder(这是默认的encoder)所以我们不用指定,直接使用encoder标签就行。PatternLayoutEncoder的组成和layout一样。如下:

Pattern表达式

Conversation Word Effect
d{pattern}、date{pattern} 日志打印的时间,语法与java.text.SimpleDateFormat兼容。Conversion Pattern Result
%d 2006-10-20 14:06:49,812
%date 2006-10-20 14:06:49,812
%date{ISO8601} 2006-10-20 14:06:49,812
%date{HH:mm:ss.SSS} 14:06:49.812
%date{dd MMM yyyy ;HH:mm:ss.SSS} 20 oct. 2006;14:06:49.812
%d{dd MMM yyyy ;HH:mm:ss.SSS,Australia/Perth} 05 4月 2022 ;11:34:13.168
Conversation Word Effect
变量名 %date 时间打印详情请参考上方
%date{pattern, timezone}、%d 日志打印的时间。pattern与java.text.SimpleDateFormat兼容
pattern不填写默认值是:yyyy-MM-dd hh:mm:ss,SSS。
第二个参数是时区,例如:%date{HH:mm:ss.SSS, Australia/Perth}
%logger、%lo、%c{length} 输出当前日志名称。没有length则输出全名。如:com.xyz.LogbackTest
%class、%C{length} 输出日志调用所在类,没有length则打印全类名。如:com.xyz.LogbackTest(与%c一样)
%method、%M 输出日志所在方法(没有length参数)如:main
%caller{length} 日志调用位置,length代表日志深度,如:Caller+0 at com.xyz.LogbackTest.main(LogbackTest.java:9)
%thread、%t 输出线程名(没有length参数)
%level、%le、%p 输出日志级别(没有length参数)
%message、%msg、%m 输出日志记录内容,就是调用logger的方法的时候传入的log字符串
%exception、%ex 输出异常信息。如:logger.error("error...",new Exception("exception"));
%line、%L 输出日志的行数。如:9
%file、%F 输出调用logger的java源码文件名,速度不快,避免使用。如:LogbackTest.java
%n 换行符
% 输出%号
特殊占位符
%X{user} 表示可以获取外部自定义传入的值, 如:%X{user}=》org.slf4j.MDC.put("user", "xx-yy-zz");
宽度设置 可以限制上面的ConversationWord的宽度和左右对齐
%20logger 最小宽度20,当小于20时,则左侧留空白。右对齐
%-20logger 最小宽度20,当小于20时,则右侧留空白。左对齐
%.30logger 最大宽度30,超出时从头部开始截断。如:%.2、test=》st
%.-30logger 最大宽度30,超出时从末尾开始截断。如:%.-2、test=》te
%20.30logger 最小20,最大30,小于20的时候右对齐,大于30的时候开始处截断
%-20.30logger 最小20,最大30,小于20的时候左对齐,大于30的时候开始处截断
显示设置
%highlight() 突出显示,如:%highlight(%-5level)
%green(%red、%blue、%white) 字体显示为指定颜色
{length} 可指定长度,如:%logger{36}
网络访问设置 需要依赖logger-access模块
%remoteIP、%a 远程IP
%localIP、%A 本地IP
%clientHost、%h 远程主机名
%localPort 本地端口
%requestMethod、%m http请求方法
%protocol、%H http请求协议
%statusCode、%s http请求status code
%requestURL、%r http请求地址
%requestURI、%U http请求资源地址
%queryString、%q http请求参数
%server、%v 服务器地址
%elapsedTime、%D http请求处理的时间,单位是毫秒
%elapsedSeconds、%T http请求处理的时间,单位是秒
%date、%t 日志记录时间
%threadName、%I 处理请求的线程名
%reqAttribute{attributeName} http请求attribute值
%reqCookie{cookie} http请求cookie值
%reqContent http请求体内容
%fullRequest http完整请求
%responseContent http响应
%fullResponse http完整响应

格式化修饰器:可以限制上面的ConversationWord的宽度和左右对齐。比如:

  • 左对齐修饰符(-):接着是可选的最小宽度修饰符,用十进制数表示。如果字符小于最小宽度,则左填充或右填充,默认是左填充(即右对齐),填充符为空格。如果字符大于最小宽度,字符永远不会被截断
  • 最大宽度修饰符(.):后面加十进制数。如果字符大于最大宽度,则从前面截断。后面加减号“-”在加数字,表示从尾部截断

1、用来指定日志的输出格式及编码等其他配置(encoder元素)

<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        
        <pattern>%d %lo %C %M %le %t %le %lo : %m%npattern>
        
        <pattern>%date %logger %class %method %highlight(%level) %thread : %msg%npattern>
        
        <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%npattern>
        
        <charset class="java.nio.charset.Charset">UTF-8charset>
        
        <immediateFlush>falseimmediateFlush>
    encoder>
appender>

2、使用特殊占位符%X{}示例:

<configuration debug="false">
    
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d [%X{uuid}] [%X{x}] [%t] [%-5level] %c %M %L %m %npattern>
        encoder>
    appender>
    <root level="INFO">
        <appender-ref ref="consoleAppender"/>
    root>
configuration>
package com.xyz;
import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;
import java.util.UUID;

public class LogbackTest {
    public static void main(String[] args) {
        Logger logger = (Logger)LoggerFactory.getLogger(LogbackTest.class);
        org.slf4j.MDC.put("uuid", UUID.randomUUID().toString());
        logger.info("info {}", "test");
    }
}
2022-04-06 18:46:33,795 [4effd2ef-a4de-4a6c-82c1-c1d522e9aa76] [] [main] [INFO ] com.xyz.LogbackTest main 10 info test 

08、filters 过滤器元素

官网地址:https://logback.qos.ch/manual/filters.html

Filter是日志过滤器,是appender里面的子元素。执行一个过滤器会有返回DENY、NEUTRAL、ACCEPT三个枚举值中的一个。appender 有多个过滤器时,按照配置顺序执行。

  • DENY:日志将立即被抛弃不再经过其他过滤器
  • NEUTRAL:有序列表里的下个过滤器过接着处理日志
  • ACCEPT:日志会被立即处理,不再经过剩余过滤器
1、LevelFilter

LevelFilter 基于级别来过滤日志事件。如果事件的级别与配置的级别相等,过滤器会根据配置的 onMatch 与 onMismatch 属性,接受或者拒绝事件

<configuration>
    
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            
            <level>INFOlevel>
            
            <onMatch>ACCEPTonMatch>
            
            <onMismatch>DENYonMismatch>
        filter>
        <encoder>
            <pattern>%date %-4relative [%thread] %-5level %logger{35} - %msg%npattern>
        encoder>
    appender>
    <root level="INFO">
        <appender-ref ref="consoleAppender" />
    root>
configuration>
2、ThresholdFilter

ThresholdFilter 基于给定的临界值来过滤事件。如果事件的级别等于或高于给定的临界值,当调用 decide() 时,ThresholdFilter 将会返回 NEUTRAL。但是事件的级别低于临界值将会被拒绝。简单来说:针对指定级别及以上级别进行日志过滤

<configuration>
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        
        
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFOlevel>
        filter>
        <encoder>
            <pattern>%date %-4relative [%thread] %-5level %logger{35} - %msg%npattern>
        encoder>
    appender>
    <root level="INFO">
        <appender-ref ref="consoleAppender" />
    root>
configuration>
3、EvaluatorFilter

EvaluatorFilter: 求值过滤器,评估、鉴别日志是否符合指定条件。有一下子节点:

  • :鉴别器,常用的鉴别器是JaninoEventEvaluato,也是默认的鉴别器,它以任意的java布尔值表达式作为求值条件,求值条件在配置文件解释过成功被动态编译,布尔值表达式返回true就表示符合过滤条件。evaluator有个子标签,用于配置求值条件
  • :用于配置符合过滤条件的操作
  • :用于配置不符合过滤条件的操作

求值表达式作用于当前日志,logback向求值表达式暴露日志的各种字段(evaluator标签中可以用的对象和值):

Name Type Description
event LoggingEvent 与记录请求相关联的原始记录事件,下面所有变量都来自event,例如,event.getMessage()返回下面"message"相同的字符串
message String 日志的原始消息,例如,设有logger mylogger,“name"的值是"AUB”,对于 mylogger.info(“Hello {}”,name); "Hello {}"就是原始消息。
formattedMessage String 日志被各式话的消息,例如,设有logger mylogger,“name"的值是"AUB”,对于 mylogger.info(“Hello {}”,name); "Hello Aub"就是格式化后的消息。
logger String logger 名。
loggerContext LoggerContextVO 日志所属的logger上下文。
level int 级别对应的整数值,所以 level > INFO 是正确的表达式。
timeStamp long 创建日志的时间戳。
marker Marker 与日志请求相关联的Marker对象,注意“Marker”有可能为null,所以你要确保它不能是null。
mdc Map 包含创建日志期间的MDC所有值得map。访问方法是:mdc.get(“myKey”) 。mdc.get()返回的是Object不是String,要想调用String的方法就要强转,例如,((String) mdc.get(“k”)).contains(“val”) .MDC可能为null,调用时注意。
throwable java.lang.Throwable 如果没有异常与日志关联"throwable" 变量为 null. 不幸的是, “throwable” 不能被序列化。在远程系统上永远为null,对于与位置无关的表达式请使用下面的变量throwableProxy
throwableProxy IThrowableProxy 与日志事件关联的异常代理。如果没有异常与日志事件关联,则变量"throwableProxy" 为 null. 当异常被关联到日志事件时,“throwableProxy” 在远程系统上不会为null

过滤器还可以来自自带的或表达式直接写在配置文件中。


<dependency>
    <groupId>org.codehaus.janinogroupId>
    <artifactId>janinoartifactId>
    <version>3.1.6version>
dependency>
<configuration>
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        
        <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
            <evaluator>
                
                <expression>
                    // 根据日志消息判断
                    if(event.getMessage().contains("url")){
                    return true;
                    }
                    if(formattedMessage.contains("url")){
                    return true;
                    }
                    return false;
                expression>
            evaluator>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
        <encoder>
            <pattern>%date %-4relative [%thread] %-5level %logger{35} - %msg%npattern>
        encoder>
    appender>
    <root level="ALL">
        <appender-ref ref="consoleAppender"/>
    root>
configuration>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Timer;
import java.util.TimerTask;

public class LogbackTest {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(LogbackTest.class);
        // 1秒后启动,每秒跑一次
        new Timer().scheduleAtFixedRate(new TimerTask(){
            @Override
            public void run() {
                logger.error("error test");
                logger.warn("warn test");
                logger.info("info {}", "url");
                logger.debug("debug test ");
                logger.trace("trace url");
            }
        }, 1000, 1000);
    }
}
2022-04-03 22:46:31,251 1421 [Timer-0] INFO  LogbackTest - info url
2022-04-03 22:46:31,251 1421 [Timer-0] TRACE LogbackTest - trace url
2022-04-03 22:46:32,254 2424 [Timer-0] INFO  LogbackTest - info url
2022-04-03 22:46:32,254 2424 [Timer-0] TRACE LogbackTest - trace url

EvaluatorFilter 中还有一个特殊的标签,基本很少用,了解即可。

  • :匹配器,尽管可以使用String类的matches()方法进行模式匹配,但会导致每次调用过滤器时都会创建一个新的Pattern对象,为了消除这种开销,可以预定义一个或多个matcher对象,定以后就可以在求值表达式中重复引用。的子标签。
  • 中包含两个子标签,一个,用于定义matcher的名字,求值表达式中使用这个名字来引用matcher;另一个,用于配置匹配条件
<configuration debug="true">   
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">   
        <filter class="ch.qos.logback.core.filter.EvaluatorFilter">   
            <evaluator>           
                <matcher>   
                    <Name>oddName>   
                       
                    <regex>statement [13579]regex>   
                matcher>   

                <expression>odd.matches(formattedMessage)expression>   
            evaluator>   
            <OnMismatch>NEUTRALOnMismatch>   
            <OnMatch>DENYOnMatch>   
        filter>   
        <encoder>   
            <pattern>%-4relative [%thread] %-5level %logger - %msg%npattern>   
        encoder>   
    appender>   

    <root level="DEBUG">   
        <appender-ref ref="STDOUT" />   
    root>   
configuration>  
4、自定义过滤器

通过实现ch.qos.logback.core.filter.Filter接口可以自定义过滤器,自定义过滤器类LogbackUrlFilter.class,示例如下:

package com.xyz;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class LogbackUrlFilter extends Filter<ILoggingEvent> {
    @Override
    public FilterReply decide(ILoggingEvent event) {
        if(event.getMessage().contains("url")){
            return FilterReply.ACCEPT;
        }
        if(event.getFormattedMessage().contains("url")){
            return FilterReply.ACCEPT;
        }
        return FilterReply.DENY;
    }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Timer;
import java.util.TimerTask;

public class LogbackTest {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(LogbackTest.class);
        // 1秒后启动,每秒跑一次
        new Timer().scheduleAtFixedRate(new TimerTask(){
            @Override
            public void run() {
                logger.error("error test");
                logger.warn("warn test");
                logger.info("info {}", "url");
                logger.debug("debug test ");
                logger.trace("trace url");
            }
        }, 1000, 1000);
    }
}
2022-04-03 22:46:31,251 1421 [Timer-0] INFO  LogbackTest - info url
2022-04-03 22:46:31,251 1421 [Timer-0] TRACE LogbackTest - trace url
2022-04-03 22:46:32,254 2424 [Timer-0] INFO  LogbackTest - info url
2022-04-03 22:46:32,254 2424 [Timer-0] TRACE LogbackTest - trace url

通常情况下,日志输出会配置三个,一个控制台输出用于开发阶段;一个INFO及以上级别的日志输出,可追踪相应的生产日志;一个单独ERROR级别的日志输出,方便快速检查出异常日志。都可以通过Appender和Filter来控制。

09、logger 元素

logger用来设置某一个类或者某个包的日志输出级别、以及关联的appender,这样就可以控制非业务日志不写到对应的文件日志中。

logger标签中包含三个属性:

  • name:要输出日志的包名或者类名,比如com.xyz。必选项

  • level:设置日志的级别(不区分大小写:TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF)如果未设置,则logger会向上继承最近一个非空级别。可选项

  • additivity:是否将日志向上级传递,默认为 true。可选项

logger通过1个或多个子节点appender-ref来控制日志的输出:


<logger name="org.springframework" level="WARN"/>


<logger name="com" level="debug" />




<logger name="com.xyz" level="info" additivity="true">
    <appender-ref ref="consoleAppender" />
logger>

10、root 元素

root元素配置根记录器。它是个特殊的logger,是所有logger的根节点,只能指定日志级别及level(默认DEBUG)和appender-ref(输出的appender)


<root level="info">
    
    <appender-ref ref="consoleAppender"/>
    <appender-ref ref="fileAppender"/>
root>

<root level="ALL">
    <appender-ref ref="fileAppender"/>
root>

<root level="info">
    <appender-ref ref="consoleAppender"/>
root>

level属性的值可以是不区分大小写的字符串TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF之一。root元素可以包含零个或多个appender-ref元素;被引用的每个appender都被添加到根记录器中。

root元素和logger元素的区别?

root是根logger,是一种logger,root和根logger其实是一回事;只不过root中不能有 name 和 additivity 这两个属性

11、include 包含元素

文件包含元素:将配置文件的一部分包含在另一个文件中,可以通过标签include来引入另一个配置文件。如下所示:

<configuration>
    <include file="src/main/java/resources/includedConfig.xml"/>
    <root level="DEBUG">
        <appender-ref ref="includedConsole" />
    root>
configuration>

includedConfig.xml文件定义了被引用的内容:

<included>
    <appender name="includedConsole" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>"%d - %m%n"pattern>
        encoder>
    appender>
included>

include标签引入的文件可以为一个文件,一个类路径上的资源,或者一个URL。如下:

<include file="src/main/java/resources/includedConfig.xml"/>
<include resource="includedConfig.xml"/>
<include url="http://xxx.com/includedConfig.xml"/>

如果被引用的文件不存在,logback会打印内部的状态信息。如果包含的文件是可选的,可以通过optional属性设置为true来进制打印显示警告信息。

<include optional="true"/>

12、springProfile 元素

如果是基于SpringBoot项目,针对不同环境(profile)有不同的日志输出,比如开发(dev)环境只输出到控制台,生产环境(prod)只输入INFO和ERROR,那则可用到Spring支持的profile机制。对应的元素为springProfile。profile的值与springboot中配置文件的spring.profiles.active值进行对照。

<configuration>
    <springProfile name="dev">
        
        <logger name="com.example.demo.controller" level="DEBUG" additivity="false">
            <appender-ref ref="consoleLog"/>
        logger>
    springProfile>

    <springProfile name="dev | test">
        
        <logger name="com.example.demo.controller" level="INFO" additivity="false">
            <appender-ref ref="consoleLog"/>
        logger>
    springProfile>

    <springProfile name="!production">
        
        <logger name="com.example.demo.controller" level="INFO" additivity="false">
            <appender-ref ref="consoleLog"/>
        logger>
    springProfile>
configuration>

4、Logback其他操作

1、动态切换日志级别

Logback提供有代码方式直接修改日志级别,我们可以获取LoggerContext对象修改日志级别及其他配置。如下是Java代码实现(无配置文件)

package com.xyz;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;

public class LogbackTest {
    public static void main(String[] args) {
        Logger logger = (Logger)LoggerFactory.getLogger(LogbackTest.class);

        System.out.println("============使用默认的日志输出级别DEBUG==============");
        printLogs(logger);

        System.out.println("============动态设置日志输出级别为ERROR==============");
        // 返回正在使用的 ILoggerFactory 实例.
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        // 根据包路径或类路径获取日志记录器,"ROOT" 表示根记录器: Logger getLogger(final String name);
        loggerContext.getLogger(Logger.ROOT_LOGGER_NAME).setLevel(Level.toLevel("error"));
        printLogs(logger);

        System.out.println("============动态设置日志输出级别为WARN==============");
        loggerContext.getLogger("com.xyz").setLevel(Level.valueOf("warn"));
        printLogs(logger);
    }

    private static void printLogs(Logger logger) {
        logger.error("test error...");
        logger.warn("test warn...");
        logger.info("test info...");
        logger.debug("test debug...");
        logger.trace("test trace...");
    }
}
============使用默认的日志输出级别DEBUG==============
18:16:51.570 [main] ERROR com.xyz.LogbackTest - test error...
18:16:51.570 [main] WARN com.xyz.LogbackTest - test warn...
18:16:51.570 [main] INFO com.xyz.LogbackTest - test info...
18:16:51.570 [main] DEBUG com.xyz.LogbackTest - test debug...
============动态设置日志输出级别为ERROR==============
18:16:51.570 [main] ERROR com.xyz.LogbackTest - test error...
============动态设置日志输出级别为WARN==============
18:16:51.570 [main] ERROR com.xyz.LogbackTest - test error...
18:16:51.570 [main] WARN com.xyz.LogbackTest - test warn...

2、停止logback-classic

为了释放 logback-classic 资源,停止 logback context 是一个好主意。如果停止,会关闭所有 loggers 关联的 appenders,并有序的停止所有活动线程。

import org.sflf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;

// 返回正在使用的 ILoggerFactory 实例.
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
loggerContext.stop(); // stop logback-classic

3、模块logback-access

logback-access模块与Servlet容器(如Tomcat和Jetty)集成,以提供HTTP访问日志功能。我们可以使用logback-access模块来替换tomcat的访问日志

  1. 将logback-access.jar与logback-core.jar复制到$TOMCAT_HOME/lib/目录下(可以从本地的maven库直接copy)

    
    <dependency>
        <groupId>ch.qos.logbackgroupId>
        <artifactId>logback-coreartifactId>
        <version>1.2.3version>
    dependency>
    
    <dependency>
        <groupId>ch.qos.logbackgroupId>
        <artifactId>logback-accessartifactId>
        <version>1.2.3version>
    dependency>
    
  2. 修改$TOMCAT_HOME/conf/server.xml中的Host元素中添加:

    <Valve className="ch.qos.logback.access.tomcat.LogbackValve" />
    
  3. logback默认会在$TOMCAT_HOME/conf下查找文件:logback-access.xml

     
    <configuration> 
         
        <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/> 
        <property name="LOG_DIR" value="${catalina.base}/logs"/> 
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> 
            <file>${LOG_DIR}/access.logfile> 
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> 
                <fileNamePattern>access.%d{yyyy-MM-dd}.log.zipfileNamePattern> 
            rollingPolicy>
            <encoder> 
                 
                
                <pattern>combinedpattern> 
            encoder> appender> 
        <appender-ref ref="FILE"/> 
    configuration>
    
  4. 结果验证:启动tomcat,刷新页面,查看日志:logs/access.log

    127.0.0.1 - - [06/四月/2022:10:43:40 +0800] "GET / HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 Edg/99.0.1150.55"
    127.0.0.1 - - [06/四月/2022:10:43:40 +0800] "GET / HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 Edg/99.0.1150.55"
    
  5. 官方配置:https://logback.qos.ch/access.html#configuration

5、MDC分布式应用追踪请求

此方式可以用在任何日志实现框架中使用,如:Logback、log4j2 等

上面所讲的日志都是在单个应用系统下记录日志的。一旦进入分布式系统,很可能就会出现日志错乱,对日志追踪和排查造成难题。如果使用像ELK这类框架将日志进行归集统一处理,也需要一个标识,来记录日志的整个请求处理过程。

Slf4j提供了MDC(Mapped Diagnostic Contexts诊断上下文映射),可以让开发人员在诊断上下文中放置信息。通过ThreadLocal实现了线程与线程之间的数据隔离。在输出时可以通过标识符%X{key}来输出MDC中设置的内容。【此方式可以用在任何日志实现框架中使用,如:Logback、log4j2 …】

分布式应用追踪请求实现思路如下:

Web拦截器增加唯一ID »» 增加ID到MDC中 »» 调用其他服务时ID作为Header参数 »» 输出日志添加ID »» 请求结束,清除ID »» 根据相同ID排查日志

下面来看一下具体的实现代码。这里使用的是SpringBoot + Filter,也可以使用HandlerInterceptor拦截器(效果一样)

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.UUID;
import org.slf4j.MDC;

public class CorrelationIdLoggingFilter implements Filter {
    private static final String CORRELATION_ID = "correlation_id";
    private static final String UU_ID = "uu_id";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;

        String correlationId = req.getHeader(CORRELATION_ID);
        MDC.put(CORRELATION_ID, correlationId);
        String uuId = UUID.randomUUID().toString();
        MDC.put(UU_ID, uuId);

        chain.doFilter(request, response);
        MDC.remove(CORRELATION_ID);
        MDC.remove(UU_ID);
    }
}
@Configuration
public class FilterRegistration {
    @Bean
    public FilterRegistrationBean correlationIdLoggingFilterRegistrationBean() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CorrelationIdLoggingFilter()); // 可以new也可以Bean注入
        registration.setName("correlationIdLoggingFilter"); // 设置过滤器名称
        registration.addUrlPatterns("/*"); // 拦截路径
        registration.setOrder(-1); // 设置执行顺序,数字越低优先级越高
        return registration;
    }
}

<property name="log_pattern" value="%d{MM-dd HH:mm:ss.SSS} [%X{uu_id}] [%X{correlational_id}] [%5p] [%40.40c{1.}:%3L] - %m%n"/>

logging.pattern.console=%d{MM-dd HH:mm:ss.SSS} [%X{uu_id}] [%X{correlation_id}] [%5p] [%40.40c{1.}:%3L] - %m%n

启动后测试可以看出:启动时候没有correlation_id与uu_id值,当有请求进来才会生成:

curl -H 'Content-Type:application/json' -H 'correlation_id:xxxxx-yyyyy-zzzzz'  http://localhost:8080/logback/logs
04-15 12:16:29.740 [] [] [ INFO] [             o.s.b.w.e.t.TomcatWebServer:220] - Tomcat started on port(s): 8080 (http) with context path ''
04-15 12:16:29.750 [] [] [ INFO] [                      c.x.XyzApplication: 61] - Started XyzApplication in 1.504 seconds (JVM running for 2.672)
04-15 12:16:51.659 [] [] [ INFO] [                       o.a.c.c.C.[.[.[/]:173] - Initializing Spring DispatcherServlet 'dispatcherServlet'
04-15 12:16:51.659 [] [] [ INFO] [               o.s.w.s.DispatcherServlet:525] - Initializing Servlet 'dispatcherServlet'
04-15 12:16:51.660 [] [] [ INFO] [               o.s.w.s.DispatcherServlet:547] - Completed initialization in 1 ms
04-15 12:16:51.678 [e91e1660-69d2-4fd8-bdcb-304c0cd89c70] [xxxxx-yyyyy-zzzzz] [ERROR] [                    c.x.Log4j2Controller: 24] - hello, I am error!
04-15 12:16:51.678 [e91e1660-69d2-4fd8-bdcb-304c0cd89c70] [xxxxx-yyyyy-zzzzz] [ WARN] [                    c.x.Log4j2Controller: 25] - hello, I am warn!
04-15 12:16:51.680 [e91e1660-69d2-4fd8-bdcb-304c0cd89c70] [xxxxx-yyyyy-zzzzz] [ INFO] [                    c.x.Log4j2Controller: 26] - hello, I am info!

6、SpringBoot集成Logback

SpringBoot官网文档:https://docs.spring.io/spring-boot/docs/2.5.0/reference/html/features.html#features.logging

1、SpringBoot日志依赖关系

  1. spring-boot-starter是SpringBoot启动器,每一个SpringBoot应用都会依赖到它

  2. sping-boot-starter依赖Sping-boot-starter-looging

  3. SpringBoot 底层默认使用 SLF4J+ Logback 方式进行日志记录

  4. SpringBoot 使用中间替换包把其的日志框架都替换成了SLF4J

  5. SpringBoot 能自动适配所有的日志框架,且底层使用SLF4J + Logback方式记录日志,引入其他框架时,只需要把这个框架依赖的日志框架排除掉即可

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
        
        <exclusions>
            <exclusion>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-loggingartifactId>
            exclusion>
        exclusions>
    dependency>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-log4j2artifactId>
    dependency>
    

2、SpringBoot全局日志设置

SpringBoot官网配置文件详解:https://docs.spring.io/spring-boot/docs/2.5.0/reference/htmlsingle/#application-properties.core

  1. 日志的级别由低到高分别为:trace(跟踪) < debug(调试) < info(信息) < warn(警告) < error(错误)

  2. 在配置文件中调整输出的日志级别,日志就只会在这个级别及以后的高级别生效,SpringBoot 默认使用 INFO 级别(Logback 默认是 DEBUG)

  3. SpringBoot 的全局配置文件 “application.properties” 或 “application.yml” 中可以修改日志配置项:

    # 默认名logback-spring.xml,如果要设置其他名称则需要如下配置
    # logging.config=classpath:logback-spring.xml
    # 设置根节点的日志级别输出,root表示整个项目
    logging.level.root=INFO
    # 指定特定包及类的日志输出级别,未指定就按root设置的级别输出,如果root也未指定则按SpringBoot的默认级别info输出
    logging.level.org.springframework.web=DEBUG
    logging.level.org.hibernate=ERROR
    logging.level.com.xyz=DEBUG
    
    # 配置日志输出的文件,这两个选一个配置就可以了,一起配置的话,name的生效.每次启动都是追加日志
    # .name=具体文件, 写入指定的日志文件.文件名可以是确切的位置,也可以是相对于当前目录的位置(相对路径为与pom.xml同级)
    # .path=具体目录, 写入spring.log文件到指定目录.目录名可以是确切的位置,也可以是相对于位置(文件名spring.log无法更改)
    logging.file.name=logs/spring-boot.log
    logging.file.path=logs/
    
    # 指定控制台输出的日志格式,例如: %d{yyyy-MM-dd HH:mm:ss} [%X{uu_id}] -- [%thread] %-5level %logger{50} %msg%n
    # 1、%d 表示日期时间,
    # 2、%thread 表示线程名,
    # 3、%‐5level 级别从左显示5个字符宽度
    # 4、%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
    # 5、%msg 日志消息,
    # 6、%n 换行符
    # 7、%line 显示日志输出位置的行号,方便寻找位置
    # 8、%X 特殊占位符,%X{uu_id}是获取uu_id的值,代码中设置uu_id值:org.slf4j.MDC.put("uuid", "xx-yy-zz");
    # 配置日志输出格式, .file是配置输出到文件的日志格式, .console是配置输出到控制台的日志格式
    logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{50}:%line %msg%n
    logging.pattern.file=%d{yyyy-MM-dd HH:mm} -- [%thread] %-5level %logger{50} %msg%n
    
    # 设置日志记录器组,将相关的记录器组合在一起,然后设置日志记录器组的日志级别为TRACE
    logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
    logging.level.tomcat=TRACE
    # SpringBoot包括以下预定义的日志记录组,可以开箱即用
    # web: org.springframework.core.codec, org.springframework.http, org.springframework.web
    # sql: org.springframework.jdbc.core, org.hibernate.SQL
    logging.level.web=INFO
    logging.level.sql=DEBUG
    
  4. SpringBoot全局配置中的日志配置优先级高于第三方日志框架配置文件(application.properties > logback-spring.xml)

3、SpringBoot官网文档翻译

1、SpringBoot日志生成路径
logging.file.name logging.file.path 示例 说明
(none) (none) 只在控制台输出
指定文件名 (none) demo.log 输出到当前项目根路径下的 demo.log 文件中
(none) 指定目录 logs/log_lzy 输出到当前项目所在磁盘根路径下的/logs/log_lzy目录中的 spring.log 文件中
指定文件名 指定目录 当两个同时指定时, name会生效。推荐使用logging.file.name设置,因为它可自定义文件名
# 配置日志输出的文件,这两个选一个配置就可以了,一起配置的话,name的生效. 每次启动都是追加日志
# .name=具体文件, 写入指定的日志文件.文件名可以是确切的位置,也可以是相对于当前目录的位置(相对路径为与pom.xml同级)
# .path=具体目录, 写入spring.log文件到指定目录.目录名可以是确切的位置,也可以是相对于位置(文件名spring.log无法更改)
logging.file.name=logs/spring-boot.log
logging.file.path=logs/
  1. 默认情况:日志文件超过10M时,会新建文件进行递增,如logback.log、logback1.log、logback2.log,使用logging.file.max-size更改大小限制
  2. 默认情况:日志只记录到控制台,不写入日志文件,如果要在控制台输出之外写入到日志文件,则需要设置 .file 或 .path 属性
  3. 默认情况,logging.file.* 等配置使用的都是RollingFileAppender

日志输出到文件是非常有用的,比如命令行启动一个 jar 包,但是它一执行就自动报错,然后退出了,还来不急看清错误信息,此时可以修改配置把日志输出到指定文件中,再次启动错误信息就会自动存放进去

2、SpringBoot日志级别设置

SpringBoot Log Levels 日志级别官方文档:https://docs.spring.io/spring-boot/docs/2.5.0/reference/htmlsingle/#features.logging.log-levels

  1. 通过配置logging.level.=可以设置所有受支持的日志系统的日志级别,其中 level 是 ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF 之一

  2. 可以使用 logging.level.root 配置根日志记录器:

    # 未特别指定的仍然按 Spring Boot 的默认的 logging.level.root 设置输出.
    logging.level.root=WARN  # 根节点日志级别,即整个应用的日志级别设置,默认为 info
    logging.level.org.springframework.web=DEBUG   # 单独某个包的日志级别设置,spring web 包日志输出级别
    logging.level.org.hibernate=ERROR    # 单独某个包的日志级别设置,hibernate 日志输出级别
    logging.level.com.xzy=info  # 自己项目中指定包下的日志输出级别
    
3、SpringBoot日志记录器组

SpringBoot Log Groups 日志记录器组官方文档:https://docs.spring.io/spring-boot/docs/2.5.0/reference/htmlsingle/#features.logging.log-groups

  1. 将相关的记录器组合在一起,以便可以同时对它们进行配置,这通常是很有用的。Spring Boot 允许在 Spring 环境中定义日志组。例如下面通过将 “tomcat” 组添加到 application.properties 中来定义它,定义后,可以用一行更改组中所有记录器的级别

    logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
    logging.level.tomcat=TRACE
    
  2. SpringBoot 包括以下预定义的日志记录组,可以开箱即用:

    Name Loggers
    web org.springframework.core.codec, org.springframework.http, org.springframework.web
    sql org.springframework.jdbc.core, org.hibernate.SQL
    logging.level.web=INFO
    logging.level.sql=DEBUG
    
4、SpringBoot设置打印SQL

使用Mybatis的时候,SQL语句是DEBUG下才会打印,而这里我们只配置了INFO,所以想要查看SQL语句的话,有以下两种操作:

1、第一种把改成这样就会打印SQL,不过这样日志那边会出现很多其他消息

2、第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常INFO级别:

  • application.properties 全局配置

    logging.level.sql=DEBUG
    logging.level.org.mybatis=debug
    logging.level.com.xyz.*.dao=debug
    
  • logback-spring.xml 自定义配置文件配置

<configuration debug="true" scan="true" scanPeriod="60 seconds">
    
    <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" />
    <logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" />
    <logger name="org.hibernate.SQL" level="DEBUG" />
    <logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />
    <logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />

    
    <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"/>
configuration>
5、JAR启动设置日志输出级别

可以在启动的时候通过命令行参数指定日志输出级别(java -jar xxx.jar --level),相当于 logging.level.root 配置的根日志记录器。

java -jar .java-se-1.0-SNAPSHOT.jar --debug

4、Logback日志配置文件详解

  1. 可以直接在 SpringBoot 的全局配置文件中修改 SLF4J 的默认配置,也可以使用 SLF4J 实现框架的自己的配置文件。直接放置再类路径下即可

  2. 官网参考链接,根据日志记录系统的不同,各自的配置文件文件也不同:

    Logging System(日志系统) Customization(日志文件名称)
    Logback logback-spring.xml,logback-spring.groovy,logback.xml or logback.groovy
    Log4j2 log4j2-spring.xml,log4j2.xml
    JDK (Java Util Logging) logging.properties
  3. 因为 SpringBoot 底层默认采用 SLF4J+Logback 的日志组合,也就是说如果在 src/main/resources 目录下放置其中任一类型的配置文件,SpringBoot便会自动进行使用。而SpringBoot官方推荐优先使用带有-spring的文件名配置(如有logback-spring.xml,则不会使用logback.xml)。若需要对配置文件名进行修改,或者希望把放到其它目录下,可以在application中通过logging.config属性来指定,如:

    logging.config=classpath:dev/logback-spring.xml
    
  4. 具体配置文件设置详情可参考上面的教程:【配置文件结构详解】

  5. 这是转载其他人整理的百分号属性参数说明大全:

        ********************************************************************************************************************
        参数        说明                                         举例                    输出显示媒介
        ********************************************************************************************************************
        %c          列出logger名字空间的全称,如果加上{<层数>},   假设当前logger的命名空间是"a.b.c"
                    则表示列出从最内层算起的指定层数的名字空间
                                                                %c                  a.b.c
                                                                %c{2}               b.c
                                                                %20c                (若名字空间长度小于20,则左边用空格填充)
                                                                %-20c               (若名字空间长度小于20,则右边用空格填充)
                                                                %.30c               (若名字空间长度超过30,截去多余字符)
                                                                %20.30c             (若名字空间长度小于20,则左边用空格填充;
                                                                                        若名字空间长度超过30,截去多余字符)
                                                                %-20.30c            (若名字空间长度小于20,则右边用空格填充;
                                                                                        若名字空间长度超过30,截去多余字符)
        ********************************************************************************************************************
        %C          列出调用logger的类的全名(包含包路径)         假设当前类是"org.apache.xyz.SomeClass"
                                                                %C                  org.apache.xyz.SomeClass
                                                                %C{1}               SomeClass
        %class
        ********************************************************************************************************************
        %d          显示日志记录时间,{<日期格式>}使用ISO8601定义的日期格式
                                                                %d{yyyy/MM/dd HH:mm:ss,SSS}     2005/10/12 22:23:30,117
                                                                %d{ABSOLUTE}        22:23:30,117
                                                                %d{DATE}            12 Oct 2005 22:23:30,117
                                                                %d{ISO8601}         2005-10-12 22:23:30,117
        ********************************************************************************************************************
        %F          显示调用logger的源文件名                     %F                   MyClass.java
        ********************************************************************************************************************
        %l          显示日志事件的发生位置,包含包路径、方法名、
                    源文件名,以及在代码中的行数                  %l                   com.a.b.MyClass.main(MyClass.java:168)
        ********************************************************************************************************************
        %L          显示调用logger的代码行                       %L                   129
        %line                                                  %line                129
        ********************************************************************************************************************
        %level      显示该条日志的优先级                         %level               INFO
        %p                                                     %p                   INFO
        ********************************************************************************************************************
        %m          显示输出消息                                 %m                  This is a message for debug.
        %message                                                %message            This is a message for debug.
        ********************************************************************************************************************
        %M          显示调用logger的方法名                       %M                   main
        ********************************************************************************************************************
        %n          当前平台下的换行符                           %n                   Windows平台下表示rn,UNIX平台下表示n
        ********************************************************************************************************************
        %p          显示该条日志的优先级                         %p                   INFO
        %level                                                 %level               INFO
        ********************************************************************************************************************
        %r          显示从程序启动时到记录该条日志时已经经过的毫秒数  %r                 1215
        ********************************************************************************************************************
        %t          输出产生该日志事件的线程名                    %t                   http-nio-8080-exec-10
        %thread                                                 %thread              http-nio-8080-exec-10
        ********************************************************************************************************************
        %x          按NDC(Nested Diagnostic Context,线程堆栈)顺序输出日志           假设某程序调用顺序是MyApp调用com.foo.Bar
                                                                %c %x - %m%n        MyApp - Call com.foo.Bar.
                                                                                    com.foo.Bar - Log in Bar
                                                                                    MyApp - Return to MyApp.
        ********************************************************************************************************************
        %X          按MDC(Mapped Diagnostic Context,线程映射表)
                    输出日志。通常用于多个客户端连接同一台服务器,
                    方便服务器区分是那个客户端访问留下来的日志。     %X{5}             (记录代号为5的客户端的日志)
        ********************************************************************************************************************
        %%          显示一个百分号                               %%                  %
        ********************************************************************************************************************
    

5、动态切换日志级别的几种方式

1、logback.xml 配置文件定时监控

修改 logback.xml 配置文件,定时监控配置变化情况。





<configuration scan="true" scanPeriod="60 seconds" debug="false"/>
  1. 如果是在本地 IDE 编辑器中测试,注意修改的是 classes 编译目录下的 logback.xml 文件,而不是 resources 目录下的源文件
  2. 鉴于现在都是微服务开发,分布式部署,而且为了方便管理,基本都是打包后部署在一些平台上面。直接修改日志配置文件不太现实
2、LoggerContext 切换日志输出级别

使用Controller接口动态修改日志输出级别,想设置什么级别,只需传参调接口即可,无论是设置root级别,还是指定包或类,不用重启服务能立马生效

package com.example.xyz;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LogbackController {
    private static final Logger log = (Logger) LoggerFactory.getLogger(LogbackController.class);
    /**
     * 打印日志测试: http://localhost:8080/logback/logs
     */
    @GetMapping("logback/logs")
    public void logs() {
        log.error("hello, I am error!");
        log.warn("hello, I am warn!");
        log.info("hello, I am {}!", "info");
        log.debug("hello, I am debug!");
        log.trace("hello, I am trace!");
    }

    /**
     * logback 动态切换指定包或者类的日志输出级别,立即生效.
     *   http:localhost:8080/logback/updateLevel
     *   http:localhost:8080/logback/updateLevel?level=DEBUG
     *   http:localhost:8080/logback/updateLevel?level=DEBUG&clazz=com.xyz
     *
     * @param level :日志级别,可选值有:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF,默认为 debug。不区分大小写.
     * @param clazz :指定的包或者类路径,为空时默认设置全局(root)日志级别。路径不存在时,照样会设置这个路径,不会影响全局级别,这一点与 log4j2 不同.
     *              比如 org.springframework。
     * @return map  :返回指定路径的当前日志级别,root 表示全局级别
     */
    @GetMapping(value = "/logback/updateLevel")
    public String setLevel(String level, String clazz) {
        try {
            // 返回正在使用的 ILoggerFactory 实例.
            LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
            /**
             * Logger getLogger(final String name):根据包路径或类路径获取日志记录器,"ROOT" 表示根记录器
             * Level toLevel(String sArg):转换为日志级别,如果转换失败,则默认为 debug
             * synchronized void setLevel(Level newLevel):为日志记录器设置日志输出级别,立即生效.
             */
            if (clazz == null || "".equals(clazz.trim())) {
                // 设置根日志记录器对象并设置日志输出级别
                loggerContext.getLogger(Logger.ROOT_LOGGER_NAME).setLevel(Level.toLevel(level));
            } else {
                // 设置指定日志记录器并设置日志输出级别,路径不存在也没有关系,会返回它的日志记录器,然后设置输出级别
                loggerContext.getLogger(clazz).setLevel(Level.toLevel(level));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return "fail";
        }
        return "success";
    }
}
3、SpringBoot Actuator 监控管理日志

使用SpringBoot Actuator监控管理日志的优点:

  • 无需编码,只需要引用Spring Boot Actuator监控依赖,然后开启访问端点 /loggers,即可轻松查看日志输出级别,并进行切换
  • 解耦日志框架,无论使用的 Logback 还是 Log4j2 ,都能轻松切换

1、引入pring Boot Actuator依赖


<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-actuatorartifactId>
dependency>

2、开启日志访问端点: /loggers

management:
  endpoint:
    health:
      show-details: ALWAYS # 展示节点的详细信息
  endpoints:
    web:
      exposure:
        include: info,health,logfile,loggers # 指定公开的访问端点

3、查看级别

  • 发送 GET 请求,获取日志等级:http://localhost:8080/actuator/loggers
  • 返回的信息非常详细,包含了 ROOT,以及程序中各个包和类的日志级别
  • 其中 configuredLevel 表示配置级别,effectiveLevel 表示有效级别,configuredLevel 可能为 null,因为没有配置。

4、修改日志级别

  • 发送 POST 请求,设置指定包或者类(com.xyz)日志输出级别:http://localhost:8080/actuator/loggers/com.xyz
  • 发送 POST 请求,设置 root 全局日志输出级别:http://localhost:8080/actuator/loggers/root
  • 请求 Body 的内容格式:{“configuredLevel”:“error”}

7、参考文献 & 鸣谢

  • Spring Boot 2.x 日志配置 与集成 Logback 日志框架【CSDN 蚩尤后裔】https://blog.csdn.net/wangmx1993328/article/details/81044147
  • 万字详解logback日志框架,再没这么全的了【CSDN 程序新视界】https://blog.csdn.net/wo541075754/article/details/109193354
  • 学会这些Logback高级知识点,程序日志性能提高几十倍(上)【CSDN 陈皮的JavaLib】https://javalib.blog.csdn.net/article/details/113899664
  • java日志(三)–slf4j和logback使用【CSDN:panda-star】https://blog.csdn.net/chinabestchina/article/details/104743907

你可能感兴趣的:(从零开始学,Java日志框架,java)