log4j几个tips

log4j是很常用的日志框架,这里总结几个小知识点:

1. logger是以名称为key,logger为value的形式存储在Hashtable里,所以,logger作为入参不需要传入引用,直接输入名称get即可。

LogFactoryImpl.java

/**
     * The {@link org.apache.commons.logging.Log} instances that have
     * already been created, keyed by logger name.
     */
    protected Hashtable instances = new Hashtable();

    public Log getInstance(String name) throws LogConfigurationException {

        Log instance = (Log) instances.get(name);
        if (instance == null) {
            instance = newInstance(name);
            instances.put(name, instance);
        }
        return (instance);

    }

2. logger的继承关系是根据名称的“.”分割来区分,表现为子logger打印日志时遍历父logger里的appender的进行日志打印。

Category.java

public
  void callAppenders(LoggingEvent event) {
    int writes = 0;

    for(Category c = this; c != null; c=c.parent) {
      // Protected against simultaneous call to addAppender, removeAppender,...
      synchronized(c) {
	if(c.aai != null) {
	  writes += c.aai.appendLoopOnAppenders(event);
	}
	if(!c.additive) {
	  break;
	}
      }
    }

    if(writes == 0) {
      repository.emitNoAppenderWarning(this);
    }
  }

3.定义模块名为常量,按模块名称取logger,解决项目里包名类名相同日志无法区分问题。

贴代码:
示例一

package com.zoo;

import java.util.Properties;

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


/**
 * 
 * @author yankai913@gmail.com
 * @date 2014年12月22日
 */
public class LogTest {
    static final Log log = LogFactory.getLog(LogTest.class);


    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.setProperty("log4j.rootLogger", "DEBUG,stdout");
        properties.setProperty("log4j.appender.stdout", "org.apache.log4j.ConsoleAppender");
        properties.setProperty("log4j.appender.stdout.layout", "org.apache.log4j.PatternLayout");
        properties.setProperty("log4j.appender.stdout.layout.ConversionPattern",
            "%d [%t] %-5p %C{6} (%F:%L) - %m%n");
        // log4j的继承关系是"."
        // log --> com.zoo.LogTest
        // log2(父log) --> com.zoo
        // log3(父log2) --> com
        // 以此类推
        // 子logger的继承关系表现是,子logger打印日志时,遍历父logger里的appender
        // 进行日志打印,"com.zoo.LogTest"的父子logger分别是:
        // "com.zoo.LogTest"的logger -> "com.zoo"的logger -> "root"的logger。
        // 以下这句话定义了上述的log2(即父log),导致日志打印2次。
        properties.setProperty("log4j.logger.com.zoo", "INFO, stdout");
        // 以下这句话定义com.zoo包的logger(即log2)的appender不被继承,日志打印只有一条。
        properties.setProperty("log4j.additivity.com.zoo", "false");
        PropertyConfigurator.configure(properties);
        System.out.println(log);
        log.info("Hello World!");
        System.out.println("end");
    }
}

示例二

package com.zoo;

import java.util.Properties;

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


/**
 * 
 * @author yankai913@gmail.com
 * @date 2014年12月22日
 */
public class LogTest2 {
    // 定义公共的logerName,按module分
    static final String Module1_LogName = "Module1";
    static final String Module2_LogName = "Module2";


    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.setProperty("log4j.rootLogger", "DEBUG,file");
        properties.setProperty("log4j.appender.file", "org.apache.log4j.FileAppender");
        properties.setProperty("log4j.appender.file.layout", "org.apache.log4j.PatternLayout");
        properties.setProperty("log4j.appender.file.layout.ConversionPattern",
            "%d [%t] %-5p %c{1} %C{6} (%F:%L) - %m%n");
        properties.setProperty("log4j.appender.file.append", "true");
        properties.setProperty("log4j.appender.file.file", "logtest2.log");
        PropertyConfigurator.configure(properties);
        // 比较同名称的log,结果为true,所以log作为入参不需要传入引用,直接get即可。
        System.out.println(Module1.log.equals(ServiceImpl_1.log));
        System.out.println(Module2.log.equals(ServiceImpl_2.log));
        // 按模块搜索查看日志,关键词就是模块名称,即上面的Module1,Module2。
        // 解决包名类名完全一样,但是在不同模块的日志查询。
        Module1.println();
        Module2.println();
        ServiceImpl_1.println();
        ServiceImpl_2.println();
        System.out.println("end");
    }

    public static class Module1 {
        public static Log log = LogFactory.getLog(Module1_LogName);


        public static void println() {
            log.info("this is module1");
        }
    }

    public static class Module2 {
        public static Log log = LogFactory.getLog(Module2_LogName);


        public static void println() {
            log.info("this is module2");
        }
    }

    public static class ServiceImpl_1 {
        public static Log log = LogFactory.getLog(Module1_LogName);


        public static void println() {
            log.info("this is service");
        }
    }

    public static class ServiceImpl_2 {
        public static Log log = LogFactory.getLog(Module2_LogName);


        public static void println() {
            log.info("this is service");
        }
    }
}

练习代码看这里

此条目发表在编程语言分类目录,贴了, 标签。将固定链接加入收藏夹。