Apache Commons-logging使用实例

Apache Commons-logging使用实例
本文将介绍如何在程序中使用Apache Commons-logging
author: ZJ 07-3-17

1.Commons-Loggin简介
Jakarta Commons Logging (JCL)提供的是一个日志(Log)接口(interface),同时兼顾轻量级和不依赖于具体的日志实现工具。它提供给中间件/日志工具开发者一个简单的日志操作抽象,允许程序开发人员使用不同的具体日志实现工具。用户被假定已熟悉某种日志实现工具的更高级别的细节。JCL提供的接口,对其它一些日志工具,包括Log4J, Avalon LogKit, and JDK 1.4等,进行了简单的包装,此接口更接近于Log4J和LogKit的实现。

2.快速入门
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. 如果应用程序运行在jdk1.4的系统中,使用相关的包装类(Jdk14Logger)
   5. 使用简易日志包装类(SimpleLog)
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接口。 其输出日志的方法中不进行任何操作。

3.使用JCL开发
因为Log4j的强大,同时开发者又不希望对Log4j的依赖性太强。所以目前比较流行的是Commons-logging和Log4j结合使用。
 
1. 部署日志器
   下载commons-logging.jar和log4j.jar包,能后把它们放到工程的lib目录下,引入工程中。
2. 指定日志器
   在属性文件common-logging.properties中设置实现接口的类。如下(这里设置Log4j为所使用的日志包):
#commons-logging.properties文件配置信息
 
# org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
# Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
 
#利用log4j为输出介质
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog
 
#JDK5 Logger
#org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
 
3.org.apache.commons.logging.Log接口中定义的方法,按严重性由高到低的顺序有:
log.fatal(Object message);
log.fatal(Object message, Throwable t);
log.error(Object message);
log.error(Object message, Throwable t);
log.warn(Object message);
log.warn(Object message, Throwable t);
log.info(Object message);
log.info(Object message, Throwable t);
log.debug(Object message);
log.debug(Object message, Throwable t);
log.trace(Object message);
log.trace(Object message, Throwable t);
除此以外,还提供下列方法以便代码保护。
log.isFatalEnabled();
log.isErrorEnabled();
log.isWarnEnabled();
log.isInfoEnabled();
log.isDebugEnabled();
log.isTraceEnabled();
 
4.信息级别
确保日志信息在内容上和反应问题的严重程度上的恰当,是非常重要的。
1)fatal非常严重的错误,导致系统中止。期望这类信息能立即显示在状态控制台上。
 
2)error其它运行期错误或不是预期的条件。期望这类信息能立即显示在状态控制台上。
 
3)warn使用了不赞成使用的API、非常拙劣使用API, '几乎就是'错误, 其它运行时不合需要和不合预期的状态但还没必要称为 "错误"。期望这类信息能立即显示在状态控制台上。
 
4)info运行时产生的有意义的事件。期望这类信息能立即显示在状态控制台上。
 
5)debug系统流程中的细节信息。期望这类信息仅被写入log文件中。
 
6)trace更加细节的信息。期望这类信息仅被写入log文件中。
  通常情况下,记录器的级别不应低于info.也就是说,通常情况下debug的信息不应被写入log文件中。
4.Apache Commons-logging使用流程
1)将common-logging.jar 包加入到环境变量或者classpath。
 
2)导入org.apache.commons.logging.Log; org.apache.commons.logging.LogFactory;及相关包
 
3)在需要使用logging的地方获取Log实例。
private static Log log = LogFactory.getLog(Test.class);
 
4)使用Logger对象的debug,info,fatal...方法。
log.debug("Debug info.");
5.Apache Commons-logging使用示例
Test.java
package sample;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 
public class Test {
    private static Log log = LogFactory.getLog(Test.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) {
       Test test = new Test();
       test.log();
    }
}
 
结果:
DEBUG  sample.Test.log(Test.java:13) Debug info.
INFO   sample.Test.log(Test.java:14) Info info
WARN   sample.Test.log(Test.java:15) Warn info
ERROR  sample.Test.log(Test.java:16) Error info
FATAL  sample.Test.log(Test.java:17) Fatal info
当没有任何配置文件(.properties)时,就如同上的结果。此时,它使用的是使用简易日志包装类(SimpleLog)。
下面加入包与配置文件,使其使用log4j。
1)  加入配置文件commons-logging.properties和log4j.properties。
 
2)  将 log4j.jar 和 common-logging.jar 两个包加入到环境变量或者classpath 。
 
3)Test.java内容不变。
 
3)  commons-logging.properties
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog
 
4)log4j.properties
log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
 
结果:
INFO [main] - Info info
WARN [main] - Warn info
ERROR [main] - Error info
FATAL [main] - Fatal info
6.Apache Log介绍集
7.参考资料
[1]官方文档
[2] Jakarta Commons Logging(JCL)开发手记
[url]http://blog.csdn.net/fasttalk/archive/[/url]2005/06/29/406681.aspx

本文出自 “i张俊” 博客,请务必保留此出处http://zhangjunhd.blog.51cto.com/113473/25135

展开阅读全文

apache commons-logging和log4j的分析,请指点

09-26

今天看了会jbpm的源码,看到了他的log实现机制,于是乎,呼哧呼哧的一起劲一直看到commons-logging的底层代码rn也可以模仿 org.jbpm.util.log.JbpmLogFactory和JbpmLog这两个类写自己的log打印方法rnrn下面是简要的分析,其中不乏理解错误,请高手指教,谢谢rn * 一、log运行过程rn * 0、LogFactory.getFactory() 先从缓存中查找已缓存的工厂,如果有则直接返回,否则查找commons-logging.properties文件,rn * 1、如果有,则找其org.apache.commons.logging.LogFactory属性,rn * 1.1 如果该属性有配置,并且配置的工厂类能找到,则加载该工厂,rn * 1.2 如果找不到,则默认找org.apache.commons.logging.impl.LogFactoryImpl这个工厂类rn * 2、如果没有commons-logging.properties文件,则默认加载org.apache.commons.logging.impl.LogFactoryImplrn * 2.1 LogFactoryImpl初始化时先判断当前环境下是否存在org.apache.commons.logging.impl.Log4jFactory,如果存在,则将该类.newInstance()作为当前工厂的真正代理实体类rn * 3、根据刚才找到的工厂类,生成新的实例,并放入contextClassLoader的缓存池中rn * 4、如果有配置文件commons-logging.properties,则根据其配置初始化新实例工厂的属性rn * 5、调用工厂的getInstance(Class clazz):Log方法,从缓存池中获取Log实例rn * 5.0 如果当前有代理工厂(步骤2.1),则直接中代理工厂中获取Log实例,否则5.1:从当前工厂的缓存池(instances)中获取rn * 5.1 当前工厂的缓存池(instances)初始时Log实例不存在,需要新建一个,即调用newInstance(String clazzName)方法,之后(5.5)则可以直接从缓存池中获取rn * 5.2 调用getLogConstructor():Constructor方法,获取构造子rn * 5.2.1 先从工厂的属性集中获取org.apache.commons.logging.Log属性的值,如果不存在,则rn * 5.2.2 从jvm系统环境中获取org.apache.commons.logging.Log属性的值,如果不存在,则rn * 5.2.3 查看当前环境中是否有log4j的类(通过loadclass查看类org.apache.log4j.Category、org.apache.commons.logging.impl.Log4JCategoryLog在lib目录中是否存在),如果存在这个类,则加载org.apache.commons.logging.impl.Log4JCategoryLog这个作为Log实体类,否则rn * 5.2.4 查看jdk14的log类(java.util.logging.Logger、org.apache.commons.logging.impl.Jdk14Logger)是否存在,如存在,则加载org.apache.commons.logging.impl.Jdk14Logger这个作为Log实体类,否则rn * 5.2.5 加载org.apache.commons.logging.impl.SimpleLog这个类作为Log实体类rn * 5.2.6 获取该Log实体类上的setLogFactory方法logMethod,使用签名:new Class[] org.apache.commons.logging.LogFactory.class rn * 5.2.7 获取该Log实体类的构造子,Constructor logConstructor = logClass.getConstructor(new Class[] java.lang.String.class );rn * 5.3 再根据这个构造子,生成一个新的实例Log(logConstructor.newInstance(new Object[1]clazzName))rn * 5.4 用当前工厂类做参数,调用新实例的logMethod(如果存在的话,若不存在,则不调用):setLogFactory方法(logMethod.invoke(instance, new Object[1]this))从而最终得到Log实例rn * 5.4.1 log4j的Log实体类不存在setLogFactory,因为在getInstance(Class clazz)的时候是调用的org.apache.commons.logging.impl.Log4jFactory.getInstance(Class clazz)方法直接获取Log实例rn * Log instance = new Log4JCategoryLog(Category.getInstance(clazz))category = Category.getInstance(name);;rn * 获取后便放入该工厂的缓存池中rn * 其他类Log实例如SimpleLog也没有setLogFactory方法rn * log4j的log.debug() log.warn()等函数具体由Log4JCategoryLog这个实现类来执行rn * 而该实现类Log4JCategoryLog中的debug、warn函数,则由category.log(FQCN, Priority.DEBUG, message, throwable);来执行rn * 这个category的实例化由后一部分分析rn * 5.5 将得到的Log实例放入缓存池中,供下次使用时调用rn * rn * 二、log4j底层打印的分析(commons-logging这个jar包中的log调用了log4j这个jar包)rn * org.apache.log4j.Category.getInstance(clazz)分析(日志的打印底层是由Category这个类来打印的):rn * 1、先从org.apache.log4j.LogManager中获取一个Category实例:LogManager.getLogger(clazz);rn * 1.1 LogManager有一个静态代码块,该块从配置文件(log4j.properties,如果没有在System.getProperty(key, def);中配置的话)中读取所有配置的属性rn * 1.2 LogManager从DefaultRepositorySelector这个库中获取存放Category实例的库,再从Category库中获取目前所需的Categoryrn * repositorySelector.getLoggerRepository().getLogger(clazz.getName());rn * 1.3 上述的repositorySelector:org.apache.log4j.spi.DefaultRepositorySelector,而获取到的LoggerRepository为org.apache.log4j.Hierarchyrn * 1.4 Hierarchy的getLogger(clazz.getName());返回一个org.apache.log4j.Logger(继承自Category)对象实例,在这个getLogger方法中调用了JVM底层方法,同时将新生成的Logger放入缓存池中rn * 1.5 用新生成的org.apache.log4j.Logger打印信息,完成日志的打印,由于该Logger类继承自Category,同时他只重载了部分方法,而打印日志等方法还在Category中执行,因此Category是整个打印的关键部分rn * rn * 三、配置文件的读取由如下类实现rn * org.apache.log4j.helpers.OptionConverter(方法:selectAndConfigure)判断是xml配置文件log4j.xml还是属性配置文件log4j.propertiesrn * 属性配置文件log4j.properties由org.apache.log4j.PropertyConfigurator读取rnrn 论坛

commons-logging接合log4j得用法?

06-24

commons-logging提供了通用得接口和各种log得实现接合,我原来使用得log4j,所以就想rn把log4j得代码改成commons-logging,找了一篇文章就照着做,把我原来得一个类改了下:rnpublic class JdbcMap extends BaseMap rnrn /**rn * All logging goes through this loggerrn */rn private static Log log = LogFactory.getLog(JdbcMap.class);rn rnrn private Statement sta = null;rn /**rn * 通过session获得connectionrn * @return 当前session得connectionrn */rn public Connection getConnection() throws HibernateExceptionrn return getSession().connection();rn rn rn public Statement getStatement() throws HibernateException, SQLExceptionrn if (sta == null)rn sta = getSession().connection().createStatement();rn rn rn return sta;rn rn rn public void closeStatement() throws SQLExceptionrn if (sta != null)rn sta.close();rn sta = null;rn rn rn /**rn * 执行查询rn * rn * @param sql 查询sqlrn * @returnrn * @throws HibernateException if can't get connection from sessionrn * @throws SQLException if can't executequery from connectionrn */rn public ResultSet executeQuery(String sql) rn throws HibernateException, SQLExceptionrn rn if (log.isDebugEnabled()) rn log.debug("debug execute query: " + sql);rn rn rn rn if (log.isInfoEnabled()) rn log.info("info execute query: " + sql);rn rnrn rn Statement sta = getStatement();rn rn ResultSet res = sta.executeQuery(sql);rn rn return res;rn rn rn rn public static void main(String[] args) rn if (log.isDebugEnabled()) rn log.debug("debug execute query: " );rn rn if (log.isInfoEnabled()) rn log.info("info execute query: " );rn rn rn rn rnrnrn我在web-inf/classses目录下建了commons-logging.properties和log4j.properties,我建了两个appender,rncommons-logging.properties内容:rnorg.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLoggerrnlog4j.properties内容:rnlog4j.rootLogger=debug, dest1,dest2rnrnlog4j.appender.dest1=org.apache.log4j.ConsoleAppenderrnlog4j.appender.dest1.layout=org.apache.log4j.PatternLayoutrnlog4j.appender.dest1.layout.ConversionPattern=%d %-5p %-5c3 %x -> %m%nrnrnrnlog4j.appender.dest2=org.apache.log4j.RollingFileAppenderrnlog4j.appender.dest2.File=c://bridge.logrnrnlog4j.appender.dest2.MaxFileSize=100KBrn# Keep one backup filernlog4j.appender.dest2.MaxBackupIndex=3rnrnlog4j.appender.dest2.layout=org.apache.log4j.PatternLayoutrnlog4j.appender.dest2.layout.ConversionPattern=%d [%t] %-5p %-5c3(%L) %x -> %m%nrn并把commons-logging.jar和log4j.jar都拷贝到了web-inf/lib目录下,所有准备工作都做完了,然后rn我建立了一个servlet,调用了rn jdbcmap map= new jdbcmap();rn map.executeQuery(sql);rn但是运行servlet后,只在控制台打出了这一句log.info("info execute query: " + sql); c://bridge.logrn这个文件没有建立,所以得出结论commons-logging没有调用log4j,而是调用得jdklog(commons-logging默认先rn找log4j,找不到就用jdk1.4log,要不然就simplelog),于是我就直接运行JdbcMap(见main函数),结果得到了我rn想要得结果,c://bridge.log建立了,里面得内容和控制台打出得一样,log.debug("debug execute query: " )rn这一句也打了出来.rn 终于说完了,有点罗嗦,大家帮我看看,最好试一试,有知道得就告诉我,rn 我怀疑是不是classloader得问题. 论坛

没有更多推荐了,返回首页