目的
由于需要写文件来上报数据,并且文件需要按天切割,因此采用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}");
}
}