log4j+commons-logging结合使用

时间:2021-02-24 22:01:09

1.参考文献:

  1. Apache Commons-logging使用实例
  2. Apache Log4j配置说明
  3. log4j.properties配置详解
  4. commons-logging结合Log4j的问题
  5. Properties文件相关
  6. Apache通用日志工具commons-logging和Log4j使用总结

2.Commons-Loggin简介

Apache针对不同的语言平台为做了一系列日志工具包,可应用于java、.net、php、c++,这些日志包都是免费的,使用非常方便,可以极大提高编程效率。并且,Apache为了让众多的日志工具有一个相同操作方式,还实现做了一个通用日志工具包:commons-logging,也称Jakarta Commons Logging (JCL)。commons-logging是为那些需要建立在不同环境下使用不同日志架构的组件或库的开发者创建的,其中包括Apache Log4j以及Java log的日志架构。把日志信息commons-logging的Log接口,并由commons-logging在运行时决定使用哪种日志架构。现在,Apache通用日志工具commons-logging和Log4j已经成为Java日志的标准工具。

3.快速入门

JCL有两个基本的抽象类:Log(基本记录器)和LogFactory(负责创建Log实例)。当commons-logging.jar被加入到CLASSPATH(通常将commons-logging.jar放在web project下的WebContent\WEB-INF\lib目录中)之后,它会合理地猜测你想用的日志工具,然后进行自我设置,用户根本不需要做任何设置。默认的LogFactory是按照下列的步骤去发现并决定那个日志工具将被使用的(按照顺序,寻找过程会在找到第一个工具时中止,这个顺序非常重要):

  1. 寻找当前factory中名叫org.apache.commons.logging.Log配置属性的值
  2. 寻找系统中属性中名叫org.apache.commons.logging.Log的值
  3. 如果应用程序的classpath中有log4j,则使用相关的包装(wrapper)类(Log4JLogger)
  4. 如果应用程序运行在jdk1.4的系统中,使用相关的包装类(Jdk14Logger)
  5. 使用简易日志包装类(SimpleLog)
上述的加载顺序可以通过commons-logging中LogSource.java的源代码可以看出,源代码如下,具体可以参考注释:
package log.sample;

public class ca {
static {
// Is Log4J Available?用户Log4J是否可用
try {
/**
* 通过Class.forName("org.apache.log4j.Logger"))来查找Log4J,
* 只有将log4j.jar添加到classpath以后才能找到,
* 这也是为什么默认情况下只要将log4j.jar文件放在lib文件夹中
* 而不需要在common-logging.properties配置文件中进行配置就能自动使用log4j的原因
*/
if (null != Class.forName("org.apache.log4j.Logger")) {
log4jIsAvailable = true;
} else {
log4jIsAvailable = false;
}
} catch (Throwable t) {
log4jIsAvailable = false;
}

// Is JDK 1.4 Logging Available?原来同上面的Log4J
try {
if ((null != Class.forName("java.util.logging.Logger")) &&
(null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger"))) {
jdk14IsAvailable = true;
} else {
jdk14IsAvailable = false;
}
} catch (Throwable t) {
jdk14IsAvailable = false;
}

// Set the default Log implementation,通过common-logging.properties配置文件来决定日志实现方式
String name = null;
try {
name = System.getProperty("org.apache.commons.logging.log");
if (name == null) {
name = System.getProperty("org.apache.commons.logging.Log");
}
} catch (Throwable t) {
}
if (name != null) {
try {
setLogImplementation(name);
} catch (Throwable t) {
try {
setLogImplementation
("org.apache.commons.logging.impl.NoOpLog");
} catch (Throwable u) {
;
}
}
} else {
try {
if (log4jIsAvailable) {//如果log4j可用,默认优先使用Log4JLogger
setLogImplementation
("org.apache.commons.logging.impl.Log4JLogger");
} else if (jdk14IsAvailable) {//第二优先使用Jdk14Logger
setLogImplementation
("org.apache.commons.logging.impl.Jdk14Logger");
} else {//最后使用commoms-logging中的自带的实现,但它不进行任何操作
setLogImplementation
("org.apache.commons.logging.impl.NoOpLog");
}
} catch (Throwable t) {
try {
setLogImplementation
("org.apache.commons.logging.impl.NoOpLog");
} catch (Throwable u) {
;
}
}
}

}
}
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.Log4JCategoryLog:使用Log4J,该实现已被弃用,推荐使用Log4JLogger
  • -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接口。 其输出日志的方法中不进行任何操作。

4.信息级别

  确保日志信息在内容上和反应问题的严重程度上的恰当,是非常重要的。log4j主要有如下的信息级别:

  1. fatal:非常严重的错误,导致系统中止。期望这类信息能立即显示在状态控制台上。
  2. error:其它运行期错误或不是预期的条件。期望这类信息能立即显示在状态控制台上。
  3. warn:使用了不赞成使用的API、非常拙劣使用API, '几乎就是'错误, 其它运行时不合需要和不合预期的状态但还没必要称为 "错误"。期望这类信息能立即显示在状态控制台上。
  4. info:运行时产生的有意义的事件。期望这类信息能立即显示在状态控制台上。
  5. debug:系统流程中的细节信息。期望这类信息仅被写入log文件中。
  6. trace:更加细节的信息。期望这类信息仅被写入log文件中。

  通常情况下,我们希望将info级别以上的日志信息输出到控制台,而debug级别以上的信息写入到log文件中,而error信息写入到一个单独的文件中去,下面我们的实例将会实现这样的功能。

4.使用commons-logging结合log4j进行开发

4.1. 下载必要的jar包

   下载commons-logging.jar和log4j.jar包,然后把它们放到工程的lib目录下,引入工程中。

4.2. 编写common-logging.properties配置文件

  在属性文件common-logging.properties中设置实现接口的类。如下(这里设置Log4j为所使用的日志包):

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

  这里需要注意的是,如果common-logging.properties配置使用Log4JCategoryLog,会报错误,具体见参考文献4。配置如下:

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

  在第三节中我们讲到如何在项目中引入了log4j.jar,那么common-logging默认会使用log4j最为日志实现方式。

4.3.log4j.properties配置实现日志的不同输出形式

前面我们讲到要求在控制台输入info级别的日志,然后有一个log.log记录debug级别以上的日志,一个error.log记录error级别以上的日志。log4j.properties配置如下:

### set log levels ###
log4j.rootLogger = debug , stdout , D , E

### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
## 输出INFO级别以上的日志
log4j.appender.stdout.Threshold = INFO
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n

### 输出到日志文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D:/logs/log.log
log4j.appender.D.Append = true
## 输出DEBUG级别以上的日志
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

### 保存异常信息到单独文件 ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
## 异常日志文件名
log4j.appender.E.File = D:/logs/error.log
log4j.appender.E.Append = true
## 只输出ERROR级别以上的日志!!!
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

4.4.单独使用log4j实例:Log4jTest.java

package log.sample;

import org.apache.log4j.Logger;

public class Log4jTest {
private static Logger log = Logger.getLogger(Log4jTest.class);
public void log() {
log.debug("Debug info.");
log.info("Info info");
log.warn("Warn info");
log.error("Error info");
log.fatal("Fatal info");
}

public static void main(String[] args) {
Log4jTest test = new Log4jTest();
test.log();
}
}

4.5.common-logging结合log4j实例:JCLTest.java

package log.sample;

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

public class JCLTest {
private static Log log = LogFactory.getLog(JCLTest.class);
public void log(){
log.debug("Debug info.");
log.info("Info info");
log.warn("Warn info");
log.error("Error info");
log.fatal("Fatal info");
}
public static void main(String[] args) {
JCLTest test = new JCLTest();
test.log();
}
}

说明:4.4和4.5的输出结果是一样的。