Logger for log4j source code reading (1)

Source: Internet
Author: User

Overview

Log4j is a very convenient and powerful open-source log project. After simple configuration, it can achieve quite good results.

One hot brain decides to read the source code of log4j. Its original intention is to read the source code to improve the ability to write code.

 

The core concepts of log4j can be divided:

The logger log receiver is used by programmers to record logs in their own code in the form of logger. Error.

Append log writer writes the log information received by logger to various devices, such as files and the console.

Layout log formatter first formats the input logs and then outputs them.

 

Log4j divides logs into several levels, from low to high: Debug <info <warn <error <fatal.

If low-level logs can be output, logs with a higher level can also be output.

 

UML

The first time I painted UML, I was a little nervous...

The main purpose is to use a UML diagram to reflect the logger's organizational structure and the relationship between logger and other components. Therefore, many factors are ignored.

Omitted. The subsequent descriptions will be compared with this figure.

 

Logger

Logger inherits from category, and in category, it indicates that

This class has been deprecated andreplaced by the {@link Logger} <em>subclass</em></b></font>. Itwill be kept around to preserve backward compatibility until mid2003.

Name: As your identity, you can use name in the factory method to generate a new logger instance.

Level: Each logger has a Level Attribute. when outputting a log, the logger obtains the Level Attribute by getjavastivelevel ().

Valid level to determine whether the log can be output. The level judgment process will be described in detail later.

Parent: Each logger has a parent node. The parent-child relationship is generated in loggerrepository. It's because of the parent-child relationship.

Therefore, in the geteffectivelevel method, we traverse the parent node and find the first level not empty. That is

If the level of the current node is not explicitly specified, the level of the parent node is used.

You know, there is a public parent node rootlogger.

 1   /** 2      Starting from this category, search the category hierarchy for a 3      non-null level and return it. Otherwise, return the level of the 4      root category. 5  6      <p>The Category class is designed so that this method executes as 7      quickly as possible. 8    */ 9   public10   Level getEffectiveLevel() {11     for(Category c = this; c != null; c=c.parent) {12       if(c.level != null) {13         return c.level;14     }15     }16     return null; // If reached will cause an NullPointerException.17   }
View code

AAI: Each logger can be associated with multiple appender. The received logs are output to each appender in sequence. Logger will

Management proxy to appenderattachableimpl. For example, the addappender operation is actually handled by aII.

  /**     Add <code>newAppender</code> to the list of appenders of this     Category instance.     <p>If <code>newAppender</code> is already in the list of     appenders, then it won‘t be added again.  */  synchronized  public  void addAppender(Appender newAppender) {    if(aai == null) {      aai = new AppenderAttachableImpl();    }    aai.addAppender(newAppender);    repository.fireAddAppenderEvent(this, newAppender);  }
View code

In appenderattachableimpl, only appender is added to vector.

  /**     Attach an appender. If the appender is already in the list in     won‘t be added again.  */  public  void addAppender(Appender newAppender) {    // Null values for newAppender parameter are strictly forbidden.    if(newAppender == null) {        return;    }        if(appenderList == null) {      appenderList = new Vector(1);    }    if(!appenderList.contains(newAppender)) {        appenderList.addElement(newAppender);    }  }
View code

Debug: Similarly, info, error, and so on are all user call logging methods. After determining the level, send the log to the appender for output.

After the log is converted to a loggingevent, callappenders is called to traverse the parent node. Each node calls appenderattachableimpl.

. In fact, in appenderattachableimpl, all appender associated with the current node are traversed and output in sequence.

  public  void debug(Object message) {    if(repository.isDisabled(Level.DEBUG_INT)) {        return;    }    if(Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {      forcedLog(FQCN, Level.DEBUG, message, null);    }  }
View code
  /**     This method creates a new logging event and logs the event     without further checks.  */  protected  void forcedLog(String fqcn, Priority level, Object message, Throwable t) {    callAppenders(new LoggingEvent(fqcn, this, level, message, t));  }
View code
  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);    }  }
View code

 

Loggerrepository

Loggerrepository is the repository for logger management. It provides the factory method getlogger (name) to create a logger instance. And all created

Is logically organized into a tree structure (the parent field of logger ). Each instance has a parent node. The loggerrepository package

Contains a rootlogger Member, which is the sharing ancestor node of all logger. It is precisely because of the existence of this tree structure that operations such as getjavastivelevel

And will traverse the parent node. When no special configuration is made for all child nodes, the attributes of the parent node (Level, outputer) are used ).

Loggerrepository also has the Level Attribute. When logging, you first determine whether the level exceeds the level of the warehouse. This attribute is all by default.

  public  void debug(Object message) {    if(repository.isDisabled(Level.DEBUG_INT)) {        return;    }...
View code
  public  boolean isDisabled(int level) {    return thresholdInt > level;  }
View code

 

Appender

Logger converts the received logs into loggingevents and submits them to the proxy appenderattachableimpl for output through the callappender method.

Appenderattachableimpl, after traversing all associated appender, calls its doappender Method for output in sequence. And every appender

There is also a concept of priority, and other levels are the same as those of logger. Therefore, when the appender executes the output, it is also necessary to determine whether the level meets the requirements.

Before the appender settings. In addition, the appender provides some filters to further control the output (it should be a simple responsibility chain mode ).

 public  synchronized   void doAppend(LoggingEvent event) {    if(closed) {      LogLog.error("Attempted to append to closed appender named ["+name+"].");      return;    }        if(!isAsSevereAsThreshold(event.getLevel())) {      return;    }    Filter f = this.headFilter;        FILTER_LOOP:    while(f != null) {      switch(f.decide(event)) {      case Filter.DENY: return;      case Filter.ACCEPT: break FILTER_LOOP;      case Filter.NEUTRAL: f = f.getNext();      }    }        this.append(event);      }
View code

Of course, you also need to format the output through layout. Format (...) before outputting.

 

Logmagager

This is a user interface that is not shown in the above UML diagram. It mainly provides some factories and some default configurations. For example, the default repository.

At the same time, some factory methods, such as getlogger, are also provided. The content will only be transferred to other modules for implementation.

  static {    // By default we use a DefaultRepositorySelector which always returns ‘h‘.    Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));    repositorySelector = new DefaultRepositorySelector(h);}
View code

Therefore, you can use logger using logmanager and testmain. Class to convert it to name.

public static Logger LOG = LogManager.getLogger(TestMain.class);
View code

 

Summary

When reading the source code, I only had some knowledge about the big framework, such as the Implementation Details of appender and layout. Although log4j is powerful, it is only a record.

Logs. The source code is not complex. If you are interested, read the logs once. For me, this is just the beginning of reading the source code. Hope to learn more in the future

Excellent Design.

 

Logger for log4j source code reading (1)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.