zoukankan      html  css  js  c++  java
  • Java 日志组件(一)

        作为一名Java程序员,日常开发中很定会接触日志系统,但是众多的框架,包括Log4j、Log4j2、Logback、Slf4j、commons-logging等等,引用的maven依赖众多,到底可以去掉哪些,一行Loggerfactory.getLogger(LogbackTest.class)后做了

      哪些工作,怎么去找的配置文件,这还是有很多细节可以研究的。

        目前日志框架有jdk自带的logging、log4j、logback,目前用于实现日志统一的框架Apache的commons-logging、slf4j。为了理清它们的关系与繁杂的各种集成jar包如下:

        • log4j、log4j-api、log4j-core
        • log4j-1.2-api、log4j-jcl、log4j-slf4j-impl、log4j-jul
        • logback-core、logback-classic、logback-access
        • commons-logging
        • slf4j-api、slf4j-log4j12、slf4j-simple、jcl-over-slf4j、slf4j-jdk14、log4j-over-slf4j、slf4j-jcl

    1、jdk自带的logging

      1.1、使用案例:

    1 private static final Logger logger=Logger.getLogger(JdkLoggingTest.class.getName());
    2 
    3 public static void main(String[] args){
    4     logger.info("jdk logging info: a msg");
    5 }

        其中的Logger是:java.util.logging.Logger

      1.2、简单的过程分析:

    • 创建一个LogManager

       默认是java.util.logging.LogManager,但是也可以自定义,修改系统属性“java.util.logging.manager”即可,源码如下:

     1 try {
     2     cname = System.getProperty("java.util.logging.manager");
     3     if (cname != null) {
     4         try {
     5             Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
     6             manager = (LogManager) clz.newInstance();
     7         } catch (ClassNotFoundException ex) {
     8             Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
     9             manager = (LogManager) clz.newInstance();
    10         }
    11     }
    12 } catch (Exception ex) {
    13     System.err.println("Could not load Logmanager "" + cname + """);
    14     ex.printStackTrace();
    15 }
    16 if (manager == null) {
    17     manager = new LogManager();
    18 }
    • 加载配置文件

         默认是jre目录下的lib/logging.properties文件,也可以自定义修改系统属性“java.util.logging.file”,源码如下:

    String fname = System.getProperty("java.util.logging.config.file");
    if (fname == null) {
        fname = System.getProperty("java.home");
        if (fname == null) {
            throw new Error("Can't find java.home ??");
        }
        File f = new File(fname, "lib");
        f = new File(f, "logging.properties");
        fname = f.getCanonicalPath();
    }
    InputStream in = new FileInputStream(fname);
    BufferedInputStream bin = new BufferedInputStream(in);
    try {
        readConfiguration(bin);
    }
    •  创建logger,并缓存起来,放置到一个Hashtable中,并把LogManager设置进新创建的logger中。

      以tomcat为例,它就自定义了上述配置:

      在tomcat的启动文件中catalina.bat中,有如下设置:

    •  修改属性"java.util.logging.manager",自定义LogManager,使用自己的ClassLoaderLogManager
    1 if not "%LOGGING_MANAGER%" == "" goto noJuliManager
    2 set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
    3 :noJuliManager
    4 set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%
    • 修改属性"java.util.logging.config.file",自定义配置文件,使用自己的%CATALINA_BASE%conflogging.properties文件
    1 if not "%LOGGING_CONFIG%" == "" goto noJuliConfig
    2 set LOGGING_CONFIG=-Dnop
    3 if not exist "%CATALINA_BASE%conflogging.properties" goto noJuliConfig
    4 set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%conflogging.properties"
    5 :noJuliConfig
    6 set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%

      所以如果想研究tomcat的日志,可以从上面入手。

    2、log4j

      2.1、使用案例

      log4j的maven依赖

    1 <dependency>
    2     <groupId>log4j</groupId>
    3     <artifactId>log4j</artifactId>
    4     <version>1.2.17</version>
    5 </dependency>

      编写log4j.properties配置文件,放到类路径下

    1 log4j.rootLogger = debug, console
    2 log4j.appender.console = org.apache.log4j.ConsoleAppender
    3 log4j.appender.console.layout = org.apache.log4j.PatternLayout
    4 log4j.appender.console.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} %m%n

      示例代码:

     1 public class Log4jTest {
     2     private static final Logger logger=Logger.getLogger(Log4jTest.class);
     3     public static void main(String[] args){
     4         if(logger.isTraceEnabled()){
     5             logger.debug("log4j trace message");
     6         }
     7         if(logger.isDebugEnabled()){
     8             logger.debug("log4j debug message");
     9         }
    10         if(logger.isInfoEnabled()){
    11             logger.debug("log4j info message");
    12         }
    13     }
    14 }

      补充:上述方式默认到类路径下加载log4j.properties配置文件,如果配置文件不在类路径下,可以选择如下加载方式来加载配置文件:

    1 //使用classLoader来加载资源
    2 PropertyConfigurator.configure(Log4jTest.class.getClassLoader().getResource("properties/log4j.properties"));
    3 
    4 //使用log4j自带的Loader来加载资源
    5 PropertyConfigurator.configure(Loader.getResource("properties/log4j.properties"));

      2.1、获取Logger的原理  

      简单说明Logger获取的过程:

    • 没有指定配置文件路径

        1、LogManager初始化:

    1 static public Logger getLogger(Class clazz) {
    2     return LogManager.getLogger(clazz.getName());
    3 }

        2、初始化一个Logger仓库Hierarchy

    1 public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
    2       private LoggerFactory defaultFactory;
    3       Hashtable ht;
    4       Logger root;
    5     //其他略
    6 }

        LoggerFactory defaultFactory就是创建的Logger工厂

        Hashtable ht用来存放上述工厂创建的Logger

        Logger root作为根Logger

        LoggerManager在初始化的时候使用如下方式初始化Hierarchy

    1 static {
    2     Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
    3     //
    4 }

        new RootLogger作为root logger,默认是debug级别,最后把Hierarchy绑定到LogManager上,可以在任何地方来获取这个logger仓库Hierarchy

        3、在LogManager的类初始化的过程中默认寻找类路径下的配置文件,优先加载xml配置

    1 Loader.getResource("log4j.xml");
    2 Loader.getResource("log4j.properties")

        4、解析上述配置文件

        5、获取Logger

    • 手动加载不在类路径下的配置文件

        PropertyConfigurator.configure 执行时会去进行上述的配置文件解析,源码如下:

    1 public static void configure(java.net.URL configURL) {
    2      new PropertyConfigurator().doConfigure(configURL,
    3                         LogManager.getLoggerRepository());
    4 }
      • 仍然先会引发LogManager的类加载,创建出logger仓库Hierarchy,同时尝试加载类路径下的配置文件,此时没有则不进行解析,此时logger仓库Hierarchy中的RootLogger默认采用debug级别,没有appender而已。

      • 然后解析配置文件,对上述logger仓库Hierarchy的RootLogger进行级别的设置,添加appender

      • 此时再去调用Logger.getLogger,不会导致LogManager的类初始化(因为已经加载过了)

    • 配置文件在类路径下,而我们又手动使用PropertyConfigurator去加载

          也就会造成2次加载解析配置文件,仅仅会造成覆盖而已(对于RootLogger进行从新设置级别,删除原有的appender,重新加载新的appender),所以多次加载解析配置文件以最后一次为准。

      2.3、主要对象的总结

        • LogManager: 它的类加载会创建logger仓库Hierarchy,并尝试寻找类路径下的配置文件,如果有则解析

        • Hierarchy : 包含三个重要属性:

          • LoggerFactory logger的创建工厂
          • Hashtable 用于存放上述工厂创建的logger
          • Logger root logger,用于承载解析文件的结果,设置级别,同时存放appender
        • PropertyConfigurator: 用于解析log4j.properties文件

        • Logger : 我们用来输出日志的对象

  • 相关阅读:
    玩转TypeScript(2) --简单TypeScript类型
    玩转TypeScript(1) --定义简单的类
    在WisOne平台上学习TypeScript
    为juggle添加了一个js扩展
    和大家分享一个abelkhan的demo
    全服排行榜算法思路
    abelkhan中的rpc框架
    abelkhan编译文档
    abelkhan服务器框架
    一起学习c++11——c++11中的新增的容器
  • 原文地址:https://www.cnblogs.com/ouhouki/p/10060556.html
Copyright © 2011-2022 走看看