Jakarta Commons Logging (JCL)提供的是一个日志(Log)接口(interface),同时兼顾轻量级和不依赖于具体的日志实现工具。它提供给中间件/日志工具开发者一个简单的日志操做抽象,容许程序开发人员使用不一样的具体日志实现工具。用户被假定已熟悉某种日志实现工具的更高级别的细节。JCL提供的接口,对其它一些日志工具,包括Log4J, Avalon LogKit, and JDK 1.4等,进行了简单的包装,此接口更接近于Log4J和LogKit的实现。html
在Logging系统中,目前框架都是基于相同的设计,即从一个LogFactory中取得一个命名的Log(Logger)实例,而后使用这个Log(Logger)实例打印debug、info、warn、error等不一样级别的日志。做为两个门面日志系统,Commons Logging和SLF4J也一样采用这样的设计。
所谓门面日志系统,是指它们自己并不实现具体的日志打印逻辑,它们只是做为一个代理系统,接收应用程序的日志打印请求,而后根据当前环境和配置,选取一个具体的日志实现系统,将真正的打印逻辑交给具体的日志实现系统,从而实现应用程序日志系统的“可插拔”,便可以经过配置或更换jar包来方便的更换底层日志实现系统,而不须要改变任何代码。我的感受SLF4J的实现更加灵活,而且它还提供了Maker和MDC的接口。java
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
建立commons-logging.properties文件,将其放在classpath下,若是是maven项目则将其放在src/main/resource目录下,配置内容以下git
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
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."); } }
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。github
LogFactory使用动态查找机制进行日志实例化,执行顺序为:common-logging.properties---->系统环境变量------->log4j--->jul--->simplelog---->nooplogapache
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接口。 其输出日志的方法中不进行任何操做。app
1)fatal 很是严重的错误,致使系统停止。指望这类信息能当即显示在状态控制台上。框架
2)error 其它运行期错误或不是预期的条件。指望这类信息能当即显示在状态控制台上。maven
3)warn 使用了不同意使用的API、很是拙劣使用API, '几乎就是'错误, 其它运行时不合须要和不合预期的状态但还不必称为 "错误"。指望这类信息能当即显示在状态控制台上。ide
4)info 运行时产生的有意义的事件。指望这类信息能当即显示在状态控制台上。
5)debug 系统流程中的细节信息。指望这类信息仅被写入log文件中。
6)trace 更加细节的信息。指望这类信息仅被写入log文件中。
org.apache.commons.logging.simplelog.defaultlog=TRACE
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; } }
<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>
在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
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.