05.dubbo日志机制

dubbo对于其日志机制,设计的还是比较灵活的,可以自由配置选用哪种日志框架。这样就能达成跟你的项目所采用的日志框架一致的目的。这是做中间件开发的同学一个值得学习的设计。tomcat是一直到8点几版本才开始能方便的支持不同日志框架的对接。早些版本都是要替换jar之类的办法,还是有一点麻烦的。有些开源框架只支持一种日志框架对接,这样就不是很好了。

入手处

分析其日志机制,从哪边入手呢?随便翻一个其用到日志的类,就可以作为入口了。比如我们前面刚讲过的ExtensionLoader。


private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);

public interface Logger {}

public class LoggerFactory {}

日志机制实现分析

Logger是一个接口。dubbo为其做了Log4jLogger、Slf4jLogger、JdkLogger等实现。

LoggerFactory的getLogger主要由LoggerAdapter(LOGGER_ADAPTER)完成。LoggerAdapter有对应slf4j、log4j等实现。

public static Logger getLogger(Class<?> key) {
  FailsafeLogger logger = LOGGERS.get(key.getName());
  if (logger == null) {
    LOGGERS.putIfAbsent(key.getName(), new FailsafeLogger(LOGGER_ADAPTER.getLogger(key)));// LOGGER_ADAPTER完成Logger实例的获取
    logger = LOGGERS.get(key.getName());
  }
  return logger;
}

那LOGGER_ADAPTER是什么时候什么逻辑指定的呢?

LoggerFactory的static块中指定的:


static {
	    String logger = System.getProperty("dubbo.application.logger");// 根据指定的日志框架名称设置LOGGER_ADAPTER
	    if ("slf4j".equals(logger)) {
    		setLoggerAdapter(new Slf4jLoggerAdapter());
    	} else if ("jcl".equals(logger)) {
    		setLoggerAdapter(new JclLoggerAdapter());
    	} else if ("log4j".equals(logger)) {
    		setLoggerAdapter(new Log4jLoggerAdapter());
    	} else if ("jdk".equals(logger)) {
    		setLoggerAdapter(new JdkLoggerAdapter());
    	} else {
    		try {
    			setLoggerAdapter(new Log4jLoggerAdapter());
            } catch (Throwable e1) {
                try {
                	setLoggerAdapter(new Slf4jLoggerAdapter());
                } catch (Throwable e2) {
                    try {
                    	setLoggerAdapter(new JclLoggerAdapter());
                    } catch (Throwable e3) {
                        setLoggerAdapter(new JdkLoggerAdapter());
                    }
                }
            }
    	}
	}

public static void setLoggerAdapter(LoggerAdapter loggerAdapter) {
		if (loggerAdapter != null) {
			Logger logger = loggerAdapter.getLogger(LoggerFactory.class.getName());
			logger.info("using logger: " + loggerAdapter.getClass().getName());
			LoggerFactory.LOGGER_ADAPTER = loggerAdapter; // 设置LOGGER_ADAPTER
			for (Map.Entry<String, FailsafeLogger> entry : LOGGERS.entrySet()) {
				entry.getValue().setLogger(LOGGER_ADAPTER.getLogger(entry.getKey()));
			}
		}
	}