log4j的初始化,Logger的实例为NOPLogger,所有Appender,委托给
rootLogger管理,今天我们来看一下,日志的打印输出。
日志输出源头为下一句
Java代码
- log.info("========test daily level info=========");
我们来看一下,这一句都做了些什么?
Java代码
- public final class NOPLogger extends Logger
- public class Logger extends Category
而NOPLogger,Logger,没有info方法,来看Category
//Category
Java代码 下载
- public class Category
- implements AppenderAttachable
- {
- AppenderAttachableImpl aai;
- static
- {
- FQCN = (org.apache.log4j.Category.class).getName();
- }
- //输出日志
- public void info(Object message)
- {
- //查看info日志,是否开启
- if(repository.isDisabled(20000))
- return;
- //如果INFO,大于等于有效的日志级别,则输出日志
- if(Level.INFO.isGreaterOrEqual(getEffectiveLevel()))
- forcedLog(FQCN, Level.INFO, message, null);
- }
- //根据日志级别,输出日志
- protected void forcedLog(String fqcn, Priority level, Object message, Throwable t)
- {
- //将LoggingEvent,委托给AppenderS处理,
- callAppenders(new LoggingEvent(fqcn, this, level, message, t));
- }
- public void callAppenders(LoggingEvent event)
- {
- int writes;
- Category c;
- writes = 0;
- c = this;
- _L3:
- label0:
- {
- if(c == null)
- break; /* Loop/switch isn't completed */
- synchronized(c)
- {
- if(c.aai != null)
- //Appenders处理日志输出事件
- writes += c.aai.appendLoopOnAppenders(event);
- if(c.additive)
- break label0;
- }
- break; /* Loop/switch isn't completed */
- }
- category;
- JVM INSTR monitorexit ;
- goto _L1
- exception;
- throw exception;
- _L1:
- c = c.parent;
- if(true) goto _L3; else goto _L2
- _L2:
- if(writes == 0)
- repository.emitNoAppenderWarning(this);
- return;
- }
- }
//AppenderAttachableImpl 下载
Java代码
- public class AppenderAttachableImpl
- implements AppenderAttachable
- {
- protected Vector appenderList;
- //遍历rootLooger的Appenders,每一个Appenders分别处理log输出事件
- public int appendLoopOnAppenders(LoggingEvent event)
- {
- int size = 0;
- if(appenderList != null)
- {
- size = appenderList.size();
- for(int i = 0; i < size; i++)
- {
- Appender appender = (Appender)appenderList.elementAt(i);
- appender.doAppend(event);
- }
- }
- return size;
- }
- }
这里我们来看一下DailyRollingFileAppender
//DailyRollingFileAppender
Java代码 下载
- public class DailyRollingFileAppender extends FileAppender
- {
- static final int TOP_OF_TROUBLE = -1;
- static final int TOP_OF_MINUTE = 0;
- static final int TOP_OF_HOUR = 1;
- static final int HALF_DAY = 2;
- static final int TOP_OF_DAY = 3;
- static final int TOP_OF_WEEK = 4;
- static final int TOP_OF_MONTH = 5;
- private String datePattern;
- private String scheduledFilename;
- private long nextCheck;
- Date now;
- SimpleDateFormat sdf;
- RollingCalendar rc;
- int checkPeriod;
- static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
- public DailyRollingFileAppender(Layout layout, String filename, String datePattern)
- throws IOException
- {
- super(layout, filename, true);
- this.datePattern = "'.'yyyy-MM-dd";
- nextCheck = System.currentTimeMillis() - 1L;
- now = new Date();
- rc = new RollingCalendar();
- checkPeriod = -1;
- this.datePattern = datePattern;
- //构造是调用激活配置方法
- activateOptions();
- }
- }
//AppenderSkeleton
Java代码
- public abstract class AppenderSkeleton
- implements Appender, OptionHandler
- {
- //处理日志事件
- public synchronized void doAppend(LoggingEvent event)
- {
- append(event);
- }
- //待子类拓展
- protected abstract void append(LoggingEvent loggingevent);
- }
//AppenderSkeleton
Java代码
- public class WriterAppender extends AppenderSkeleton
- {
- //处理日志事件
- public void append(LoggingEvent event)
- {
- if(!checkEntryConditions())
- {
- return;
- } else
- {
- subAppend(event);
- return;
- }
- }
- protected void subAppend(LoggingEvent event)
- {
- qw.write(layout.format(event));
- if(layout.ignoresThrowable())
- {
- String s[] = event.getThrowableStrRep();
- if(s != null)
- {
- int len = s.length;
- for(int i = 0; i < len; i++)
- {
- //输出日志,关键是QuietWriter
- qw.write(s[i]);
- qw.write(Layout.LINE_SEP);
- }
- }
- }
- if(shouldFlush(event))
- qw.flush();
- }
- protected boolean immediateFlush;
- protected String encoding;
- protected QuietWriter qw;
- }
下面看一下QuietWriter是什么?如何来的?
看DailyRollingFileAppender的构造方法中,调用了一个方法激活配置activateOptions 下载
Java代码
- public DailyRollingFileAppender(Layout layout, String filename, String datePattern)
- throws IOException
- {
- super(layout, filename, true);
- this.datePattern = "'.'yyyy-MM-dd";
- nextCheck = System.currentTimeMillis() - 1L;
- now = new Date();
- rc = new RollingCalendar();
- checkPeriod = -1;
- this.datePattern = datePattern;
- //激活配置
- activateOptions();
- }
- public void activateOptions()
- {
- super.activateOptions();
- if(datePattern != null && fileName != null)
- {
- now.setTime(System.currentTimeMillis());
- sdf = new SimpleDateFormat(datePattern);
- int type = computeCheckPeriod();
- printPeriodicity(type);
- rc.setType(type);
- File file = new File(fileName);
- scheduledFilename = fileName + sdf.format(new Date(file.lastModified()));
- } else
- {
- LogLog.error("Either File or DatePattern options are not set for appender [" + name + "].");
- }
- }
查看FileAppender
Java代码
- public class FileAppender extends WriterAppender
- {
- public void activateOptions()
- {
- if(fileName != null)
- {
- try
- {
- setFile(fileName, fileAppend, bufferedIO, bufferSize);
- }
- }
- public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
- throws IOException
- {
- LogLog.debug("setFile called: " + fileName + ", " + append);
- if(bufferedIO)
- setImmediateFlush(false);
- reset();
- FileOutputStream ostream = null;
- try
- {
- ostream = new FileOutputStream(fileName, append);
- }
- //根据文件流,创建Writer
- Writer fw = createWriter(ostream);
- if(bufferedIO)
- fw = new BufferedWriter(fw, bufferSize);
- //设置QuietWriter的输出流
- setQWForFiles(fw);
- this.fileName = fileName;
- fileAppend = append;
- this.bufferedIO = bufferedIO;
- this.bufferSize = bufferSize;
- writeHeader();
- LogLog.debug("setFile ended");
- }
- //设置QuietWriter的输出流
- protected OutputStreamWriter createWriter(OutputStream os)
- {
- OutputStreamWriter retval = null;
- String enc = getEncoding();
- if(enc != null)
- try
- {
- retval = new OutputStreamWriter(os, enc);
- }
- if(retval == null)
- retval = new OutputStreamWriter(os);
- return retval;
- }
- //设置QuietWriter的输出流
- protected void setQWForFiles(Writer writer)
- {
- qw = new QuietWriter(writer, errorHandler);
- }
- }
再看一下ConsoleAppender
Java代码 下载
- //ConsoleAppender。
- ublic class ConsoleAppender extends WriterAppender
- {
- private static class SystemOutStream extends OutputStream
- {
- public void close()
- {
- }
- public void flush()
- {
- System.out.flush();
- }
- public void write(byte b[])
- throws IOException
- {
- System.out.write(b);
- }
- public void write(byte b[], int off, int len)
- throws IOException
- {
- System.out.write(b, off, len);
- }
- public void write(int b)
- throws IOException
- {
- System.out.write(b);
- }
- public SystemOutStream()
- {
- }
- }
- public ConsoleAppender(Layout layout, String target)
- {
- this.target = "System.out";
- follow = false;
- setLayout(layout);
- setTarget(target);
- activateOptions();
- }
- public void activateOptions()
- {
- if(follow)
- {
- if(target.equals("System.err"))
- setWriter(createWriter(new SystemErrStream()));
- else
- //设置输出流
- setWriter(createWriter(new SystemOutStream()));
- } else
- if(target.equals("System.err"))
- setWriter(createWriter(System.err));
- else
- setWriter(createWriter(System.out));
- super.activateOptions();
- }
- }
总结:
从上面的分析我们可以看出,log日志的输出,是遍历rootLogger的Appender来处理日志输出事件,Appender,首先确定日志级别是否大于RootLogger的日志级别,大于,则处理日志,而日志的输出委托给QuietWriter,而QuietWriter来源于DailyRollingFileAppender,
ConsoleAppender。
来源:oschina
链接:https://my.oschina.net/u/2978057/blog/769720