开源分析——Log4J

 

LogManager -> getLoggerRepository


RepositorySelector.getLoggerRepository

Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG)); = RepositorySelector 

DefaultRepositorySelector(NOPLoggerRepository)

NOPLoggerRepository->NOPLogger

写入分析 

-------------------------

Logger.warn -> 

Category.warn

Category.forcelog

category.callAppenders

AppenderAttachableImpl.appendLoopOnAppenders

Appender.doAppend

这里实际上交给了各种的appender实现日志记录,这些appender在配置的时候注入

----------------------------

WriterAppender

AppenderSkeleton.doAPpend

WriterAppender.append -subAppend -this.qw.write

QuietWriter.write

这个狗屁writer又是靠外界插入write,在WRiterAppender.setWriter

  WriterAppender(Layout layout, OutputStream os) {
    this(layout, new OutputStreamWriter(os));


---------------------------

添加appender

AppenderAttachableImpl.addAppender

Category.addAPpender

这里就到了PropertyConfigurator


-------------------------

找了半天,终于找到了入口,在FileAppender,这里调用了

WriterAppender.createWriter()

初始化 

-------------------------

代码
  public
  
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");
  }
代码
  protected
  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(); 

原文地址:https://www.cnblogs.com/zc22/p/1791057.html