开源分析——Log4J
LogManager -> getLoggerRepository
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG)); = RepositorySelector
写入分析
初始化
-------------------------
synchronized
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
throws IOException {
LogLog.debug("setFile called: "+fileName+", "+append);
// It does not make sense to have immediate flush and bufferedIO.
if(bufferedIO) {
setImmediateFlush(false);
}
reset();
FileOutputStream ostream = null;
try {
//
// attempt to create file
//
ostream = new FileOutputStream(fileName, append);
} catch(FileNotFoundException ex) {
//
// if parent directory does not exist then
// attempt to create it and try to create file
// see bug 9150
//
String parentName = new File(fileName).getParent();
if (parentName != null) {
File parentDir = new File(parentName);
if(!parentDir.exists() && parentDir.mkdirs()) {
ostream = new FileOutputStream(fileName, append);
} else {
throw ex;
}
} else {
throw ex;
}
}
Writer fw = createWriter(ostream);
if(bufferedIO) {
fw = new BufferedWriter(fw, bufferSize);
}
this.setQWForFiles(fw);
this.fileName = fileName;
this.fileAppend = append;
this.bufferedIO = bufferedIO;
this.bufferSize = bufferSize;
writeHeader();
LogLog.debug("setFile ended");
}
OutputStreamWriter createWriter(OutputStream os) {
OutputStreamWriter retval = null;
String enc = getEncoding();
if(enc != null) {
try {
retval = new OutputStreamWriter(os, enc);
} catch(IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.warn("Error initializing output writer.");
LogLog.warn("Unsupported encoding?");
}
}
if(retval == null) {
retval = new OutputStreamWriter(os);
}
return retval;
}
什么时候flush???
。每次操作完,都会flush
。WriterAppender.subAppend
if(shouldFlush(event)) {
this.qw.flush();
这里shouldFlush默认=true
文件操作是每次new,还是new了之后一直使用?
。 获取logger的方法是:Logger.getLogger => LogManager->DefaultRepositorySelector(Hierarchy) -> Hierarchy.getLogger ->
.logger = factory.makeNewLoggerInstance(name); DefaultCategoryFactory..makeNewLoggerInstance(name) =
。new Logger() extends Category
. 这里使 Category的Loggerrepository = Hierarchy
. 这里开始看不出来如何初始化实际写日志的模块,实际上是config的时候,已经初始化了appender,因此get的时候已经是取初始化的了。
。如果没有在配置文件注明的,就是初始化为console的日志。
。 void configure() {
Logger root = Logger.getRootLogger();
root.addAppender(new ConsoleAppender(
new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
如果没有配置,则整个日志系统根本无法运行,所以只有配置了才有效。
写入日志的时候,使用了迭代,最终回到了rootLogger。 而getLogger的时候,输入仅仅是一个string标签,作为log的写入,log最终还是由config初始化
初始化FileAppender的方法:
LogManager.static
PropertySetter.activated
DailyRollingFileAppener.activateOptions
FileAppender.activateOptions.
代码中可以看出,是初始化的时候stream就初始了。
-------------------------------------
小结:
Logger在初始化的时候,就对stream等全部初始了。 涉及到的关键类包括:
FileOutputStream(fileName, append);
OutputStreamWriter(OutputStream):: Writer
FilterWriter(Writer)
写入的时候: FilterWriter.out.write();