zoukankan      html  css  js  c++  java
  • 004-log-common-logging,Apache整合日志框架JCL门面框架、JCL+log4j

    一、概述

      Jakarta Commons Logging (JCL)提供的是一个日志(Log)接口(interface),同时兼顾轻量级和不依赖于具体的日志实现工具。它提供给中间件/日志工具开发者一个简单的日志操作抽象,允许程序开发人员使用不同的具体日志实现工具。用户被假定已熟悉某种日志实现工具的更高级别的细节。JCL提供的接口,对其它一些日志工具,包括Log4J, Avalon LogKit, and JDK 1.4等,进行了简单的包装,此接口更接近于Log4J和LogKit的实现。

      在Logging系统中,目前框架都是基于相同的设计,即从一个LogFactory中取得一个命名的Log(Logger)实例,然后使用这个Log(Logger)实例打印debug、info、warn、error等不同级别的日志。作为两个门面日志系统,Commons Logging和SLF4J也同样采用这样的设计。 
    所谓门面日志系统,是指它们本身并不实现具体的日志打印逻辑,它们只是作为一个代理系统,接收应用程序的日志打印请求,然后根据当前环境和配置,选取一个具体的日志实现系统,将真正的打印逻辑交给具体的日志实现系统,从而实现应用程序日志系统的“可插拔”,即可以通过配置或更换jar包来方便的更换底层日志实现系统,而不需要改变任何代码。个人感觉SLF4J的实现更加灵活,并且它还提供了Maker和MDC的接口。

    1.1、pom依赖

            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>

    1.2、配置

      创建commons-logging.properties文件,将其放在classpath下,如果是maven项目则将其放在src/main/resource目录下,配置内容如下

    org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

    1.3、使用

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    public class ApplicationMain {
        private static Log logger = LogFactory.getLog(ApplicationMain.class);
    
        public static void main(String[] args) {
            System.out.println(logger.getClass().getName());
            // 记录debug级别的信息
            logger.debug("This is debug message.");
            // 记录info级别的信息
            logger.info("This is info message.");
            // 记录error级别的信息
            logger.error("This is error message.");
        }
    }

    二、详细说明

        

    2.1、LogFactory获取相对应的Log实现类逻辑

    JCL有两个基本的抽象类:Log(基本记录器)和LogFactory(负责创建Log实例)。当commons-logging.jar被加入到 CLASSPATH之后,它会合理地猜测你想用的日志工具,然后进行自我设置,用户根本不需要做任何设置。默认的LogFactory是按照下列的步骤去发现并决定那个日志工具将被使用的(按照顺序,寻找过程会在找到第一个工具时中止): 
      1. 寻找当前factory中名叫org.apache.commons.logging.Log配置属性的值 
      2. 寻找系统中属性中名叫org.apache.commons.logging.Log的值 
      3. 如果应用程序的classpath中有log4j,则使用相关的包装(wrapper)类(Log4JLogger) 
      4. 如果存在Lumberjack版本的Logging系统,则使用Jdk13LumberjackLogger类。 
      5. 如果应用程序运行在jdk1.4的系统中,使用相关的包装类(Jdk14Logger) 
      6. 使用简易日志包装类(SimpleLog) 
      7. 以上步骤都失败,则抛出LogConfigurationException。

    LogFactory使用动态查找机制进行日志实例化,执行顺序为:common-logging.properties---->系统环境变量------->log4j--->jul--->simplelog---->nooplog

    org.apache.commons.logging.Log的具体实现:

      org.apache.commons.logging.Log的具体实现有如下: 
      - org.apache.commons.logging.impl.Jdk14Logger 使用JDK1.4。 
      - org.apache.commons.logging.impl.Log4JLogger 使用Log4J。 
      - org.apache.commons.logging.impl.LogKitLogger 使用 avalon-Logkit。 
      - org.apache.commons.logging.impl.SimpleLog common-logging自带日志实现类。它实现了Log接口,把日志消息都输出到系统错误流System.err 中。 
      - org.apache.commons.logging.impl.NoOpLog common-logging自带日志实现类。它实现了Log接口。 其输出日志的方法中不进行任何操作。

    2.2、日志级别

    1)fatal 非常严重的错误,导致系统中止。期望这类信息能立即显示在状态控制台上。

    2)error 其它运行期错误或不是预期的条件。期望这类信息能立即显示在状态控制台上。

    3)warn 使用了不赞成使用的API、非常拙劣使用API, '几乎就是'错误, 其它运行时不合需要和不合预期的状态但还没必要称为 "错误"。期望这类信息能立即显示在状态控制台上。

    4)info 运行时产生的有意义的事件。期望这类信息能立即显示在状态控制台上。

    5)debug 系统流程中的细节信息。期望这类信息仅被写入log文件中。

    6)trace 更加细节的信息。期望这类信息仅被写入log文件中。

    如上述配置了SimpleLog,增加simplelog.properties配置文件,放到classpath下,如果是maven则放到src/main/resource目录下,配置内容参考:
    org.apache.commons.logging.simplelog.defaultlog=TRACE
    

    2.3、LogFactory实现原理

      LogFactory作为log的工厂存在,使用动态查找机制进行log实例的获取,具体执行步骤如下:

      ①首先在classpath下寻找commons-logging.properties文件。如果找到,则使用其中定义的Log实现类;如果找不到,则在查找是否已定义系统环境变量org.apache.commons.logging.Log,找到则使用其定义的Log实现类;

      ②查看classpath中是否有Log4j的包,如果发现,则自动使用Log4j作为日志实现类;

      ③使用JDK自身的日志实现类(JDK1.4以后才有日志实现类);

      ④使用commons-logging自己提供的一个简单的日志实现类SimpleLog;

      上述步骤当LogFactory成功找到一个日志实现之后就会停止

      LogFactory的核心步骤在于discoverLogImplementation方法,源码分析如下:

    if (isDiagnosticsEnabled()) {
                this.logDiagnostic("Discovering a Log implementation...");
            }
    
            this.initConfiguration();
            Log result = null;
            //从common-logging.properties文件中提取org.apache.commons.logging.Log这个变量的value
            String specifiedLogClassName = this.findUserSpecifiedLogClassName();
    
            //配置文件中存在该变量则实例化
            if (specifiedLogClassName != null) {
                if (isDiagnosticsEnabled()) {
                    this.logDiagnostic("Attempting to load user-specified log class '" + specifiedLogClassName + "'...");
                }
    
                //核验相应日志对象是否存在
                result = this.createLogFromClass(specifiedLogClassName, logCategory, true);
    
                //如果日志对象不存在,则报错
                if (result == null) {
                    StringBuffer messageBuffer = new StringBuffer("User-specified log class '");
                    messageBuffer.append(specifiedLogClassName);
                    messageBuffer.append("' cannot be found or is not useable.");
                    this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.Log4JLogger");
                    this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.Jdk14Logger");
                    this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.Jdk13LumberjackLogger");
                    this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.SimpleLog");
                    throw new LogConfigurationException(messageBuffer.toString());
                } else {
                    return result;
                }
            } else {
                //当日志文件中不存在该变量时,按照机制遍历classesToDiscover字符串数组
    
                if (isDiagnosticsEnabled()) {
                    this.logDiagnostic("No user-specified Log implementation; performing discovery using the standard supported logging implementations...");
                }
    
                //遍历classesToDiscover字符串数组获取日志实例(动态查找机制)
                for(int i = 0; i < classesToDiscover.length && result == null; ++i) {
                    result = this.createLogFromClass(classesToDiscover[i], logCategory, true);
                }
    
                //到最后仍旧找不到匹配的日志实例,则抛错
                if (result == null) {
                    throw new LogConfigurationException("No suitable Log implementation");
                } else {
                    return result;
                }
            }

    三、common-logging+log4j应用

    3.1、POM依赖

            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>
    
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>

    3.2、配置文件

      在commons-logging.properties文件,将log指向log4j,可以不加因为默认的,没有的话会先加载log4j

    org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

      配置log4j.properties配置【可以参看002-log-log4j

    ### 设置###
    log4j.rootLogger = debug,stdout,D,E
    
    ### 输出信息到控制抬 ###
    log4j.appender.stdout = org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target = System.out
    log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
    
    ### 输出DEBUG 级别以上的日志到 ###
    log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.D.File = log.log
    log4j.appender.D.Append = true
    log4j.appender.D.Threshold = DEBUG 
    log4j.appender.D.layout = org.apache.log4j.PatternLayout
    log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    
    ### 输出ERROR 级别以上的日志到error.log ###
    log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.E.File =error.log 
    log4j.appender.E.Append = true
    log4j.appender.E.Threshold = ERROR 
    log4j.appender.E.layout = org.apache.log4j.PatternLayout
    log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    View Code

    3.2、java代码依旧使用logging代码即可

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    public class ApplicationMain {
        private static Log logger = LogFactory.getLog(ApplicationMain.class);
    
        public static void main(String[] args) {
            System.out.println(logger.getClass().getName());
            // 记录debug级别的信息
            logger.debug("This is debug message.");
            // 记录info级别的信息
            logger.info("This is info message.");
            // 记录error级别的信息
            logger.error("This is error message.");
        }
    }

    输出

    org.apache.commons.logging.impl.Log4JLogger
    [DEBUG] 2019-06-21 14:07:37,823 method:com.github.bjlhx15.common.study.log.ApplicationMain.main(ApplicationMain.java:13)
    This is debug message.
    [INFO ] 2019-06-21 14:07:37,826 method:com.github.bjlhx15.common.study.log.ApplicationMain.main(ApplicationMain.java:15)
    This is info message.
    [ERROR] 2019-06-21 14:07:37,826 method:com.github.bjlhx15.common.study.log.ApplicationMain.main(ApplicationMain.java:17)
    This is error message.

      

  • 相关阅读:
    python网络爬虫之使用scrapy自动爬取多个网页
    流畅的python学习笔记:第五章
    python cookbook第三版学习笔记 一
    python网络爬虫之scrapy 调试以及爬取网页
    python网络爬虫之scrapy 工程创建以及原理介绍
    流畅的python学习笔记:第三章
    python网络爬虫之LXML与HTMLParser
    python 解析docx文档的方法,以及利用Python从docx文档提取插入的文本对象和图片
    【原创】大数据基础之Drill(2)Drill1.14+Hive2.1.1运行
    【原创】大叔问题定位分享(12)Spark保存文本类型文件(text、csv、json等)到hdfs时为什么是压缩格式的
  • 原文地址:https://www.cnblogs.com/bjlhx/p/11064167.html
Copyright © 2011-2022 走看看