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。在common-logging.properties中配置的org.apache.commons.logging.Log参数指定了common-logging将使用哪种日志实现,这也是前言所说的,通过配置实现日志组件的可插拔和解耦,极大增加了灵活性
-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.common-logging日志级别
common-logging日志级别从高到低如下:
1)fatal 非常严重的错误,导致系统中止。期望这类信息能立即显示在状态控制台上。apache建议使用4级,即 ERROR、WARN、INFO、DEBUG
2)error 其它运行期错误或不是预期的条件。期望这类信息能立即显示在状态控制台上。
3)warn 使用了不赞成使用的API、非常拙劣使用API, '几乎就是'错误, 其它运行时不合需要和不合预期的状态但还没必要称为 "错误"。期望这类信息能立即显示在状态控制台上。
4)info 运行时产生的有意义的事件。期望这类信息能立即显示在状态控制台上。
5)debug 系统流程中的细节信息。期望这类信息仅被写入log文件中。
6)trace 更加细节的信息。期望这类信息仅被写入log文件中。
而当我们在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
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 2018年11月19日|2018年11月19日 星期一 亲子日记第144篇
- 《魔法科高中的劣等生》第26卷(Invasion篇)发售
- 拍照一年啦,如果你想了解我,那就请先看看这篇文章
- 事件代理
- 亲子日记第186篇,2018、7、26、星期四、晴
- 日志打卡
- Java|Java OpenCV图像处理之SIFT角点检测详解
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)
- java中如何实现重建二叉树