• Logback配置解析


    logback优点

    比较吸引的几个优点如下:

    • 内核重写,初始化内存加载更小
    • 文档比较齐全
    • 支持自动重新加载配置文件,扫描过程快且安全,它并不需要另外创建一个扫描线程
    • 支持自动去除旧的日志文件,可以控制已经产生日志文件的最大数量

    logback加载

    在项目中引入logback依赖:

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>${logback.version}</version>
    </dependency>
    

    启动项目时,logback会按照如下顺序扫描配置文件:

    • 在系统配置文件System Properties中寻找是否有logback.configurationFile对应的value
    • 在classpath下寻找是否有logback.groovy(即logback支持groovy与xml两种配置方式)
    • 在classpath下寻找是否有logback-test.xml
    • 在classpath下寻找是否有logback.xml

    以上任何一项找到了,就不进行后续扫描,按照对应的配置进行logback的初始化,可从控制台输出信息中查看加载的配置文件。

    当所有以上四项都找不到的情况下,logback会调用ch.qos.logback.classic.BasicConfigurator的configure方法,构造一个ConsoleAppender用于向控制台输出日志,默认日志输出格式为%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n

    ContextInitializer类中相关方法摘录如下:

    final public static String GROOVY_AUTOCONFIG_FILE = "logback.groovy";
    final public static String AUTOCONFIG_FILE = "logback.xml";
    final public static String TEST_AUTOCONFIG_FILE = "logback-test.xml";
    final public static String CONFIG_FILE_PROPERTY = "logback.configurationFile";
    
    ...
        
    public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
        ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
        URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }
        url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }
        url = getResource(GROOVY_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }
        return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus);
    }
    
    public void autoConfig() throws JoranException {
        StatusListenerConfigHelper.installIfAsked(loggerContext);
        URL url = findURLOfDefaultConfigurationFile(true);
        if (url != null) {
            configureByResource(url);
        } else {
            Configurator c = EnvUtil.loadFromServiceLoader(Configurator.class);
            if (c != null) {
                try {
                    c.setContext(loggerContext);
                    c.configure(loggerContext);
                } catch (Exception e) {
                    throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass().getCanonicalName() : "null"), e);
                }
            } else {
                BasicConfigurator basicConfigurator = new BasicConfigurator();
                basicConfigurator.setContext(loggerContext);
                basicConfigurator.configure(loggerContext);
            }
        }
    }
    

    logback配置文件解析

    • 根节点<configuration>

    <!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
    <configuration scan="true" scanPeriod="30 seconds" debug="true">
        
    <!-- 
    	scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    	scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    	debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
    -->
    
    • 设置变量<property>

    <configuration>
        <!-- 定义日志文件的存储地址 -->
    	<property name="LOG_HOME" value="log"/>
        <!-- 格式化输出 -->
    	<property name="LOG_PATTERN" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}][%-5level][%t][%file:%line][%X{traceId}] -| %m%n"/>
    </configuration>
    
    • <logger>与<root>

    <logger>用来设置某一个包或者具体某一个类的日志打印级别、以及指定appender。<logger>可以包含零个或者多个<appender-ref>元素,标识这个appender将会添加到这个logger。

    <root>也是<logger>元素,但它是根logger,只有一个level属性,因为它的name就是ROOT

    <!-- name:必填,指定受此logger约束的某一个包或者具体的某一个类。这个name表示的是LoggerFactory.getLogger(XXX.class),XXX的包路径,包路径越少越是父级
         level:用来设置打印级别,五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR,如果未设置此级别,那么当前logger会继承上级的级别
      	 additivity:是否向上级logger传递打印信息,默认为true -->
    <logger name="com.example.iot" level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="INFO-APPENDER"/>
        <appender-ref ref="ERROR-APPENDER"/>
    </logger>
    
    <!-- 没有配置<appender-ref>,表示此<logger>不会打印出任何信息 -->
    <logger name="com.example.iot.demo1" level="DEBUG" additivity="true" />
    
    <!-- 没有配置level,即继承父级的level,<logger>的父级为<root>,那么level=info -->
    <logger name="com.example.iot.demo2" additivity="false" />
    
    <!-- 控制台输出日志级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
    
    • <appender>

    负责写日志的组件,有两个必要属性name和class

    1. 常用的控制台输出:ConsoleAppender
    <!-- name指定<appender>的名称
      	 class指定<appender>的全限定名 -->
    <!-- 控制台输出 appender -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- <encoder>表示输出格式 -->
            <pattern>${LOG_PATTERN}</pattern>
            <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
            <charset>utf8</charset>
        </encoder>
    </appender>
    
    1. 常用的滚动记录文件:RollingFileAppender
    <!-- INFO日志 appender: 按照每天生成日志文件 -->
    <appender name="INFO-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_HOME}/iot-sdk-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>true</append>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名: 
    			%d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
    			%i:自增数字
    		-->
            <fileNamePattern>${LOG_HOME}/iot-sdk-info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>30</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>100MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>
    
    • <encoder>

    encoder节点负责两件事情:

    1. 把日志信息转换为字节数组
    2. 把字节数组写到输出流

    以下是一个常用配置:

    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用””进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
    			 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %t %file:%line %X{traceId} -| %m%n</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>
    
    • <filter>

    配合appender使用,<filter>是<appender>的一个子节点,表示在当前给到的日志级别下再进行一次过滤

    1. Level 级别过滤器

    根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据onMath和onMismatch接收(ACCEPT)或拒绝(DENY)日志。

    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>
    
    1. ThresholdFilter: 临界值过滤器

    将日志级别低于<level>的全部进行过滤。当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。

    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 记录info级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>
    

    自定义appender

    logback提供的appender基本够用,有时候也免不了有自定义的需求。以下是一个简单的自定义appender:

    package com.example.iot.demo;
    
    import ch.qos.logback.classic.spi.ILoggingEvent;
    import ch.qos.logback.core.AppenderBase;
    
    public class DemoAppender extends AppenderBase<ILoggingEvent> {
        @Override
        protected void append(ILoggingEvent eventObject) {
            // 打印格式化后的日志信息
            System.out.println(eventObject.getFormattedMessage());
        }
    }
    

    在配置文件中引入DemoAppender

    <appender name="DEMO-APPENDER" class="com.example.iot.demo.DemoAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>
    
    <logger name="com.example.iot.demo" level="DEBUG" additivity="true">
        <appender-ref ref="DEMO-APPENDER"/>
    </logger>
    

    常用配置

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scan="true" scanPeriod="30 seconds" debug="true">
        <!-- logback的根节点 <configuration>的属性scan、scanPeriod、debug
           scan:        当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
           scanPeriod:  设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
           debug:       当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
         -->
    
        <!-- 定义日志文件的存储地址 -->
        <property name="LOG_HOME" value="log"/>
        <!-- 格式化输出:
            %d          表示日期,
            %thread     表示线程名,
            %level      日志级别从左显示5个字符宽度,
            %thread     线程名
            %file:%line 文件名:行号,
            %m          日志消息,
            %n          换行符,
            %X{traceId} 自定义设置的参数
            %mdc        自定义参数
        -->
        <property name="LOG_PATTERN"
                  value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%5level) -- [%15.15t] %cyan(%-23.23logger{23}) : %m%n"/>
    
    
        <!-- appender是configuration的子节点,是负责写日志的组件 -->
        <!-- 控制台输出 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${LOG_PATTERN}</pattern>
                <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
                <charset>utf8</charset>
            </encoder>
        </appender>
    
        <!-- INFO日志 appender: 按照每天生成日志文件 -->
        <appender name="INFO-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 过滤器,记录info级别以上的日志 -->
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>INFO</level>
            </filter>
            <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
            <file>${LOG_HOME}/iot-sdk-info.log</file>
            <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
            <append>true</append>
            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                <!-- 日志文件输出的文件名: %d可以包含一个Java.text.SimpleDateFormat指定的时间格式 -->
                <fileNamePattern>${LOG_HOME}/iot-sdk-info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
                <maxHistory>30</maxHistory>
                <!-- 文件大小超过100MB归档 -->
                <maxFileSize>100MB</maxFileSize>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${LOG_PATTERN}</pattern>
                <charset>utf8</charset>
            </encoder>
        </appender>
    
        <!-- 错误日志 appender: 按照每天生成日志文件 -->
        <appender name="ERROR-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 过滤器,只记录error级别的日志 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <!-- 日志名称 -->
            <file>${LOG_HOME}/iot-sdk-error.log</file>
            <append>true</append>
            <!-- 每天生成一个日志文件,保存30天的日志文件 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                <!-- 日志文件输出的文件名:按天回滚 daily -->
                <fileNamePattern>${LOG_HOME}/iot-sdk-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 日志文件保留天数 -->
                <maxHistory>30</maxHistory>
                <!-- 文件大小超过100MB归档 -->
                <maxFileSize>100MB</maxFileSize>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${LOG_PATTERN}</pattern>
                <charset>utf8</charset>
            </encoder>
        </appender>
    
        <!-- 指定项目中某个包,当有日志操作行为时的日志记录级别
            级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE
            additivity=false 表示匹配之后,不再继续传递给其他的logger
        -->
        <logger name="com.example.iot" level="DEBUG" additivity="false">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="INFO-APPENDER"/>
            <appender-ref ref="ERROR-APPENDER"/>
        </logger>
    
        <!-- 控制台输出日志级别 -->
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
        </root>
    </configuration>
    

    参考:

    1. Logback documentation
    2. Java日志框架:logback详解
    走在同样的路上,遇见不一样的风景
  • 相关阅读:
    26个Jquery使用小技巧(jQuery tips, tricks & solutions)
    JavaScript中Eval()函数的作用
    基于邮件通道的WCF通信系统
    同步一个数据库要发多少个数据包?
    还在写SQL的同志,去喝杯咖啡吧!
    隐藏在程序旮旯中的“安全问题”
    在SQLMAP中使用动态SQL
    SQLSERVER 占了500多M内存,原来的程序无法一次查询出50多W数据了,记录下这个问题的解决过程。
    实例探究字符编码:unicode,utf8,default,gb2312 的区别
    Why to do,What to do,Where to do 与 Lambda表达式!
  • 原文地址:https://www.cnblogs.com/flylinran/p/10506088.html
Copyright © 2020-2023  润新知