JDK Logging In-depth analysis

Source: Internet
Author: User
Tags string format log4j

Log output is a prerequisite for all systems, and many developers may not be able to relate to the JDK logging modules because they often use log4j. What is the connection. How the JDK logging handles the details.  This week, first analyze the JDK logging mechanism. * * Starting from the example

The use of JDK logging is simple, as shown in the following code, where you can get a logger by using the static method of the Logger class, and then you can enter log entries from the logger you get from anywhere. Like Logger.info ("Main running.") 's Call.

Package com.bes.logging;
 
Import Java.util.logging.Level;
Import Java.util.logging.Logger;
 
public class Loggertest {
      private static Loggerlogger = Logger.getlogger ("com.bes.logging");
      public static void Main (String argv[]) {
               //Log a finetracing message
               logger.info ("main running.");
               Logger.fine ("Doingstuff");
               try {
                         thread.currentthread (). Sleep (1000)//Do some work
               } catch (Exception ex) {
                         Logger.log ( Level.warning, "Trouble sneezing", ex);
               }
               Logger.fine ("Done");
      }

Without any code modifications and JDK configuration changes, running the above example, you will find that the console only appears with the "Main running." Log. The following questions should appear in your brain ...

1, "Main running." Why the log is not output. How to make them appear.

2, the log appears in the time, class name, method name and so on from where the output.

3, why the log will appear in the console.

4, a large system may have many sub modules (which can be easily understood as having many package names), and how to control the individual log levels of these child modules.

5, Expansion: Apache that popular log4j project and JDK logging have contact, how to achieve their own loggermanager.

With these questions, you might be more interested in understanding the logging mechanism of JDK, and this chapter will analyze the mechanism of this simple module for you. * * * Terminology solution: before in-depth analysis, need to master the following terms

==>logger: For logger, you need to know the next few things

1, the code needs to enter the log place will use logger, this is almost a JDK logging module spokesperson, we often use Logger.getlogger ("com.aaa.bbb"); get a logger, Then use logger to do log output.

2,logger is actually just a logical snap-in, and most of its operations are just passing other < roles as a repeater, for example: Logger.getlogger ("XXX") calls will depend on the Logmanager class, When you use logger to enter log information, all handler in logger are called for log input.

The 3,logger is hierarchical, and we can generally understand the parent-child inheritance relationship between package names. Each logger usually has the name of the Java package. Child logger typically inherits logger levels, handler, ResourceBundle names (related to internationalization information) from the parent logger.

4, the entire JVM will have a root logger with an empty name, and all anonymous logger will have root logger as their parent

==>logmanager: The management of all logger within the entire JVM, logger generation, acquisition, and so on, depend on it and also include configuration file reads. Logmanager will have a Hashtable "private hashtable<string,weakreference<logger>> loggers" to store all of the current Logger, If you need to get logger, Hashtable already has a presence logger directly back to Hashtable, if there is no Hashtable in logger, then create a new one at the same time into the Hashtable to save.

==>handler: Used to control log output, For example, the JDK comes with Consolehanlder to redirect the output stream to the System.err output, and every time the logger method is invoked, the handler publish method is invoked, and each logger has multiple handler. We can use handler to enter the log into different places (such as file system or remote socket connection).

==>formatter: Log in the actual output before the need for a certain format words: For example, whether the output time. Time format. Whether to enter the thread name. The use of internationalization information is dependent on formatter.

==>log level: Needless to say, this is an easy to understand one, but also logging why can help us adapt from the development of debugging to the deployment of online and other stages of the log output granularity of different needs. JDK log level from high to Low (231-1)->severe (1000)->warning (900)->info (m)->config (m)->fine Finer (->finest)->all (-231), each level corresponds to a number, and the comparison of the level of the output log depends on the number size comparison. But note: Not only is logger has a level, handler is also a level, that is, if a logger level is fine, the customer wants to enter the fine level of the log, if at this time logger corresponding handler level for info, Then the fine level log is still not output.

To summarize the corresponding relationship:

==>logmanager and logger are 1 pairs of relationships, and the entire JVM runs with only one logmanager, and all logger are in Logmanager

==>logger and handler are many-to-many relationships, logger call all Hanlder for log processing when logging output

==>handler and formatter are a pair of relations, a handler has a formatter for the format of the log processing

==> is clear: logger and level are a pair of relationships, hanlder and level is a one-to-one relationship ***logging configuration:

The JDK default logging configuration file is: $JAVA _home/jre/lib/ Logging.properties, you can use System Properties Java.util.logging.config.file Specify the appropriate configuration file to overwrite the default profile, which typically contains the following sections of the definition:

1, handlers: separate each handler with commas, and these handler will be added to the root logger. That is to say, even if we do not configure the Handler property for other logger, the logger will always find the root logger in the output log to find the input of the handler log.

2,. Level is the log levels of root logger

3,

4, logger configuration, all attributes ending with [. Level] are considered to be defined as the level of a logger, such as Com.bes.server.level=fine is given to [Com.bes.server] The logger definition level is fine. By the way, the logger inheritance relationship is mentioned earlier, and if there is a com.bes.server.webcontainer this logger, and there is no property defined for that logger in the configuration file, it will be from [Com.bes.server] This logger is inherited by attributes. In addition to levels, you can define handler and Useparenthandlers (the default is True) properties for logger, such as com.bes.server.handler= Com.bes.test.ServerFileHandler (needs to be a extends Java.util.logging.Handler class), Com.bes.server.useparenthandlers=false (meaning that com.bes.server this logger log output, the log is only processed once, with its own handler output, will not be passed to the parent logger handler). The following is an example of a JDK configuration file

handlers= java.util.logging.filehandler,java.util.logging.consolehandler
 
. level= INFO
 
Java.util.logging.FileHandler.pattern =%h/java%u.log
java.util.logging.FileHandler.limit = 50000
Java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = Java.util.logging.XMLFormatter
 
java.util.logging.ConsoleHandler.level = INFO
Java.util.logging.ConsoleHandler.formatter =java.util.logging.simpleformatter
 
com.xyz.foo.level = SEVERE
Sun.rmi.transport.tcp.logLevel = FINE
***logging principle of execution acquisition of @@ ZZFCTHOTFIXZ A, the first is to call the logger of the following method to obtain a logger

    public static synchronized Logger GetLogger (String name) {
           Logmanager manager =logmanager.getlogmanager ();
        Returnmanager.demandlogger (name);
    

B, the above call triggers the Java.util.logging.LoggerManager class initialization work, Loggermanager has a static initialization block (this is the ~_~ that will precede the Loggermanager constructor call):

static {accesscontroller.doprivileged (newprivilegedaction<object> () {public Object run () {St
           Ring CNAME =null;
               try {CNAME =system.getproperty ("Java.util.logging.manager"); if (CNAME!=null) {try {Class clz =classloader.getsystemclassloader (). LoadClass
                       (CNAME);
                   Manager= (Logmanager) clz.newinstance (); The catch (ClassNotFoundException ex) {Class clz =thread.currentthread (). Getcontextclassloader (). LoadClass (CN
                      AME);
                   Manager= (Logmanager) clz.newinstance (); (Exceptionex) {System.err.println ("could not load logmanager \" + CN
              Ame+ "" "");
           Ex.printstacktrace ();
           } if (Manager ==null) {manager = Newlogmanager (); } manager.rootlogger= manager.new Rootlogger ();
 
           Manager.addlogger (Manager.rootlogger);
          Logger.global.setLogManager (manager);
 
           Manager.addlogger (Logger.global);
       return null;
}
   }); }

It can be seen from the static initialization block that Loggermanager can be replaced by using System Properties Java.util.logging.manager to specify a class that inherits from Java.util.logging.LoggerManager, such as the one used in Tomcat startup scripts The mechanism to use its own loggermanager.

Whether it is the JDK default Java.util.logging.LoggerManager or custom Loggermanager, the initialization will add two logger to Loggermanager, the root of the name "" Logger, and the logger level is set to the default info, the other is global logger with the name global, and the level is still info.

After the Logmanager "class" Initialization is completed, the configuration file (the default is $java_home/jre/lib/logging.properties) is read, and the key value pairs such as the property name <-> attribute value of the configuration file are saved in memory. It is convenient to use when initializing logger. The GetLogger action initiated by the Logger class in the C,a step will invoke the following method of Java.util.logging.LoggerManager:

     Logger Demandlogger (String name) {
       Logger result =getlogger (name);
       if (result = = null) {Result
           = Newlogger (name, null);
           Addlogger (result);
           Result =getlogger (name);
       return result;
     }

As you can see, Loggermanager first looks up from the existing logger list, and if not, creates a new Looger and adds it to the list. Of course it is important to initialize the logger after the new Looger is initialized, as described in the Java.util.logging.loggermanager#addlogger () method. The modification method sets the logger level according to the configuration file and adds handler to logger.

So far logger has been acquired, and you also need to know that at this time your logger already have levels, handler and other important information, the following will analyze the logic of the output log. output of the @@@ 日志

First, we usually call the methods below the logger class, passing in the log level and the log content.

    public void log (Levellevel, String msg) {
          if (Level.intvalue () < Levelvalue | | Levelvalue = = Offvalue) {return
              ;
          }
          LogRecord lr = new LogRecord (level, msg);
          Dolog (LR);
    

This method can be seen that the logger class is the first level of validation, if the level of validation through, you will create a new LogRecord object, LogRecord In addition to the log level, the log content will contain the call thread information, log time, etc., then call Dolog ( LogRecord LR) method

    private void Dolog (LogRecord lr) {
          lr.setloggername (name);
          String ebname =geteffectiveresourcebundlename ();
          if (ebname!= null) {
              lr.setresourcebundlename (ebname);
              Lr.setresourcebundle (Findresourcebundle (Ebname));
          }
          Log (LR);
    }

The Dolog (LogRecord LR) method sets the ResourceBundle information (which is related to internationalization) and then calls the log (LogRecord record) method directly

   public void log (LogRecord record) {
          if (Record.getlevel (). Intvalue () <levelvalue | | levelvalue = = offvalue) {
              return;
          }
          Synchronized (this) {
              if (filter!= null &&!filter.isloggable (record)) {return
                  ;
              }
          }
          Logger Logger = this;
          while (logger!= null) {
              Handler targets[] = Logger.gethandlers ();
 
              if (targets!= null) {for
                  (int i = 0; i < Targets.length, i++) {
                           targets[i].publish (record);
                       }
              }
 
              if (!logger.getuseparenthandlers ()) {break
                       ;
              }
 
              Logger= logger.getparent ();
          }
    

It is clear that while loops are the most important, first get the handler from the logger and then call the handler publish (Logrecordrecord) method separately. While loops prove that the previous reference to the log to the parent logger processing, of course, also proved that the logger can use the Useparenthandlers property control log does not go to the upper logger pass the argument. So far logger control of the log is almost complete, the next job is to look at the handler, here we take Java.util.logging.ConsoleHandler as an example to illustrate the output of the log.

public class Consolehandler extends Streamhandler {public
    Consolehandler () {
          sealed = false;
          Configure ();
          Setoutputstream (System.err);
          sealed = true;
    }

In addition to the need to invoke its own configure () method for levels, filter, formatter, and so on, the Consolehandler constructor is the most important thing that we are most concerned about is Setoutputstream (System.err) , the system error stream is used as its output. The Consolehandler publish (Logrecordrecord) is inherited from Java.util.logging.StreamHandler, as follows:

Public synchronized void publish (LogRecord record) {
       if (!isloggable) {return
           ;
       }
       String msg;
       try {
           msg =getformatter (). Format (record);
       } catch (Exception ex) {
           //We don ' t want Tothrow a Exception here, But we
           //theexception to any registered ErrorManager.
           ReportError (Null,ex, errormanager.format_failure);
           return;
       }
       
       try {
           if (!doneheader) {
              writer.write (Getformatter (). GetHead (this));
               Doneheader =true;
           }
           Writer.write (msg);
       catch (Exception ex) {
           //We don ' t want Tothrow a Exception here, but We//the theexception to any
           registere D ErrorManager.
           ReportError (Null,ex, errormanager.write_failure);
       }
    

Method logic is also very clear, first of all, call formatter to format the message, explain: The format is actually an important opportunity for international processing. The message is then output directly to the corresponding output stream. It should be noted that handler will also use their level and logrecord level to compare to see whether the actual output log. Summary

At this point, the entire log output process has been parsed. The attentive reader should be able to answer the following four questions.

1, "Main running." Why the log is not output. How to make them appear.

This is the JDK default Logging.properties file configured in the handler level and with the level of all is an info-led, if you want to see the fine level log, you need to modify the Logging.properties file, and make the following two modifications

java.util.logging.consolehandler.level= fine//Modification

com.bes.logging.level=fine//add

2, the log appears in the time, class name, method name and so on from where the output.

Please refer to [java.util.logging.consolehandler.formatter= Java.util.logging.SimpleFormatter] The Java.util.logging.SimpleFormatter class specified in the configuration, and its publicsynchronized String format (LogRecord record) method illustrates everything.

Public synchronized String format (LogRecord record) {StringBuffer SB = new StringBuffer ();
    Minimize memory allocations here.
    Dat.settime (Record.getmillis ());
    Args[0] = dat;
    StringBuffer Text = new StringBuffer ();
    if (formatter = = null) {formatter = new Messageformat (format);
    } formatter.format (args, text, null);
    Sb.append (text);
    Sb.append ("");
    if (record.getsourceclassname ()!= null) {Sb.append (Record.getsourceclassname ());
    else {sb.append (Record.getloggername ());
       } if (Record.getsourcemethodname ()!= null) {Sb.append ("");
    Sb.append (Record.getsourcemethodname ());
    } sb.append (LineSeparator);
   String message = FormatMessage (record);
    Sb.append (Record.getlevel (). Getlocalizedname ());
    Sb.append (":");
    Sb.append (message);
    Sb.append (LineSeparator);
          if (Record.getthrown ()!= null) {try {stringwriter SW = Newstringwriter ();  PrintWriter pw = newprintwriter (SW);
            Record.getthrown (). Printstacktrace (PW);
             Pw.close ();
        Sb.append (Sw.tostring ());
The catch (Exception ex) {}} return sb.tostring (); }

3, why the log will appear in the console.

See the [Setoutputstream (SYSTEM.ERR)] statement in the Java.util.logging.ConsoleHandler class construct method, I believe you already understand.

4, a large system may have many sub modules (which can be easily understood as having many package names), and how to control the individual log levels of these child modules.

The level of each logger is defined in the Logging.properties file, and it is best to specify your own profile using the Java.util.logging.config.file property.

The 5th question can not be answered for the time being, please keep looking, the next blog post will describe the relationship between log4j and JDK logging, and how to implement your loggermanager so that we can fully customize logger, handler, formatter, Control the internationalization of the log information, and so on.

Copy Search Replication Search

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.