我们以1.X版本为例
// 使用非显式配置文件
TTCCLayout layout = new TTCCLayout();
FileAppender appender = new FileAppender(layout,"e://testxxx.log");
BasicConfigurator.configure(appender);
Logger logger = Logger.getLogger(TestLog.class.getName());
logger.debug("sss");
// 使用显式配置文件
BasicConfigurator.configure();
Logger logger = Logger.getLogger(TestLog.class.getName());
logger.info("abcdefg");
log4j.properties
log4j.rootLogger=debug,console log4j.appender.logfile.encoding=UTF-8 log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%d{yyy-MM-dd HH:mm:ss } %L %-5p %c - %m%n log4j.logger.org.apache.log4j=info,boss_service_logfile log4j.appender.boss_service_logfile=org.apache.log4j.RollingFileAppender log4j.appender.boss_service_logfile.File=e:/TestLog.log log4j.appender.boss_service_logfile.MaxFileSize=10000kb log4j.appender.boss_service_logfile.MaxBackupIndex=10 log4j.appender.boss_service_logfile.layout=org.apache.log4j.PatternLayout log4j.appender.boss_service_logfile.layout.ConversionPattern=%d{yyy-MM-dd HH:mm:ss} %-5p - %m%n
关键接口和类
public class PatternLayout extends Layout { 我们常用到这个进行模式匹配日志的布局或者说日志的样式
public class TTCCLayout extends DateLayout {
abstract public class DateLayout extends Layout {
public abstract class Layout implements OptionHandler { 日志布局
public interface OptionHandler {
public class FileAppender extends WriterAppender { 我们常用到的文件输出
public class ConsoleAppender extends WriterAppender { 我们常用到的控制台输出
public class WriterAppender extends AppenderSkeleton {
public abstract class AppenderSkeleton implements Appender, OptionHandler {
public interface Appender { 日志输出
public class AppenderAttachableImpl implements AppenderAttachable {
public class BasicConfigurator { 日志配置的基础包装类
public class Logger extends Category { 日志对象
public class Category implements AppenderAttachable { 真正的日志执行类
protected void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
callAppenders(new LoggingEvent(fqcn, this, level, message, t));
}
// 该方法会把logger以及所属层级的日志对象,全部遍历一遍,然后在把每个日志对象的输出全部遍历一遍。
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);
}
}
}
}
public class AppenderAttachableImpl implements AppenderAttachable {
public int appendLoopOnAppenders(LoggingEvent event) {
int size = 0;
Appender appender;
if(appenderList != null) {
size = appenderList.size();
for(int i = 0; i < size; i++) {
appender = (Appender) appenderList.elementAt(i);
appender.doAppend(event); // 增加多个日志对象的输出
}
}
return size;
}
}
public interface AppenderAttachable { 附加输出到对象
public class LogManager { 主要起到初始化配置文件、初始化日志选择器的作用
public class Hierarchy implements LoggerRepository, RendererSupport { 关键类
...
This class is specialized in retrieving loggers by name and also maintaining the logger hierarchy.
翻译:这个类是专门用来按名字检索日志对象和维持日志对象的层级
public Logger getLogger(String name, LoggerFactory factory) {
CategoryKey key = new CategoryKey(name);
Logger logger;
synchronized (ht) {
Object o = ht.get(key);
if (o == null) {
logger = factory.makeNewLoggerInstance(name); 生成新的logger实例
logger.setHierarchy(this);
ht.put(key, logger);
updateParents(logger);
return logger;
} else if (o instanceof Logger) {
return (Logger) o;
} else if (o instanceof ProvisionNode) {
// System.out.println("("+name+") ht.get(this) returned ProvisionNode");
logger = factory.makeNewLoggerInstance(name);
logger.setHierarchy(this);
ht.put(key, logger);
updateChildren((ProvisionNode) o, logger);
updateParents(logger);
return logger;
} else {
// It should be impossible to arrive here
return null; // but let's keep the compiler happy.
}
}
}
...
}
public interface LoggerRepository {
public interface RendererSupport {
public class DefaultRepositorySelector implements RepositorySelector { 默认的仓库选择器
public interface RepositorySelector { 仓库选择器
public class LoggingEvent implements java.io.Serializable {
public class PropertyConfigurator implements Configurator { 属性文件解析类
public class DOMConfigurator implements Configurator xml文件解析类
public interface Configurator { 配置接口
public class Level extends Priority implements Serializable { 日志层级
public class Priority {
class DefaultCategoryFactory implements LoggerFactory { 日志对象工厂实现类
public interface LoggerFactory { 日志对象工厂接口
总体的印象 感觉log4j1.x版本的代码,几个抽象类和接口的设计很清晰,但代码的可读性不好,作者也不进行代码排版很混乱。