java日志篇(4)-common-logging

慢慢来比较快,虚心学技术

前言:Jakarta Commons-logging(JCL)是apache最早提供的日志的门面接口。它将一些具体的日志组件抽象为接口,实现日志操作的解耦和可插拔,让众多的日志工具有一个共同的操作方式

一、common-logging简单使用示例

①引入common-logging的jar包,最新jar包从官方网站http://commons.apache.org/proper/commons-logging/download_logging.cgi进行下载,下载后将jar包放到lib中引入项目即可。

如果是maven项目在pom文件中添加依赖如下:



   commons-logging
   commons-logging
   1.2

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

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

③在项目程序中使用logger开发

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CommonsTest {

    //获取logger
    private final static Log logger = LogFactory.getLog(CommonsTest.class);

    public static void main(String[] args) {
        //使用logger输出日志
        logger.trace("TRACE...");
        logger.debug("DEBUG ...");
        logger.info("INFO ...");
        logger.error("ERROR ...");
        logger.warn("WARN...");
    }
}

运行输出结果:

[INFO] CommonsTest - INFO ...
[ERROR] CommonsTest - ERROR ...
[WARN] CommonsTest - WARN...

如上实现第一个简单的common-logging程序,引发以下几个问题

问题一:common-logging.properties属性文件中的org.apache.commons.logging.Log和它的值代表了什么?

问题二:为什么明明代码中写了logger.trace和logger.debug,却没有输出?

问题三:LogFactory的实现原理是什么?

带着问题去思考学习,效率总是最高的

二、问题探索

1.org.apache.commons.logging.Log

JCL有两个基本的抽象类: Log( 基本记录器 ) 和 LogFactory( 负责创建 Log 实例 ),其中,Log有多个默认实现类,分别是:

-org.apache.commons.logging.impl.Jdk14Logger 使用JUL。
-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接口。 其输出日志的方法中不进行任何操作。

在common-logging.properties中配置的org.apache.commons.logging.Log参数指定了common-logging将使用哪种日志实现,这也是前言所说的,通过配置实现日志组件的可插拔和解耦,极大增加了灵活性

2.common-logging日志级别

common-logging日志级别从高到低如下:

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

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

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

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

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

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

apache建议使用4级,即 ERRORWARNINFODEBUG

而当我们在common-logging.properties配置使用的是SimpleLog日志实现,该日志实现默认日志级别是info,所以才会出现简单实例中的输出结果,如何更改SimpleLog的日志级别?

创建simplelog.properties配置文件,放到classpath下,如果是maven则放到src/main/resource目录下,配置内容参考:

org.apache.commons.logging.simplelog.defaultlog=TRACE

配置后结果输出如下(bingo):

[TRACE] CommonsTest - TRACE...
[DEBUG] CommonsTest - DEBUG ...
[INFO] CommonsTest - INFO ...
[ERROR] CommonsTest - ERROR ...
[WARN] CommonsTest - WARN...

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应用

log4j功能强大,为了解耦和减少依赖,大部分的项目都会使用common-logging+log4j的组合进行开发,使用起来也是十分的简单:

①引入log4j的jar包,最新jar包从官方网站http://logging.apache.org/log4j/1.2/download.html进行下载,下载后将jar包放到lib中引入项目即可。

如果是maven项目在pom文件中添加依赖如下:


   log4j
   log4j
   1.2.17

②在common-logging.properties文件,将log指向log4j

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

③创建log4j.properties文件,并将文件放在classpath下,如果是maven则放在source/main/resource目录下,简单配置如下:

#配置rootLogger
log4j.rootLogger=all,appender1

#配置第一个appender
log4j.appender.appender1=org.apache.log4j.FileAppender
#配置文件输出样式
log4j.appender.appender1.layout = org.apache.log4j.PatternLayout
log4j.appender.appender1.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
#指定仅记录ERROR以上级别的日志
log4j.appender.appender1.Threshold = ERROR
log4j.appender.appender1.ImmediateFlush = TRUE
#指定将日志累加到日志文件末尾
log4j.appender.appender1.Append = TRUE
#指定日志文件
log4j.appender.appender1.File = ./Common-logging-Modle/log/error.log
log4j.appender.appender1.Encoding = UTF-8

④运行代码不变,结果如下:

error.log

[ERROR][2019/01/31 17:56:13569][com.log.CommonsTest.main(CommonsTest.java:16)]
ERROR ...

总结

1.尽可能将可配置的内容抽离作为配置,而不是在代码中做更改,可以极大增强系统灵活性

2.common-logging的日志级别分为六个,默认级别为info,apache推荐使用四个级别:ERRORWARNINFODEBUG

3.common-logging的关键类log有5个基本实现类,分别是org.apache.commons.logging.impl.Jdk14Logger,org.apache.commons.logging.impl.Log4JLogger,org.apache.commons.logging.impl.LogKitLogger,org.apache.commons.logging.impl.SimpleLog,org.apache.commons.logging.impl.NoOpLog

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

参考文档:

【1】官方文档

【2】https://blog.csdn.net/backbug/article/details/78655664

【3】https://www.jianshu.com/p/b818d9d26d39

你可能感兴趣的:(java日志篇(4)-common-logging)