码迷,mamicode.com
首页 > 其他好文 > 详细

日志组件系列:(2)commons logging和log4j实战

时间:2016-08-04 06:52:28      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:logging   java   


(1)、下载组件,引入jar包

(2)、配置

(3)、使用API


1、下载组件,引入jar包


jar包下载地址
log4j-1.2.17.jarhttp://logging.apache.org/log4j/1.2/
commons-logging-1.2.jarhttp://commons.apache.org/proper/commons-logging/download_logging.cgi



2、配置

在项目的src目录下添加log4j.properties文件,配置如下:

log4j.rootLogger=debug, console, file

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d %p %c.%M() -%m%n

log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File= ./logs/MyLog.log
log4j.appender.file.MaxFileSize=5KB
log4j.appender.file.MaxBackupIndex=100
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %p %c.%M() -%m%n


3、使用API

App.java

package com.rk.log;

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



public class App {
	@Test
	public void test()
	{
		Log log = LogFactory.getLog(App.class);
		log.isDebugEnabled();
		log.debug("debug信息");
		log.info("info信息");
		log.warn("warn信息");
		log.error("error信息");
	}
}

输出

2016-08-03 21:00:03,661 DEBUG com.rk.test.App.test() -debug信息1
2016-08-03 21:00:03,666 INFO com.rk.test.App.test() -info信息2
2016-08-03 21:00:03,666 WARN com.rk.test.App.test() -warn信息3
2016-08-03 21:00:03,667 ERROR com.rk.test.App.test() -error信息4


4、配置详解

# 通过根元素指定日志输出的级别、目的地: 
#  日志输出优先级: debug < info < warn < error 
log4j.rootLogger=info,console,file

############# 日志输出到控制台 #############
# 日志输出到控制台使用的api类
log4j.appender.console=org.apache.log4j.ConsoleAppender
# 指定日志输出的格式: 灵活的格式
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# 具体格式内容
log4j.appender.console.layout.ConversionPattern=%d %p %c.%M()-%m%n


############# 日志输出到文件 #############
log4j.appender.file=org.apache.log4j.RollingFileAppender
# 文件参数: 指定日志文件路径
log4j.appender.file.File=../logs/MyLog.log
# 文件参数: 指定日志文件最大大小
log4j.appender.file.MaxFileSize=5kb
# 文件参数: 指定产生日志文件的最大数目
log4j.appender.file.MaxBackupIndex=100
# 日志格式
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %c.%M()-%m%n


log4j.appender.file.File

对于log4j.appender.file.File这个配置,有几点需要注意:

(1)可以配置一个绝对路径的值,例如“E:/Temp/logs/MyLog.log”

(2)一般情况下使用相对路径,即使用“.”开头,但是对于普通的Java项目和JavaWeb项目之间,有一点需要注意:“.”代表的是Java命令的执行目录,但在普通Java项目中,“.”是指项目的根目录%project%;在JavaWeb项目中,“.”是指%tomat%/bin目录。


JavaWeb项目中,一般将日志保存到tomcat的logs目录下:

可以使用

../logs/MyLog.log

由于在JavaWeb项目中,“.”代表%tomcat%/bin目录,而“..”代表返回到%tomcat%目录中,那么“../logs/MyLog.log”就代表%tomcat%/logs目录下的MyLog.log文件。




Java项目中,使用“./logs/MyLog.log”代表%project%/logs目录下的MyLog.log文件。


5、commons logging和log4j的关系?


Apache的Common Logging只是一个高层的日志框架,本身并没有实现真正的写日志能力,而是依赖其它的日志系统如Log4j或者java本身的java.util.logging。可以通过配置文件来设定最终使用log4j还是java.util.logging.没有配置log4j的时候,就会调用java.util.logging包。


换句话说,我们上面使用的日志API,其实是由commons logging提供的,而非log4j提供的。在真正写日志的时候,commons logging会调用log4j的日志输出功能。




参考:

commons-logging 和 log4j 之间的关系

http://zachary-guo.iteye.com/blog/361177



我们在做项目时,日志的记录是必不可少的一项任务,而我们通常是使用 apache 的 log4j 日志管理工具。然而,在项目中,我们经常会看到两个 jar 包:commons-logging.jar 和 log4j.rar。为什么我们在使用 log4j 的同时还要引入 commons-logging.jar 呢,或者说不用 commons-logging.jar 可不可以,这两者之间到底是怎么的一种关系呢? 


作为记录日志的工具,它至少应该包含如下几个组成部分(组件): 

1. Logger 

记录器组件负责产生日志,并能够对日志信息进行分类筛选,控制什么样的日志应该被输出,什么样的日志应该被忽略。它还有一个重要的属性 - 日志级别。不管何种日志记录工具,大概包含了如下几种日志级别:DEBUG, INFO, WARN, ERROR 和 FATAL。 

2. Level 

日志级别组件。 

3. Appender 

日志记录工具基本上通过 Appender 组件来输出到目的地的,一个 Appender 实例就表示了一个输出的目的地。 

4. Layout 

Layout 组件负责格式化输出的日志信息,一个 Appender 只能有一个 Layout。 


我们再来看看 log4j.jar,打开 jar 包,我们可以看到 Logger.class(Logger),Level.class(Level), FileAppender.class(Appender), HTMLLayout.class(Layout)。其它的我们先忽略不看,这几个字节码文件正好是记录日志必不可少的几个组件。


接下来看看 commons-logging 中的 org.apache.commons.logging.Log.java 源码: 

package org.apache.commons.logging;

/**
 * 这是一个抽象接口
 * A simple logging interface abstracting logging APIs.  In order to be
 * instantiated successfully by {@link LogFactory}, classes that implement
 * this interface must have a constructor that takes a single String
 * parameter representing the "name" of this Log.
 * <p>
 * logging的6个级别
 * The six logging levels used by <code>Log</code> are (in order):
 * <ol>
 * <li>trace (the least serious)</li>
 * <li>debug</li>
 * <li>info</li>
 * <li>warn</li>
 * <li>error</li>
 * <li>fatal (the most serious)</li>
 * </ol>
 * 这些logging level依赖于uderlying logging system的实现
 * The mapping of these log levels to the concepts used by the underlying
 * logging system is implementation dependent.
 * The implementation should ensure, though, that this ordering behaves
 * as expected.
 * 
 * logging对于性能的影响
 * Performance is often a logging concern.
 * By examining the appropriate property,
 * a component can avoid expensive operations (producing information
 * to be logged).
 * 
 * For example,
 * 
 *    if (log.isDebugEnabled()) {
 *        ... do something expensive ...
 *        log.debug(theResult);
 *    }
 * 
 * 配置和API是分离的
 * Configuration of the underlying logging system will generally be done
 * external to the Logging APIs, through whatever mechanism is supported by
 * that system.
 *
 */
public interface Log {

    // ----------------------------------------------------- Logging Properties

    /**
     * 使用此方法有助于提高性能
     * Is debug logging currently enabled?
     * <p>
     * Call this method to prevent having to perform expensive operations
     * (for example, <code>String</code> concatenation)
     * when the log level is more than debug.
     *
     * @return true if debug is enabled in the underlying logger.
     */
    public boolean isDebugEnabled();

    public boolean isErrorEnabled();

    public boolean isFatalEnabled();

    public boolean isInfoEnabled();

    public boolean isTraceEnabled();

    public boolean isWarnEnabled();

    // -------------------------------------------------------- Logging Methods

    public void trace(Object message);

    public void trace(Object message, Throwable t);

    public void debug(Object message);

    public void debug(Object message, Throwable t);

    public void info(Object message);

    public void info(Object message, Throwable t);

    public void warn(Object message);

    public void warn(Object message, Throwable t);

    public void error(Object message);

    public void error(Object message, Throwable t);

    public void fatal(Object message);

    public void fatal(Object message, Throwable t);
}


很显然,只要实现了 Log 接口,它就是一个名副其实的 Logger 组件,也验证了 Logger 组件具有日志级别的属性。


继续看 commons-logging org.apache.commons.logging.impl 包下的几个类的源码片段:

package org.apache.commons.logging.impl;  
  
import org.apache.commons.logging.Log;  
import org.apache.log4j.Logger;  
import org.apache.log4j.Priority;  
import org.apache.log4j.Level;  
import ......  
  
public class Log4JLogger implements Log, Serializable {  
    // 对 org.apache.commons.logging.Log 的实现  
    ......  
}  
  
------------------------------------------------------------------  
  
package org.apache.commons.logging.impl;  
  
import org.apache.commons.logging.Log;  
import java.io.Serializable;  
import java.util.logging.Level;  
import java.util.logging.Logger;  
  
public class Jdk14Logger implements Log, Serializable {  
     // 对 org.apache.commons.logging.Log 的实现  
    ......  
}


好了,分析到这里,我们应该知道,真正的记录日志的工具是 log4j 和 sun 公司提供的日志工具。而 commons-logging 把这两个(实际上,在 org.apache.commons.logging.impl 包下,commons-logging 仅仅为我们封装了 log4j 和 sun logger)记录日志的工具重新封装了一遍(Log4JLogger.java 和 Jdk14Logger.java),可以认为 org.apache.commons.logging.Log 是个傀儡,它只是提供了对外的统一接口。因此我们只要能拿到 org.apache.commons.logging.Log,而不用关注到底使用的是 log4j 还是 sun logger。



既然如此,我们向构建路径加了 commons-logging.jar 和 log4j.jar 两个 jar 包,那我们的应用程序到底使用的 log4j 还是 sun logger 呢?(关于这个问题的解答,查看下一个参考



。。。。。中间一段省略,可查看原文。。。



可是问题又来了,org.apache.commons.logging.Log 和 org.apache.log4j.Logger 这两个类,通过包名我们可以发现它们都是 apache 的项目,既然如下,为何要动如此大的动作搞两个东西(指的是 commons-logging 和 log4j)出来呢?事实上,在 sun 开发 logger 前,apache 项目已经开发了功能强大的 log4j 日志工具,并向 sun 推荐将其纳入到 jdk 的一部分,可是 sun 拒绝了 apache 的提议,sun 后来自己开发了一套记录日志的工具。可是现在的开源项目都使用的是 log4j,log4j 已经成了事实上的标准,但由于又有一部分开发者在使用 sun logger,因此 apache 才推出 commons-logging,使得我们不必关注我们正在使用何种日志工具。







参考:

log4j+commons-logging结合使用

http://www.cnblogs.com/xwdreamer/archive/2011/12/28/2304598.html


Common Logging有两个基本的抽象类: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 org.apache.commons.logging;

import java.lang.reflect.Constructor;
import java.util.Hashtable;

import org.apache.commons.logging.impl.NoOpLog;

/**
 * By default, calling <code>getInstance()</code> will use the following
 * algorithm:
 * <ul>
 * <li>If Log4J is available, return an instance of
 *     <code>org.apache.commons.logging.impl.Log4JLogger</code>.</li>
 * <li>If JDK 1.4 or later is available, return an instance of
 *     <code>org.apache.commons.logging.impl.Jdk14Logger</code>.</li>
 * <li>Otherwise, return an instance of
 *     <code>org.apache.commons.logging.impl.NoOpLog</code>.</li>
 * </ul>
 * <p>
 * You can change the default behavior in one of two ways:
 * <ul>
 * <li>On the startup command line, set the system property
 *     <code>org.apache.commons.logging.log</code> to the name of the
 *     <code>org.apache.commons.logging.Log</code> implementation class
 *     you want to use.</li>
 * <li>At runtime, call <code>LogSource.setLogImplementation()</code>.</li>
 * </ul>
 *
 * 不推荐使用这个LogSource类(@deprecated),推荐使用LogFactory类,
 * 但LogSource类 和 LogFactory类 使用了相同的算法。
 * @deprecated Use {@link LogFactory} instead - The default factory
 *  implementation performs exactly the same algorithm as this class did
 *
 * @version $Id: LogSource.java 1432675 2013-01-13 17:53:30Z tn $
 */
public class LogSource {

    // ------------------------------------------------------- Class Attributes

    static protected Hashtable logs = new Hashtable();

    /** Is log4j available (in the current classpath) */
    static protected boolean log4jIsAvailable = false;

    /** Is JDK 1.4 logging available */
    static protected boolean jdk14IsAvailable = false;

    /** Constructor for current log class */
    static protected Constructor logImplctor = null;

    // ----------------------------------------------------- Class Initializers

    static {

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

        // Is JDK 1.4 Logging Available?
        try {
            jdk14IsAvailable = null != Class.forName("java.util.logging.Logger") &&
                               null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger");
        } 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) {
                    // ignored
                }
            }
        } 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) {
                    // ignored
                }
            }
        }

    }


    /**
     * Set the log implementation/log implementation factory
     * by the name of the class.  The given class must implement {@link Log},
     * and provide a constructor that takes a single {@link String} argument
     * (containing the name of the log).
     */
    static public void setLogImplementation(String classname)
        throws LinkageError, NoSuchMethodException, SecurityException, ClassNotFoundException {
        try {
            Class logclass = Class.forName(classname);
            Class[] argtypes = new Class[1];
            argtypes[0] = "".getClass();
            logImplctor = logclass.getConstructor(argtypes);
        } catch (Throwable t) {
            logImplctor = null;
        }
    }

    // 其它代码省略。。。
}


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


(1)下载必要的jar包

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


(2)编写common-logging.properties配置文件

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

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


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



单独使用log4j的示例

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();
    }
}


common logging和log4j结合的示例

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();
    }
}


















日志组件系列:(2)commons logging和log4j实战

标签:logging   java   

原文地址:http://lsieun.blog.51cto.com/9210464/1834146

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!