logback-动态修改日志格式

目标

在logback作为日志框架的前提下,实现在代码中动态修改日志输出格式的需求(也许没什么用,不过可以在自己的程序启动时达到类似sprinboot的banner那样的效果-springboot的banner是没有日志的类名、时间戳之类的前缀的)。

实现,在一个日志文件中,可以输出不同格式的日志内容。

本demo的目标是:

程序启动时输出没有前缀的banner logo,后面的所有日志为带前缀的日志,比如这样:

     ____.___________
    |    |\_   _____/_____ ______ ______ ______ ______
    |    | |    __)/ ____// ____// ____// ____// ____/
/\__|    | |     \< <_|  < <_|  < <_|  < <_|  < <_|  |
\________| \___  / \__   |\__   |\__   |\__   |\__   |
               \/     |__|   |__|   |__|   |__|   |__|
2021-07-07 17:41:37.363 [main] INFO  com.jfqqqq.App - 程序启动【Wed Jul 07 17:41:37 CST 2021】...
2021-07-07 17:41:37.365 [main] INFO  com.jfqqqq.App - 程序结束...
2021-07-07 17:41:37.365 [main] INFO  com.jfqqqq.App - 程序结束...
2021-07-07 17:41:37.365 [main] INFO  com.jfqqqq.App - 程序结束...

知识点

0. 一个日志文件只能被一个appender使用,如果定义了多个appender都指向同一个日志文件,那么logback在初始化时只会使用第一个appender,只有它被“started”。“第一个”的意思是,在logback.xml中,从上到下第一个出现的引用该日志文件的appender。如下面的例子,就是name为“FILE_INFO_BANNER”的appender为第一个:

   <appender name="FILE_INFO_BANNER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        ...省略
    </appender>

    <!--info 级别 文件日志, 按照每天生成日志文件 -->
    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        ...省略
    </appender>

说明

started:在类ch.qos.logback.core.UnsynchronizedAppenderBase中,doAppend方法用来输出日志,输出时会判断当前logger是否"started",是才会输出:

1. additivity属性(在xml中配置为additivity,在代码中为additive)的作用。

简单的说,logback默认的日志行为,是按级别依次调用的,一个logger会有父logger,父logger又会有爷爷logger。。。以此类推。所以,如果这个属性为true,那么我们自己定义的logger在打印日志时,父logger也会打印。如果本logger和父logger的appender都被"started"了(比如一个被started的appender被子logger和父logger同时引用),就会出现打印重复的情况。

比如:

    <logger name="com.jfqqqq.Banner" level="info" additivity="true">
        <appender-ref ref="FILE_INFO_BANNER"/>
    </logger>
    <root level="${LOG_LEVEL}">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE_INFO_BANNER"/>
        <appender-ref ref="FILE_INFO"/>
    </root>

如果设为false,就不会重复打印了。

详情可以参考:http://skyao.github.io/2014/09/23/logback-additivity/

2. PatternLayoutEncoder,是RollingFileAppender的属性之一,用来控制输出格式。RollingFileAppender大家会很熟悉,在使用匹配模板的方式输出日志,这个会用的比较多,比如:

    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/${SELF_BLOCK}/info/info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<!--            <pattern>%msg%n</pattern>-->
        </encoder>
        <!--记录info级别-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

我们可以动态修改RollingFileAppender中的PatternLayoutEncoder,实现格式的变换。

值得注意的时,这个PatternLayoutEncoder在更改pattern后,必须要执行start()方法,才能完成真正的刷新,否则是无效的--并且,在更改前,需要先执行stop()方法。然后再start()(不要问我怎么知道的)。等于说是这样的:

//伪代码
encoder.stop();
encoder.setPattern(pattern);
encoder.start();//才能生效

3. 

综上所述,我们只要动态的修改PatternLayoutEncoder的pattern,在输出banner时改为没有前缀的格式,输出完成后再改回有前缀的格式即可。

我的实现方式

1. 定义好有前缀的输出格式的appender(代码中叫“FILE_INFO”),把它交给root logger,这样保证了有前缀的输出。

2. 然后,定义一个bannerLogger,它也引用这个“FILE_INFO”。

3. 程序启动时,获取bannerLogger,再通过它获取“FILE_INFO”,然后获取“FILE_INFO”的pattern(这个pattern就是早xml配置的pattern)并放到缓存中,然后创建新的没有前缀的格式pattern,赋予给appender,用于输出banner的内容。

4. 输出完成后,再将缓存的pattern重新赋予“FILE_INFO”, 这样,后续的日志就全都有前缀了。

注意:上面的4个步骤中只说明大意,别忘了stop()和start()函数的使用。

demo

xml

    <property name="LOG_HOME" value="" />   

    <property name="LOG_LEVEL" value="" />

    <property name="maxFileSize" value="10MB"/>

    <property name="MaxHistory" value="30"/> 

    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<!--            <pattern>%msg%n</pattern>-->
        </encoder>
        <!--记录info级别-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <logger name="com.jfqqqq.test.Banner" level="info">
        <appender-ref ref="FILE_INFO"/>
    </logger>

    <root level="${LOG_LEVEL}">
        <appender-ref ref="FILE_INFO"/>
    </root>

xml中定义了两个logger(root 与 com.jfqqqq.Banner)和一个appender(FILE_INFO)。两个logger都使用 FILE_INFO 。

java


public class Banner {

    public void println(String bannerPath) {
        try {
            ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.tdt.tile.clip.command.Banner");
            //一定要设为false,否则会出现知识点2中的重复输出的情况。会发现banner的图形有重影(每一行输出了两边,看上去像重影)
            logger.setAdditive(false);

            RollingFileAppender<ILoggingEvent> configAppender = (RollingFileAppender) logger.getAppender("FILE_INFO");
            PatternLayoutEncoder encoder = (PatternLayoutEncoder)configAppender.getEncoder();
            encoder.stop();
            String pattern = encoder.getPattern();
            encoder.setPattern("%msg%n");
            encoder.start();

            if (bannerPath!= null) {
                File file = new File(bannerPath);
                if (file.exists()) {
                    FileReader fileReader = new FileReader(file);
                    BufferedReader bufferedReader = new BufferedReader(fileReader);
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        logger.info(line);
                    }
                    bufferedReader.close();
                    fileReader.close();
                }
            }
            encoder.stop();
            encoder.setPattern(pattern);
            encoder.start();


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

完成

----------------------------------------------------- 分割线 -----------------------------------------------------------------

以下是各种实验

前提环境

App:

    public void start(String bannerPath) {
        assert bannerPath != null;
        //banner 打印
        new Banner().println(bannerPath);
        logger.info("程序启动【{}】...", new Date());
        logger.info("程序结束...");
        logger.info("程序结束...");
        logger.info("程序结束...");
    }

Banner:


public class Banner {
    public void println(String binPath) {
        try {
            ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.jfqqqq.Banner");
            String path = binPath.replace("bin", "conf" + SystemUtil.getSeparator() + "banner.txt");
            if (path != null) {
                File file = new File(path);
                if (file.exists()) {
                    FileReader fileReader = new FileReader(file);
                    BufferedReader bufferedReader = new BufferedReader(fileReader);
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        logger.info(line);
                    }
                    bufferedReader.close();
                    fileReader.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

logback.xml:

有一个appender,称呼为”FILE_INFO”,日志级别为info,输出到指定目录下的日志文件中(后面简称路径/X/info.log),如(下面demo中有写多余的配置,可以忽略):

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="" />
    <!--root 日志级别-->
    <property name="LOG_LEVEL" value="" />

    <property name="maxFileSize" value="10MB"/>

    <property name="MaxHistory" value="30"/>

    <property name="info_file_path" value="${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log"/>


    <!--info 级别 文件日志, 按照每天生成日志文件 -->
    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<!--            <pattern>%msg%n</pattern>-->
        </encoder>
        <!--记录info级别-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <root level="${LOG_LEVEL}">
        <appender-ref ref="FILE_INFO"/>

    </root>

</configuration>

失败的实验:

在xml中增加一个banner的banner_appender(name="FILE_INFO_BANNER"),设置好输出格式为没有前缀的pattern:”%msg%n“:

    <appender name="FILE_INFO_BANNER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%msg%n</pattern>
            <!--            <pattern>%msg%n</pattern>-->
        </encoder>
        <!--记录info级别-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

然后再定义一个单独的logger(name="com.jfqqqq.Banner"),使用banner_appender(FILE_INFO_BANNER):

    <logger name="com.jfqqqq.Banner" level="info">
        <appender-ref ref="FILE_INFO_BANNER"/>
    </logger>

xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="" />
    <!--root 日志级别-->
    <property name="LOG_LEVEL" value="" />

    <property name="maxFileSize" value="10MB"/>

    <property name="MaxHistory" value="30"/>

    <property name="info_file_path" value="${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log"/>


    <!--info 级别 文件日志, 按照每天生成日志文件 -->
    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<!--            <pattern>%msg%n</pattern>-->
        </encoder>
        <!--记录info级别-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="FILE_INFO_BANNER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%msg%n</pattern>
            <!--            <pattern>%msg%n</pattern>-->
        </encoder>
        <!--记录info级别-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <logger name="org.mongodb.driver.connection" level="WARN"></logger>
    <logger name="org.mongodb.driver" level="OFF"></logger>
    <logger name="com.jfqqqq.Banner" level="info">
        <appender-ref ref="FILE_INFO_BANNER"/>
    </logger>
    <root level="${LOG_LEVEL}">
        <appender-ref ref="FILE_INFO_BANNER"/>
        <appender-ref ref="FILE_INFO"/>

    </root>

</configuration>

结果

失败。包含banner在内的所有日志都是有前缀的:

2021-07-07 17:41:37.281 [main] INFO  com.jfqqqq.Banner -      ____.___________
2021-07-07 17:41:37.283 [main] INFO  com.jfqqqq.Banner -     |    |\_   _____/_____ ______ ______ ______ ______
2021-07-07 17:41:37.283 [main] INFO  com.jfqqqq.Banner -     |    | |    __)/ ____// ____// ____// ____// ____/
2021-07-07 17:41:37.283 [main] INFO  com.jfqqqq.Banner - /\__|    | |     \< <_|  < <_|  < <_|  < <_|  < <_|  |
2021-07-07 17:41:37.283 [main] INFO  com.jfqqqq.Banner - \________| \___  / \__   |\__   |\__   |\__   |\__   |
2021-07-07 17:41:37.283 [main] INFO  com.jfqqqq.Banner -                \/     |__|   |__|   |__|   |__|   |__|
2021-07-07 17:41:37.363 [main] INFO  com.jfqqqq.App - 程序启动【Wed Jul 07 17:41:37 CST 2021】...
2021-07-07 17:41:37.365 [main] INFO  com.jfqqqq.App - 程序结束...
2021-07-07 17:41:37.365 [main] INFO  com.jfqqqq.App - 程序结束...
2021-07-07 17:41:37.365 [main] INFO  com.jfqqqq.App - 程序结束...

原因:banner的appender没能初始化,最后是由root logger打印的。

实验二

xml:

给banner的logger增加additive="false"属性,并在root logger中去掉这个banner:

   <logger name="com.jfqqqq.Banner" level="info" additive="false">
        <appender-ref ref="FILE_INFO_BANNER"/>
    </logger>
    <root level="${LOG_LEVEL}">
        <appender-ref ref="FILE_INFO"/>
    </root>

其他不变

结果:

2021-07-07 18:35:03.073 [main] INFO  com.tdt.tile.clip.command.App - 程序启动【Wed Jul 07 18:35:03 CST 2021】...
2021-07-07 17:41:37.365 [main] INFO  com.jfqqqq.App - 程序结束...
2021-07-07 17:41:37.365 [main] INFO  com.jfqqqq.App - 程序结束...
2021-07-07 17:41:37.365 [main] INFO  com.jfqqqq.App - 程序结束...

失败

原因:虽然拒绝了父类的表现,但是banner的appender并没有“started”初始化,所以输出不了。

实验三

把banner的appender声明放在前边,root中也赋予这个appender:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="" />
    <!--root 日志级别-->
    <property name="LOG_LEVEL" value="" />

    <property name="maxFileSize" value="10MB"/>

    <property name="MaxHistory" value="30"/>

    <property name="info_file_path" value="${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log"/>

    <appender name="FILE_INFO_BANNER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%msg%n</pattern>
            <!--            <pattern>%msg%n</pattern>-->
        </encoder>
        <!--记录info级别-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!--info 级别 文件日志, 按照每天生成日志文件 -->
    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/info/jfqqqq.info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <maxFileSize>${maxFileSize}</maxFileSize>
            <!--日志文件保留天数-->
            <MaxHistory>${MaxHistory}</MaxHistory>
            <!--            <totalSizeCap>20GB</totalSizeCap>-->
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <!--            <pattern>%msg%n</pattern>-->
        </encoder>
        <!--记录info级别-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <logger name="org.mongodb.driver.connection" level="WARN"></logger>
    <logger name="org.mongodb.driver" level="OFF"></logger>
    <logger name="com.jfqqqq.Banner" level="info" additivity="true">
        <appender-ref ref="FILE_INFO_BANNER"/>
    </logger>
    <root level="${LOG_LEVEL}">
        <appender-ref ref="FILE_INFO_BANNER"/>
        <appender-ref ref="FILE_INFO"/>
    </root>

</configuration>

结果

     ____.___________
     ____.___________
    |    |\_   _____/_____ ______ ______ ______ ______
    |    |\_   _____/_____ ______ ______ ______ ______
    |    | |    __)/ ____// ____// ____// ____// ____/
    |    | |    __)/ ____// ____// ____// ____// ____/
/\__|    | |     \< <_|  < <_|  < <_|  < <_|  < <_|  |
/\__|    | |     \< <_|  < <_|  < <_|  < <_|  < <_|  |
\________| \___  / \__   |\__   |\__   |\__   |\__   |
\________| \___  / \__   |\__   |\__   |\__   |\__   |
               \/     |__|   |__|   |__|   |__|   |__|
               \/     |__|   |__|   |__|   |__|   |__|
程序启动【Wed Jul 07 19:06:03 CST 2021】...
程序结束...
程序结束...
程序结束...

原因:banner的appender被banner的logger和root logger同时引用,additivity为true,满足了知识点2的条件,因此用日志中,banner logger的图形会重复。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值