自定义Logger实现方案
在项目复杂业务当中,可能回遇到logbook.xml配置还不能够满足需要的情况。需要自定义实现log组件,在不更改任何配置的情况下,需要根据业务入口类(可以时controller,或是接口组件的的接口等)去分离日志内容。
下面我逐步介绍如何实现。
创建LoggerFactory,生成自定义Logger
package com.iflytek.mea.job.api.log;
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.filter.LevelFilter;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import ch.qos.logback.core.spi.FilterReply;
import ch.qos.logback.core.util.FileSize;
import org.slf4j.LoggerFactory;
import java.util.Hashtable;
import java.util.Map;
public class LoggerFactory {
public static ThreadLocal<Logger> LOGGER = new ThreadLocal<>();
private static Hashtable<String, Logger> loggerTable = new Hashtable<>();
public static Logger getLogger() {
return LOGGER_FACTORY.get();
}
public static void initLoggers(Map<String, Class> jobMap, String level) {
for (Map.Entry<String, Class> entry : jobMap.entrySet()) {
Class aClass = entry.getValue();
String className = aClass.getClass().getName();
Logger logger = (Logger) LoggerFactory.getLogger(className);
infoAppender(logger, entry.getKey());
errorAppender(logger, entry.getKey());
debugAppender(logger, entry.getKey());
switch (level) {
case "error":
logger.setLevel(Level.ERROR);
break;
case "info":
logger.setLevel(Level.INFO);
break;
case "debug":
logger.setLevel(Level.DEBUG);
break;
default:
logger.setLevel(Level.INFO);
break;
}
loggerTable.put(className, logger);
}
}
public synchronized static Logger createLogger(String className) {
if (loggerTable.containsKey(className)) {
return loggerTable.get(className);
}
Logger logger = (Logger) LoggerFactory.getLogger(className);
String jobName = className.substring(className.lastIndexOf(".") + 1);
infoAppender(logger, jobName);
errorAppender(logger, jobName);
debugAppender(logger, jobName);
logger.setLevel(Level.INFO);
loggerTable.put(className, logger);
return logger;
}
public static void debugAppender(Logger logger, String jobName) {
LoggerContext loggerContext = logger.getLoggerContext();
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setContext(loggerContext);
encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%C] [%M] - %msg%n");
encoder.start();
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(loggerContext);
TimeBasedRollingPolicy rollingPolicyBase = new TimeBasedRollingPolicy<>();
rollingPolicyBase.setContext(loggerContext);
rollingPolicyBase.setParent(appender);
rollingPolicyBase.setFileNamePattern((String.format("logs/jobs/%s/%s", jobName, jobName) + "-debug.%d{yyyy-MM-dd}.%i.log"));
SizeAndTimeBasedFNATP sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP();
sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(10 * FileSize.MB_COEFFICIENT));
rollingPolicyBase.setTimeBasedFileNamingAndTriggeringPolicy(sizeAndTimeBasedFNATP);
rollingPolicyBase.setMaxHistory(10);
rollingPolicyBase.start();
LevelFilter levelFilter = new LevelFilter();
levelFilter.setLevel(Level.DEBUG);
levelFilter.setOnMatch(FilterReply.ACCEPT);
levelFilter.setOnMismatch(FilterReply.DENY);
levelFilter.start();
appender.addFilter(levelFilter);
appender.setEncoder(encoder);
appender.setRollingPolicy(rollingPolicyBase);
appender.start();
logger.setAdditive(false);
logger.addAppender(appender);
}
public static void errorAppender(Logger logger, String jobName) {
LoggerContext loggerContext = logger.getLoggerContext();
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setContext(loggerContext);
encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%C] [%M] - %msg%n");
encoder.start();
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(loggerContext);
TimeBasedRollingPolicy rollingPolicyBase = new TimeBasedRollingPolicy<>();
rollingPolicyBase.setContext(loggerContext);
rollingPolicyBase.setParent(appender);
rollingPolicyBase.setFileNamePattern((String.format("logs/jobs/%s/%s", jobName, jobName) + "-error.%d{yyyy-MM-dd}.%i.log"));
SizeAndTimeBasedFNATP sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP();
sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(10 * FileSize.MB_COEFFICIENT));
rollingPolicyBase.setTimeBasedFileNamingAndTriggeringPolicy(sizeAndTimeBasedFNATP);
rollingPolicyBase.setMaxHistory(10);
rollingPolicyBase.start();
LevelFilter levelFilter = new LevelFilter();
levelFilter.setLevel(Level.ERROR);
levelFilter.setOnMatch(FilterReply.ACCEPT);
levelFilter.setOnMismatch(FilterReply.DENY);
levelFilter.start();
appender.addFilter(levelFilter);
appender.setEncoder(encoder);
appender.setRollingPolicy(rollingPolicyBase);
appender.start();
logger.setAdditive(false);
logger.addAppender(appender);
}
public static void infoAppender(Logger logger, String jobName) {
LoggerContext loggerContext = logger.getLoggerContext();
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setContext(loggerContext);
encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%C] [%M] - %msg%n");
encoder.start();
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(loggerContext);
TimeBasedRollingPolicy rollingPolicyBase = new TimeBasedRollingPolicy<>();
rollingPolicyBase.setContext(loggerContext);
rollingPolicyBase.setParent(appender);
rollingPolicyBase.setFileNamePattern((String.format("logs/jobs/%s/%s", jobName, jobName) + "-info.%d{yyyy-MM-dd}.%i.log"));
SizeAndTimeBasedFNATP sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP();
sizeAndTimeBasedFNATP.setMaxFileSize(new FileSize(10 * FileSize.MB_COEFFICIENT));
rollingPolicyBase.setTimeBasedFileNamingAndTriggeringPolicy(sizeAndTimeBasedFNATP);
rollingPolicyBase.setMaxHistory(10);
rollingPolicyBase.start();
LevelFilter levelFilter = new LevelFilter();
levelFilter.setLevel(Level.INFO);
levelFilter.setOnMatch(FilterReply.ACCEPT);
levelFilter.setOnMismatch(FilterReply.DENY);
levelFilter.start();
appender.addFilter(levelFilter);
appender.setEncoder(encoder);
appender.setRollingPolicy(rollingPolicyBase);
appender.start();
logger.setAdditive(false);
logger.addAppender(appender);
}
}
方法说明:
- initLoggers方法:在系统启动时,完成Logger的初始化,存储到HashTable结构当中,在系统启动阶段完成初始化。
- createLogger方法:在入口类使用此方法获取到logger,并将ThreadLocal变量LOGGER赋值为获取到的logger。
- getLogger方法:在入后方法后的业务逻辑,就可以使用此方法获取到的logger完成日志输出。
详解:
- infoAppender,errorAppender,debugAppender是Logger配置日志输出目录,以及不同日志级别输出到不同的文件。可比较下三个方法的不同之处,即可理解实现逻辑。
- 日志输出格式
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%C] [%M] - %msg%n
,输出的是logger调用的类的路径,有别于传统的配置。