logback通过程序化(programmatical)配置logger写日志文件

目的

由于需要写文件来上报数据,并且文件需要按天切割,因此采用logger的方式写文件。

为什么采用程序化配置?

如果写入的文件路径,是固定的,可以直接配置logback.xml。但是由于文件路径是动态配置的,所以需要程序化配置。

示例代码

package org.rivu.logdemo;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;

/**
 * @author ki on 2021/01/11
 */
public class LoggerHolder {

    private LoggerHolder() {
    }

    /**
     * 支持生成写文件的logger
     *
     * @param fileNamePattern logger name
     * @return Logger
     */
    public static Logger getLogger(String name, String fileNamePattern) {
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        // 如果未加载过该logger,则新建一个
        Logger logger = context.exists(name);
        // 使用懒汉单例模式,避免创建时竞争
        if (logger == null) {
            synchronized (LoggerHolder.class) {
                logger = context.exists(name);
                if (logger == null) {
                    buildLogger(name, fileNamePattern);
                    logger = context.exists(name);
                }
            }
        }
        return logger;
    }

    private static void buildLogger(String name, String fileNamePattern) {
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        // logger
        Logger logger = context.getLogger(name);
        logger.setAdditive(false);
        logger.setLevel(Level.INFO);
        logger.addAppender(rollingFileAppender(context, name, fileNamePattern));
    }

    private static RollingFileAppender<ILoggingEvent> rollingFileAppender(
            LoggerContext context,
            String name,
            String fileNamePattern) {
        String appenderName = name + "-appender";
        // 输出格式
        PatternLayoutEncoder layoutEncoder = new PatternLayoutEncoder();
        layoutEncoder.setContext(context);
        layoutEncoder.setPattern("%msg%n"); // 原样输出数据
        layoutEncoder.setCharset(StandardCharsets.UTF_8);
        layoutEncoder.start();
        // 文件appender
        RollingFileAppender<ILoggingEvent> fileAppender = new RollingFileAppender<>();
        fileAppender.setContext(context);
        fileAppender.setName(appenderName);
        fileAppender.setEncoder(layoutEncoder);
        fileAppender.setAppend(true);
        // 文件滚动策略
        TimeBasedRollingPolicy<ILoggingEvent> filePolicy = new TimeBasedRollingPolicy<>();
        filePolicy.setContext(context);
        filePolicy.setParent(fileAppender);
        filePolicy.setFileNamePattern(fileNamePattern);
        filePolicy.start();
        // 配置策略
        fileAppender.setRollingPolicy(filePolicy);
        fileAppender.start();
        return fileAppender;
    }

}

测试代码

package org.rivu.logdemo;


import ch.qos.logback.classic.Logger;
import org.junit.Test;
import org.springframework.util.Assert;

/**
 * @author ki on 2021/1/11.
 */
public class LoggerHolderTest {

    @Test
    public void testGetLogger() {
        Logger writer = LoggerHolder.getLogger("test", "/data/test.%d{yyyyMMdd}.log");
        Assert.notNull(writer, "logger empty");
        writer.info("{\"name\":\"张三丰\",\"age\":121}");
    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容