自定义Logger实现方案

自定义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 = new ThreadLocal<>();

    private static Hashtable loggerTable = new Hashtable<>();

    public static Logger getLogger() {
        return LOGGER_FACTORY.get();
    }

    public static void initLoggers(Map jobMap, String level) {
        for (Map.Entry 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);
    }
}

方法说明:

  1. initLoggers方法:在系统启动时,完成Logger的初始化,存储到HashTable结构当中,在系统启动阶段完成初始化。
  2. createLogger方法:在入口类使用此方法获取到logger,并将ThreadLocal变量LOGGER赋值为获取到的logger。
  3. getLogger方法:在入后方法后的业务逻辑,就可以使用此方法获取到的logger完成日志输出。

详解:

  1. infoAppender,errorAppender,debugAppender是Logger配置日志输出目录,以及不同日志级别输出到不同的文件。可比较下三个方法的不同之处,即可理解实现逻辑。
  2. 日志输出格式%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%C] [%M] - %msg%n,输出的是logger调用的类的路径,有别于传统的配置。

你可能感兴趣的:(工具,自定义日志输出方案)