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