java日志篇(4)-common-logging

慢慢来比较快,虚心学技术
【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级,即 ERROR、WARN、INFO、DEBUG
而当我们在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推荐使用四个级别:ERROR、WARN、INFO、DEBUG
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

    推荐阅读