log4j2 自定义封装

如果使用工具类进行封装,减少 类似

private static Logger logger = LogFactory.getLogger(XXX.class);

的定义,也不使用注解@Slf4j

可以在工具类中添加静态代码库解决此问题,示例代码如下


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.util.StackLocatorUtil;
import org.springframework.boot.SpringApplication;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

class LOG {

    public static void main(String[] args) {
        // 一般的 apps
        useProps("conf/log4j.properties");
        // do something

        // spring apps 需要添加运行参数
        // java -jar XXX.jar --spring.config.location=file:conf/
        SpringApplication.run(LOG.class, args);
        useProps("conf/log4j.properties");
    }
    
    public static final String TRACE = "trace";
    public static final String DEBUG = "debug";
    public static final String INFO = "info";
    public static final String WARN = "warn";
    public static final String ERROR = "error";

    public static void error(String msg) {
        log(ERROR, msg);
    }

    public static void error(String format, Object... args) {
        log(ERROR, format, args);
    }

    public static void info(String msg) {
        log(INFO, msg);
    }

    public static void info(String format, Object... args) {
        log(INFO, format, args);
    }

    static void log(String level, String format, Object... args) {
        log(level, StrUtils.format(format, args));
    }

    private static void log(String lvl, String msg) {
        Logger logger = getLogger();
        switch (lvl) {
            case TRACE:
                logger.trace(msg);
                break;
            default:
                logger.info(msg);
                break;
        }
    }

    public static Logger getLogger() {
        final Class<?> module = getCallerClass(10);
        return (Logger) LogManager.getLogger(module.getName());
    }

    private static Class<?> getCallerClass(int limit) {
        while (limit-- > 0) {
            if (StackLocatorUtil.getCallerClass(limit) == LOG.class) break;
        }
        return StackLocatorUtil.getCallerClass(limit + 1);
    }

    private static final String FQCN = LOG.class.getName();

    static {
        try {
            Field field = AbstractLogger.class.getDeclaredField("FQCN");
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
            field.setAccessible(true);
            field.set(null, FQCN);
            modifiersField.setInt(field, field.getModifiers() & Modifier.FINAL);
        } catch (Exception e) {
            System.out.println(StrUtils.format("modify FQCN to {} failed, err:{}", FQCN, StrUtils.errStr(e)));
        }
    }

    public static void useProps(String configFile) {
        try {
            if (Utils.exist(configFile)) {
                LoggerContext logContext = (LoggerContext) LogManager.getContext(false);
                logContext.setConfigLocation(new File(configFile).toURI());
                logContext.reconfigure();
                info("log4j2 conf file:{}", FileUtils.readAll(configFile).replaceAll("\\s+", " "));
            }
        } catch (Exception e) {
            error("can not configure log4j2, err:{}", StrUtils.errStr(e));
        }
    }
}

解决了打印代码位置时全部都是工具类位置的问题

原理是,log4j2 中 默认实现为org.apache.logging.log4j.core.Logger;继承自org.apache.logging.log4j.spi.AbstractLogger;打印时loggerName由LogManager.getLogger的传参决定,行号位置信息由AbstractLogger中的代码寻找第一个类名不是AbstractLogger.FQCN的调用堆栈决定,是故通过反射修改此值,即可找到正确的调用堆栈。

支持log4j2.properties 配置文件外置 

原理是, (LoggerContext) LogManager.getContext(false); 可获取日志组件上下文;logContext.setConfigLocation(new File(configFile).toURI()); 可绑定日志的配置文件,; logContext.reconfigure(); 可手动触发配置重载。如需实现配置热更新,可以自己写一个文件监听的thread,每X分钟检测文件是否更新时间发生变化,如变化则重载。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值