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.

  

原文地址:https://www.cnblogs.com/bjlhx/p/11064167.html