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
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.
004-log-common-logging,Apache整合日志框架JCL门面框架、JCL+log4j的更多相关文章
- 使用Common.Logging+log4net规范日志管理【转载】
使用Common.Logging+log4net规范日志管理 Common.Logging+(log4net/NLog/) common logging是一个通用日志接口,log4net是一个强大 ...
- 使用Common.Logging+log4net规范日志管理
Common.Logging+(log4net/NLog/) common logging是一个通用日志接口,log4net是一个强大的具体实现,也可以用其它不同的实现,如EntLib的日志.NLog ...
- 基于Common.Logging + Log4Net实现的日志管理
前言 Common.Logging 是Commons-Logging(apache最早提供的日志门面接口,提供了简单的日志实现以及日志解耦功能) 项目的.net版本.其目的是为 "所有的.n ...
- 在C#应用中使用Common Logging日志接口
我在C#应用中一般使用log4net来记录日志,但如果项目中有个多个工程,那么没有工程都需要引用log4neg,感觉很不爽.不过今日在开spring.net的时候,看到了有个通用日志接口Common ...
- SpringBoot整合日志log4j2
SpringBoot整合日志log4j2 一个项目框架中日志都是必不可少的,随着技术的更新迭代,SpringBoot被越来越多的企业所采用.这里简单说说SpringBoot整合log2j2日志. 一. ...
- Common.Logging log4net Common.Logging.Log4Net 配置
1.log4net 单独配置 log4net支持多种格式的日志输出,我这里只配置输出到本地的txt文件这种格式. <log4net> <root> <appender-r ...
- Common.Logging源码解析二
Common.Logging源码解析一分析了LogManager主入口的整个逻辑,其中第二步生成日志实例工厂类接口分析的很模糊,本随笔将会详细讲解整个日志实例工厂类接口的生成过程! (1).关于如何生 ...
- 【SpringBoot】整合日志框架
一.日志框架概述 1.1 日志框架的产生 1.2 市面上的日志框架 二.SLF4j 使用与整合 2.1 如何在系统中使用SLF4j 2.2 如何整合日志框架 2.3 SpringBoot中的日志关系 ...
- How To Configure Logging And Log Rotation In Apache On An Ubuntu VPS
Introduction The Apache web server can be configured to give the server administrator important info ...
随机推荐
- 使用MySQL审计Plugin
本文来源:http://blog.chinaunix.net/uid-20785090-id-5018977.html 越来越多的企业把应用往mysql上迁移,这时候对数据库的审计又成了一件紧急的事情 ...
- Computer Vision_18_Image Stitching:Automatic Panoramic Image Stitching using Invariant Features——2007
此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...
- Java学习第二天之Java程序的基本规则
一.Java程序的组织形式 Java程序是一种纯粹的面向对象的程序设计语言,因此Java程序必须以类(即class)的形式存在,类(class)是Java程序的最小程序单位.Java程序不允许可执行性 ...
- deep_learning_Github_初学者教程
Github_link_from:https://github.com/lawlite19/MachineLearning_Python 机器学习算法Python实现 目录 机器学习算法Python实 ...
- Python内存数据序列化到硬盘上哪家强
1. 闲扯一下:文件 磁盘上的数据,我们一般称为 “文件” ,一般不同的文件都有各自的后缀名,比如 .txt .docx .xlsx .jpg .mp3 .avi .这些不同类型的文件一般分为两大类: ...
- less混合
混合(mixin)变量 .border{ border: 5px solid pink; } .box{ width: 300px;height:300px; .border; } => .bo ...
- python3 基础二——基本的数据类型三
一.字符串str 1.创建字符串,为变量分配一个值 word='字符串' sentence="字符串\n" #python中单引号和双引号使用完全相同 paragraph=&quo ...
- linux下18种监测网络带宽方式
1. nload nload是一个命令行工具,让用户可以分开来监控入站流量和出站流量.它还可以绘制图表以显示入站流量和出站流量,视图比例可以调整.用起来很简单,不支持许多选项. 所以,如果你只需要快速 ...
- SmtpClient 发送邮件
利用SmtpClient 代码发送邮件. 简单测试代码: static void Main(string[] args) { MailMessage msg = new MailMessage(); ...
- IdentityServer(三)密码模式
前言 用户名密码模式相较于客户端凭证模式,多了用户.通过用户的用户名和密码向Identity Server申请访问令牌.密码模式有两种实现方式. 1.把用户写进内存Identity从中读取账号密码验证 ...