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