log4j2(三) 如何通过类名获取到logger呢?logger与loggerConfig是什么关系?-源码解析

本文详细解析了log4j2中通过类名获取logger的过程,探讨Logger与LoggerConfig的关系。从LoggerFactory开始,经过LoggerContext和缓存,最终找到LoggerConfig的创建。解释了为何会存在非本项目的日志,以及如何去除不必要的包日志,同时揭示logger名称对应指定package或类的原理。
摘要由CSDN通过智能技术生成

情景

之所以想写这篇文章是因为经常看到一些相关联的问题:

  • 怎么有这么多非本项目的log出现? 譬如引入了其他的sdk,他们又很无节操的打了很多日志。
  • 怎么去除不必要的包的日志?
  • 为什么logger的名字能对应到指定的package或者类呢?

以上这些问题都是因为没搞明白,log4j是怎么去获取logger的,本文将通过 slf4j-log4j-impl 根据class去查找logger的过程来解答上述的疑问。

解析

从例子说起

  • 打印日志的例子
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloWorld {
   
  public static void main(String[] args) {
   
    Logger logger = LoggerFactory.getLogger(HelloWorld.class);
    logger.info("Hello World");
  }
}
  • 深入到LoggerFactory.getLogger方法
	public static Logger getLogger(Class<?> clazz) {
   
        Logger logger = getLogger(clazz.getName());
        if (DETECT_LOGGER_NAME_MISMATCH) {
   
           	//省略部分打印信息的代码...
        }
        return logger;
    }

这个DETECT_LOGGER_NAME_MISMATCH是什么意思呢,就是第一步中的参数并不是当前这个类的时候, 如果这个配置为true,则会打印一条类似下面的信息:

SLF4J: Detected logger name mismatch. Given name: "com.keven.demos.log.TestNameMismatch"; computed name: "com.keven.demos.log.AsyncLoggerDemo".
SLF4J: See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation

从LoggerFactory获取logger

  • 我们接着看getLogger方法:
//此处变成通过class的全名(package name + class name)获取logger
 public static Logger getLogger(Class<?> clazz) {
   
        Logger logger = getLogger(clazz.getName());
        //省略非关键部分代码...
 }
 //这里就是说通过slf4j的实现类的loggerFactory获取logger
 //如何获取实现类的logger factory,这个在之前的文章中已经分析过了,有兴趣的同学可以看看
 //https://blog.csdn.net/sweetyi/article/details/104633321
 public static Logger getLogger(String name) {
   
      ILoggerFactory iLoggerFactory = getILoggerFactory();
      return iLoggerFactory.getLogger(name);
 }

从LoggerContext中获取logger

  • 在这里ILoggerFactory的实现类是:org.apache.logging.slf4j.Log4jLoggerFactory, 这个工厂类中没有getLogger方法,它会调用父类AbstractLoggerAdapter的getLogger方法,如下:
	public L getLogger(final String name) {
   
		//获取logger配置的上下文,这里不展开
        final LoggerContext context = getContext();
        //这里是做一层logger的缓存
        final ConcurrentMap<String, L> loggers = getLoggersInContext(context);
        //根据名字获取logger
        final L logger = loggers.get(name);
        if (logger != null) {
   
            return logger;
        }
        //没找到现成的logger,重新生成一个
        loggers.putIfAbsent(name, newLogger(name, context));
        return loggers.get(name);
    }
  • getLoggersInContext方法是用来获取context所对应的logger的内存缓存, 以下省略了用读写锁加解锁的代码,不是重点。
	/**
     * A map to store loggers for their given LoggerContexts.
     * context可能有多个,所需要找出的是对应context的缓存
     */
    protected final Map<LoggerContext, ConcurrentMap<String, L>> registry = new WeakHashMap<>();

	public ConcurrentMap
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值