• slf4j日志的一些理解


    slf4j的一些理解

    1.log4j

    /**
    * @description: 定制静态日志基础类
    * @author: mufeng
    * @create: 2020/4/7 10:26
    */
    public class BaseLogger {
       static {
           InputStream in = BaseLogger.class.getClassLoader().getResourceAsStream("log4j.properties");
           Properties properties=new Properties();
           try {
               properties.load(in);
               PropertyConfigurator.configure(properties);
               in.close();
               logger = Logger.getLogger("Logger");
          } catch (IOException e) {
               e.printStackTrace();
          }
      }
       private static Logger logger;
       static final String FQCN = BaseLogger.class.getName();
       public static void info(String msg, Object... args){
           if(logger.isInfoEnabled()){
               FormattingTuple ft = MessageFormatter.arrayFormat(msg, args);
               logger.log(FQCN, Level.INFO,ft.getMessage(),ft.getThrowable());
          }
      }
    }
    Logger logger= LoggerFactory.getLogger(Test1.class);
       @Test
       public void test1(){
           BaseLogger.info("12{}","13");
      }
       @Test
       public void test2(){
           logger.info("12{}","13");
      }

    日志输出:

    test1:

    11:05:59,145 INFO Test1:21 - 1213

    test2:

    11:05:59,145 INFO Test1:21 - 1213

    可以看出日志输出是一样的。

    实现原理:

    通过Logger logger= LoggerFactory.getLogger(Test1.class)追溯源代码

    LoggerFactory中 getILoggerFactory执行performInitialization方法,会调用bind方法

    public static ILoggerFactory getILoggerFactory() {
           if (INITIALIZATION_STATE == 0) {
               Class var0 = LoggerFactory.class;
               synchronized(LoggerFactory.class) {
                   if (INITIALIZATION_STATE == 0) {
                       INITIALIZATION_STATE = 1;
                       performInitialization();
                  }
              }
          }

           switch(INITIALIZATION_STATE) {
           case 1:
               return SUBST_FACTORY;
           case 2:
               throw new IllegalStateException("org.slf4j.LoggerFactory in failed state. Original exception was thrown EARLIER. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
           case 3:
               return StaticLoggerBinder.getSingleton().getLoggerFactory();
           case 4:
               return NOP_FALLBACK_FACTORY;
           default:
               throw new IllegalStateException("Unreachable code");
          }
      }

    findPossibleStaticLoggerBinderPathSet找出类路径所有路径集合,StaticLoggerBinder.getSingleton();存在多个会选择一个。(http://www.slf4j.org/codes.html#multiple_bindings解释:by the JVM and for all practical purposes should be considered random)

    日志输出可以看出:

    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/D:/persist/maven_Repositories/org/slf4j/slf4j-log4j12/1.7.26/slf4j-log4j12-1.7.26.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/D:/persist/maven_Repositories/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
    private static final void bind() {
      String msg;
      try {
          Set<URL> staticLoggerBinderPathSet = null;
          if (!isAndroid()) {
              staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
              reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
          }

          StaticLoggerBinder.getSingleton();
          INITIALIZATION_STATE = 3;
          reportActualBinding(staticLoggerBinderPathSet);
          fixSubstituteLoggers();
          replayEvents();
          SUBST_FACTORY.clear();
      } catch (NoClassDefFoundError var2) {
          msg = var2.getMessage();
          if (!messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
              failedBinding(var2);
              throw var2;
          }

          INITIALIZATION_STATE = 4;
          Util.report("Failed to load class "org.slf4j.impl.StaticLoggerBinder".");
          Util.report("Defaulting to no-operation (NOP) logger implementation");
          Util.report("See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.");
      } catch (NoSuchMethodError var3) {
          msg = var3.getMessage();
          if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
              INITIALIZATION_STATE = 2;
              Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
              Util.report("Your binding is version 1.5.5 or earlier.");
              Util.report("Upgrade your binding to version 1.6.x.");
          }

          throw var3;
      } catch (Exception var4) {
          failedBinding(var4);
          throw new IllegalStateException("Unexpected initialization failure", var4);
      }

    }

    得出:logger为Log4jLoggerFactory类getLogger方法得到的实例(Log4jLoggerAdapter)

    public Logger getLogger(String name) {
           Logger slf4jLogger = (Logger)this.loggerMap.get(name);
           if (slf4jLogger != null) {
               return slf4jLogger;
          } else {
               org.apache.log4j.Logger log4jLogger;
               if (name.equalsIgnoreCase("ROOT")) {
                   log4jLogger = LogManager.getRootLogger();
              } else {
                   log4jLogger = LogManager.getLogger(name);
              }

               Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
               Logger oldInstance = (Logger)this.loggerMap.putIfAbsent(name, newInstance);
               return (Logger)(oldInstance == null ? newInstance : oldInstance);
          }
      }

    logger.info()实际调用Log4jLoggerAdapter类中的info方法

    log4j怎么找到log4j.properties配置文件?

    LogManager类存在static静态块,获取了配置信息,LogManager.getLogger(name)获取调起

    (PropertyConfigurator.doConfigure方法解析log4j.properties)
     static {
       // By default we use a DefaultRepositorySelector which always returns 'h'.
       Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
       repositorySelector = new DefaultRepositorySelector(h);

       /** Search for the properties file log4j.properties in the CLASSPATH. */
       String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
          null);

       // if there is no default init override, then get the resource
       // specified by the user or the default config file.
       if(override == null || "false".equalsIgnoreCase(override)) {

         String configurationOptionStr = OptionConverter.getSystemProperty(
     DEFAULT_CONFIGURATION_KEY,
     null);

         String configuratorClassName = OptionConverter.getSystemProperty(
                                                      CONFIGURATOR_CLASS_KEY,
      null);

         URL url = null;

         // if the user has not specified the log4j.configuration
         // property, we search first for the file "log4j.xml" and then
         // "log4j.properties"
         if(configurationOptionStr == null) {
    url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
    if(url == null) {
     url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
    }
        } else {
    try {
     url = new URL(configurationOptionStr);
    } catch (MalformedURLException ex) {
     // so, resource is not a URL:
     // attempt to get the resource from the class path
     url = Loader.getResource(configurationOptionStr);
    }
        }
         
         // If we have a non-null url, then delegate the rest of the
         // configuration to the OptionConverter.selectAndConfigure
         // method.
         if(url != null) {
       LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
           try {
               OptionConverter.selectAndConfigure(url, configuratorClassName,
      LogManager.getLoggerRepository());
          } catch (NoClassDefFoundError e) {
               LogLog.warn("Error during default initialization", e);
          }
        } else {
       LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
        }
      } else {
           LogLog.debug("Default initialization of overridden by " +
               DEFAULT_INIT_OVERRIDE_KEY + "property.");
      }  
    }
  • 相关阅读:
    go-pg库操作PostgreSQL小结
    Python与Golang中实现单例模式
    MySQL与PostgreSQL中解决插入主键冲突的方法
    jemeter
    Java后端面试题集
    java 多线程
    Git入门级必知操作,从拉取到冲突、合并、推送真实流程演示
    一小时,从零实现Java人脸识别功能,opencv
    新入手服务器不会玩?抢占式实例服务器教程,从零搭建tomcat超简流程
    sharding+mybatisplus单库分表部署
  • 原文地址:https://www.cnblogs.com/mufeng07/p/12653301.html
Copyright © 2020-2023  润新知