您好,登錄后才能下訂單哦!
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。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。