| <html> |
| <head> |
| <title>log4j manual</title> |
| </head> |
| |
| <body bgcolor="white"> |
| |
| <center> |
| <h1>Short introduction to log4j</h1> |
| |
| <font size="+2">Ceki Gülcü</font> |
| <br><br> |
| March 2002 |
| <br> |
| </center> |
| |
| <p> |
| Copyright © 2000-2002 The Apache Software Foundation. All |
| rights reserved. This software is published under the terms of |
| the Apache Software License version 1.1, a copy of which has |
| been included in the LICENSE.txt file shipped with the log4j |
| distribution. This document is based on the article <a |
| href="http://www.javaworld.com/jw-11-2000/jw-1122-log4j.html">"Log4j |
| delivers control over logging"</a> published in November 2000 |
| edition of JavaWorld. However, the present article contains more |
| detailed and up to date information. The present short manual |
| also borrows some text from <a |
| href="https://www.qos.ch/shop/products/eclm/">"<em>The |
| complete log4j manual</em>"</a> by the same author (yours |
| truly). |
| |
| <h2>Abstract</h2> |
| |
| <p>This document describes the log4j API, its unique features and |
| design rationale. Log4j is an open source project based on the work of |
| many authors. It allows the developer to control which log statements |
| are output with arbitrary granularity. It is fully configurable at |
| runtime using external configuration files. Best of all, log4j has a |
| gentle learning curve. Beware: judging from user feedback, it is also |
| quite addictive. |
| |
| <h2>Introduction</h2> |
| |
| <p>Almost every large application includes its own logging or tracing |
| API. In conformance with this rule, the E.U. <a |
| href="http://www.semper.org">SEMPER</a> project decided to write its |
| own tracing API. This was in early 1996. After countless enhancements, |
| several incarnations and much work that API has evolved to become |
| log4j, a popular logging package for Java. The package is distributed |
| under the <a href=../LICENSE.txt>Apache Software License</a>, a |
| fully-fledged open source license certified by the <a |
| href="http://www.opensource.org">open source</a> initiative. The |
| latest log4j version, including full-source code, class files and |
| documentation can be found at <a |
| href="http://logging.apache.org/log4j/"><b>http://logging.apache.org/log4j/</b></a>. |
| By the way, log4j has been ported to the C, C++, C#, Perl, Python, |
| Ruby, and Eiffel languages. |
| |
| <p>Inserting log statements into code is a low-tech method for |
| debugging it. It may also be the only way because debuggers are not |
| always available or applicable. This is usually the case for |
| multithreaded applications and distributed applications at large. |
| |
| <p>Experience indicates that logging was an important component of the |
| development cycle. It offeres several advantages. It provides precise |
| <em>context</em> about a run of the application. Once inserted into |
| the code, the generation of logging output requires no human |
| intervention. Moreover, log output can be saved in persistent medium |
| to be studied at a later time. In addition to its use in the |
| development cycle, a sufficiently rich logging package can also be |
| viewed as an auditing tool. |
| |
| <p>As Brian W. Kernighan and Rob Pike put it in their truly excellent |
| book <i>"The Practice of Programming"</i> |
| <pre> |
| As personal choice, we tend not to use debuggers beyond getting a |
| stack trace or the value of a variable or two. One reason is that it |
| is easy to get lost in details of complicated data structures and |
| control flow; we find stepping through a program less productive |
| than thinking harder and adding output statements and self-checking |
| code at critical places. Clicking over statements takes longer than |
| scanning the output of judiciously-placed displays. It takes less |
| time to decide where to put print statements than to single-step to |
| the critical section of code, even assuming we know where that |
| is. More important, debugging statements stay with the program; |
| debugging sessions are transient. |
| </pre> |
| |
| <p>Logging does have its drawbacks. It can slow down an |
| application. If too verbose, it can cause scrolling blindness. To |
| alleviate these concerns, log4j is designed to be reliable, fast and |
| extensible. Since logging is rarely the main focus of an application, |
| the log4j API strives to be simple to understand and to use. |
| |
| <h2>Loggers, Appenders and Layouts</h2> |
| |
| <p>Log4j has three main components: <em>loggers</em>, |
| <em>appenders</em> and <em>layouts</em>. These three types of |
| components work together to enable developers to log messages according |
| to message type and level, and to control at runtime how these |
| messages are formatted and where they are reported. |
| |
| <h3>Logger hierarchy</h3> |
| |
| <p>The first and foremost advantage of any logging API over plain |
| <code>System.out.println</code> resides in its ability to disable |
| certain log statements while allowing others to print unhindered. This |
| capability assumes that the logging space, that is, the space of all |
| possible logging statements, is categorized according to some |
| developer-chosen criteria. This observation had previously led us to |
| choose <em>category</em> as the central concept of the |
| package. However, since log4j version 1.2, <code>Logger</code> class |
| has replaced the <code>Category</code> class. For those familiar with |
| earlier versions of log4j, the <code>Logger</code> class can be |
| considered as a mere alias to the <code>Category</code> class. |
| |
| <p>Loggers are named entities. Logger names are case-sensitive and |
| they follow the hierarchical naming rule: |
| |
| <p> |
| <table bgcolor="#EEEE99"> |
| <tr> |
| <td> |
| <dl> |
| <dt><b>Named Hierarchy</b> |
| |
| <dd><p>A logger is said to be an <em>ancestor</em> of another |
| logger if its name followed by a dot is a prefix of the |
| <em>descendant</em> logger name. A logger is said to be a |
| <em>parent</em> of a <em>child</em> logger if there are no |
| ancestors between itself and the descendant logger. |
| |
| |
| </dl> |
| </table> |
| |
| |
| <p>For example, the logger named <code>"com.foo"</code> is a parent |
| of the logger named <code>"com.foo.Bar"</code>. Similarly, |
| <code>"java"</code> is a parent of <code>"java.util"</code> and an |
| ancestor of <code>"java.util.Vector"</code>. This naming scheme |
| should be familiar to most developers. |
| |
| <p>The root logger resides at the top of the logger hierarchy. It |
| is exceptional in two ways: |
| |
| <ol> |
| <li> it always exists, |
| <li> it cannot be retrieved by name. |
| </ol> |
| <p>Invoking the class static <a |
| href="api/org/apache/log4j/Logger.html#getRootLogger()">Logger.getRootLogger</a> |
| method retrieves it. All other loggers are instantiated and |
| retrieved with the class static <a |
| href="api/org/apache/log4j/Logger.html#getLogger()">Logger.getLogger</a> |
| method. This method takes the name of the desired logger as a |
| parameter. Some of the basic methods in the Logger class are listed |
| below. |
| |
| <p><table> |
| <tr bgcolor="CCCCCC"> |
| <td> |
| <pre> |
| package org.apache.log4j; |
| |
| public class <b>Logger</b> { |
| |
| // Creation & retrieval methods: |
| public static Logger getRootLogger(); |
| public static Logger getLogger(String name); |
| |
| // printing methods: |
| public void debug(Object message); |
| public void info(Object message); |
| public void warn(Object message); |
| public void error(Object message); |
| public void fatal(Object message); |
| |
| // generic printing method: |
| public void log(Level l, Object message); |
| } |
| </pre> |
| </td> |
| </table> |
| |
| <p>Loggers <em>may</em> be assigned levels. The set of possible |
| levels, that is |
| |
| <a href="api/org/apache/log4j/Level.html#DEBUG">DEBUG</a>, |
| <a href="api/org/apache/log4j/Level.html#INFO">INFO</a>, |
| <a href="api/org/apache/log4j/Level.html#WARN">WARN</a>, |
| <a href="api/org/apache/log4j/Level.html#ERROR">ERROR</a> and |
| <a href="api/org/apache/log4j/Level.html#FATAL">FATAL</a> |
| |
| are defined in the <code><a |
| href="api/org/apache/log4j/Level.html">org.apache.log4j.Level</a></code> |
| class. Although we do not encourage you to do so, you may define |
| your own levels by sub-classing the <code>Level</code> class. A |
| perhaps better approach will be explained later on. |
| |
| <p>If a given logger is not assigned a level, then it inherits |
| one from its closest ancestor with an assigned level. More |
| formally: |
| |
| |
| <p> |
| <table bgcolor="#EEEE99"> |
| <tr> |
| <td> |
| <dl> |
| <dt><b>Level Inheritance</b> |
| |
| <dd><p>The <em>inherited level</em> for a given logger |
| <i>C</i>, is equal to the first non-null level in the logger |
| hierarchy, starting at <i>C</i> and proceeding upwards in the |
| hierarchy towards the <code>root</code> logger. |
| |
| </dl> |
| </table> |
| |
| <p>To ensure that all loggers can eventually inherit a level, |
| the root logger always has an assigned level. |
| |
| <p>Below are four tables with various assigned level values and the |
| resulting inherited levels according to the above rule. |
| |
| <p> |
| <table border="1" > |
| <tr><th>Logger<br>name</th><th>Assigned<br>level</th> |
| <th>Inherited<br>level</th></tr> |
| <tr align=left><td>root</td> <td>Proot</td> <td>Proot</td></tr> |
| <tr align=left><td>X </td> <td>none</td> <td>Proot</td></tr> |
| <tr align=left><td>X.Y </td> <td>none</td> <td>Proot</td></tr> |
| <tr align=left><td>X.Y.Z</td> <td>none</td> <td>Proot</td></tr> |
| <caption align=bottom>Example 1</caption> |
| </table> |
| |
| <p>In example 1 above, only the root logger is assigned a |
| level. This level value, <code>Proot</code>, is inherited by the |
| other loggers <code>X</code>, <code>X.Y</code> and |
| <code>X.Y.Z</code>. |
| |
| |
| <p> |
| <table border="1"> |
| <tr><th>Logger<br>name</th><th>Assigned<br>level</th> |
| <th>Inherited<br>level</th></tr> |
| <tr align=left><td>root</td> <td>Proot</td> <td>Proot</td></tr> |
| <tr align=left><td>X </td> <td>Px</td> <td>Px</td></tr> |
| <tr align=left><td>X.Y </td> <td>Pxy</td> <td>Pxy</td></tr> |
| <tr align=left><td>X.Y.Z</td> <td>Pxyz</td> <td>Pxyz</td></tr> |
| <caption align=bottom>Example 2</caption> |
| </table> |
| |
| <p>In example 2, all loggers have an assigned level value. There |
| is no need for level inheritence. |
| |
| <p><table border="1"> |
| <tr><th>Logger<br>name</th><th>Assigned<br>level</th> |
| <th>Inherited<br>level</th></tr> |
| <tr align=left><td>root</td> <td>Proot</td> <td>Proot</td></tr> |
| <tr align=left><td>X </td> <td>Px</td> <td>Px</td></tr> |
| <tr align=left><td>X.Y </td> <td>none</td> <td>Px</td></tr> |
| <tr align=left><td>X.Y.Z</td> <td>Pxyz</td> <td>Pxyz</td></tr> |
| <caption align=bottom>Example 3</caption> |
| </table> |
| |
| <p>In example 3, the loggers <code>root</code>, <code>X</code> and |
| <code>X.Y.Z</code> are assigned the levels <code>Proot</code>, |
| <code>Px</code> and <code>Pxyz</code> respectively. The logger |
| <code>X.Y</code> inherits its level value from its parent |
| <code>X</code>. |
| |
| <table border=1> |
| <tr><th>Logger<br>name</th><th>Assigned<br>level</th> |
| <th>Inherited<br>level</th></tr> |
| <tr align=left><td>root</td> <td>Proot</td> <td>Proot</td></tr> |
| <tr align=left><td>X </td> <td>Px</td> <td>Px</td></tr> |
| <tr align=left><td>X.Y </td> <td>none</td> <td>Px</td></tr> |
| <tr align=left><td>X.Y.Z</td> <td>none</td> <td>Px</td></tr> |
| <caption align=bottom>Example 4</caption> |
| </table> |
| |
| <p>In example 4, the loggers <code>root</code> and <code>X</code> |
| and are assigned the levels <code>Proot</code> and <code>Px</code> |
| respectively. The loggers <code>X.Y</code> and <code>X.Y.Z</code> |
| inherits their level value from their nearest parent <code>X</code> |
| having an assigned level.. |
| |
| |
| <p>Logging requests are made by invoking one of the printing methods |
| of a logger instance. These printing methods are |
| |
| <code> |
| <a href="api/org/apache/log4j/Logger.html#debug(java.lang.Object)">debug</a>, |
| |
| <a href="api/org/apache/log4j/Logger.html#info(java.lang.Object)">info</a>, |
| |
| <a href="api/org/apache/log4j/Logger.html#warn(java.lang.Object)">warn</a>, |
| <a href="api/org/apache/log4j/Logger.html#error(java.lang.Object)">error</a>, |
| <a href="api/org/apache/log4j/Logger.html#fatal(java.lang.Object)">fatal</a> |
| and <a href="api/org/apache/log4j/Logger.html#log(org.apache.log4j.Level, java.lang.Object)">log</a></code>. |
| |
| |
| <p>By definition, the printing method determines the level of a |
| logging request. For example, if <code>c</code> is a logger |
| instance, then the statement <code>c.info("..")</code> is a logging |
| request of level INFO. |
| |
| <p>A logging request is said to be <em>enabled</em> if its level is |
| higher than or equal to the level of its logger. Otherwise, the |
| request is said to be <em>disabled</em>. A logger without an |
| assigned level will inherit one from the hierarchy. This rule is |
| summarized below. |
| |
| |
| <p> |
| <a name="selectionRule"><table bgcolor="#EEEE99"> |
| <tr> |
| <td> |
| <dl> |
| <dt><b>Basic Selection Rule</b> |
| |
| <dd><p>A log request of level <i>p</i> in a logger with |
| (either assigned or inherited, whichever is appropriate) level <i>q</i>, is enabled if <i> p >= |
| q</i>. |
| </dl> |
| </table> |
| |
| <p>This rule is at the heart of log4j. It assumes that levels are |
| ordered. For the standard levels, we have <code>DEBUG < INFO |
| < WARN < ERROR < FATAL</code>. |
| |
| <p>Here is an example of this rule. |
| |
| <p><table bgcolor="CCCCCC"> |
| <tr><td> |
| <pre> |
| |
| // get a logger instance named "com.foo" |
| Logger logger = Logger.getLogger(<strong>"com.foo"</strong>); |
| |
| // Now set its level. Normally you do not need to set the |
| // level of a logger programmatically. This is usually done |
| // in configuration files. |
| <strong>logger</strong>.setLevel(<font |
| color="0000AA"><strong>Level.INFO</strong></font>); |
| |
| Logger barlogger = Logger.getLogger(<strong>"com.foo.Bar"</strong>); |
| |
| // This request is enabled, because <font color="00AA00"><strong>WARN</strong></font> >= <font color="0000AA"><strong>INFO</strong></font>. |
| logger.<font color="00AA00"><strong>warn</strong></font>("Low fuel level."); |
| |
| // This request is disabled, because <font color="00AA00"><strong>DEBUG</strong></font> < <font color="0000AA"><strong>INFO</strong></font>. |
| logger.<font color="00AA00"><strong>debug</strong></font>("Starting search for nearest gas station."); |
| |
| // The logger instance barlogger, named "com.foo.Bar", |
| // will inherit its level from the logger named |
| // "com.foo" Thus, the following request is enabled |
| // because <font color="00AA00"><strong>INFO</strong></font> >= <font color="0000AA"><strong>INFO</strong></font>. |
| barlogger.<font color="00AA00"><strong>info</strong></font>("Located nearest gas station."); |
| |
| // This request is disabled, because <font color="00AA00"><strong>DEBUG</strong></font> < <font color="0000AA"><strong>INFO</strong></font>. |
| barlogger.<font color="00AA00"><strong>debug</strong></font>("Exiting gas station search"); |
| </pre> |
| </table> |
| |
| <p>Calling the <code>getLogger</code> method with the same name will |
| always return a reference to the exact same logger object. |
| |
| <p>For example, in |
| |
| <table bgcolor="CCCCCC"> |
| <tr><td> |
| <pre> |
| Logger x = Logger.getLogger("wombat"); |
| Logger y = Logger.getLogger("wombat");</pre> |
| </td> |
| </table> |
| <code>x</code> and <code>y</code> refer to <em>exactly</em> the same |
| logger object. |
| |
| <p>Thus, it is possible to configure a logger and then to retrieve |
| the same instance somewhere else in the code without passing around |
| references. In fundamental contradiction to biological parenthood, |
| where parents always preceed their children, log4j loggers can be |
| created and configured in any order. In particular, a "parent" |
| logger will find and link to its descendants even if it is |
| instantiated after them. |
| |
| <p>Configuration of the log4j environment is typically done at |
| application initialization. The preferred way is by reading a |
| configuration file. This approach will be discussed shortly. |
| |
| <p>Log4j makes it easy to name loggers by <em>software |
| component</em>. This can be accomplished by statically instantiating |
| a logger in each class, with the logger name equal to the fully |
| qualified name of the class. This is a useful and straightforward |
| method of defining loggers. As the log output bears the name of the |
| generating logger, this naming strategy makes it easy to identify |
| the origin of a log message. However, this is only one possible, |
| albeit common, strategy for naming loggers. Log4j does not restrict |
| the possible set of loggers. The developer is free to name the |
| loggers as desired. |
| |
| <p>Nevertheless, naming loggers after the class where they are |
| located seems to be the best strategy known so far. |
| |
| <h2>Appenders and Layouts</h2> |
| |
| <p>The ability to selectively enable or disable logging requests based |
| on their logger is only part of the picture. Log4j allows logging |
| requests to print to multiple destinations. In log4j speak, an output |
| destination is called an <em>appender</em>. Currently, appenders exist |
| for the <a href="api/org/apache/log4j/ConsoleAppender.html">console</a>, <a |
| href="api/org/apache/log4j/FileAppender.html">files</a>, GUI |
| components, <a |
| href="api/org/apache/log4j/net/SocketAppender.html">remote socket</a> |
| servers, <a |
| href="api/org/apache/log4j/net/JMSAppender.html">JMS</a>, |
| |
| <a href="api/org/apache/log4j/nt/NTEventLogAppender.html"> NT |
| Event Loggers</a>, and remote UNIX <a |
| href="api/org/apache/log4j/net/SyslogAppender.html">Syslog</a> |
| daemons. It is also possible to log <a href="api/org/apache/log4j/AsyncAppender.html">asynchronously</a>. |
| |
| <p>More than one appender can be attached to a logger. |
| |
| <p>The <a |
| href="api/org/apache/log4j/Logger.html#addAppender(org.apache.log4j.Appender)">addAppender</a> |
| method adds an appender to a given logger. |
| |
| <b>Each enabled logging |
| request for a given logger will be forwarded to all the appenders in |
| that logger as well as the appenders higher in the hierarchy.</b> In |
| other words, appenders are inherited additively from the logger |
| hierarchy. For example, if a console appender is added to the root |
| logger, then all enabled logging requests will at least print on the |
| console. If in addition a file appender is added to a logger, say |
| <em>C</em>, then enabled logging requests for <em>C</em> and |
| <em>C</em>'s children will print on a file <em>and</em> on the |
| console. It is possible to override this default behavior so that |
| appender accumulation is no longer additive by <a |
| href="api/org/apache/log4j/Logger.html#setAdditivity(boolean)">setting |
| the additivity flag</a> to <code>false</code>. |
| |
| <p>The rules governing appender additivity are summarized below. |
| |
| <p> |
| <a name="additivity"><table bgcolor="#EEEE99"> |
| <tr> |
| <td> |
| <dl> |
| <dt><b>Appender Additivity</b> |
| |
| <dd><p>The output of a log statement of logger <i>C</i> will |
| go to all the appenders in <i>C</i> and its ancestors. This is |
| the meaning of the term "appender additivity". |
| |
| <p>However, if an ancestor of logger <i>C</i>, say <i>P</i>, |
| has the additivity flag set to <code>false</code>, then |
| <i>C</i>'s output will be directed to all the appenders in |
| <i>C</i> and it's ancestors upto and including <i>P</i> but |
| not the appenders in any of the ancestors of <i>P</i>. |
| |
| <p>Loggers have their additivity flag set to |
| <code>true</code> by default. |
| </dl> |
| </table> |
| |
| |
| <p>The table below shows an example: |
| |
| <p><table align=center border=3 cellpadding=10> |
| <tr rowspan="2"> |
| <th>Logger<br>Name <th>Added<br>Appenders <th>Additivity<br>Flag <th>Output Targets <th>Comment |
| |
| <tr><td>root <td>A1 <td>not applicable <td>A1 |
| |
| <td>The root logger is anonymous but can be accessed with the |
| Logger.getRootLogger() method. There is no default appender |
| attached to root. |
| |
| <tr><td>x <td>A-x1, A-x2 <td>true <td>A1, A-x1, A-x2 |
| <td>Appenders of "x" and root. |
| |
| <tr><td>x.y <td>none <td>true <td>A1, A-x1, A-x2 |
| <td>Appenders of "x" and root. |
| |
| <tr><td>x.y.z <td>A-xyz1 <td>true <td>A1, A-x1, A-x2, A-xyz1 |
| <td>Appenders in "x.y.z", "x" and root. |
| |
| <tr><td>security <td>A-sec <td><font color="blue">false</font> |
| <td>A-sec |
| |
| <td>No appender accumulation since the additivity flag is set to |
| <code>false</code>. |
| |
| <tr><td>security.access <td>none <td> true <td> A-sec <td>Only |
| appenders of "security" because the additivity flag in "security" is |
| set to <code>false</code>. |
| |
| </table> |
| |
| |
| <p>More often than not, users wish to customize not only the output |
| destination but also the output format. This is accomplished by |
| associating a <em>layout</em> with an appender. The layout is |
| responsible for formatting the logging request according to the user's |
| wishes, whereas an appender takes care of sending the formatted output |
| to its destination. |
| |
| The <a |
| href="api/org/apache/log4j/PatternLayout.html">PatternLayout</a>, part |
| of the standard log4j distribution, lets the user specify the output |
| format according to conversion patterns similar to the C language |
| <code>printf</code> function. |
| |
| <p>For example, the PatternLayout with the conversion pattern "%r [%t] |
| %-5p %c - %m%n" will output something akin to: |
| |
| <pre> |
| 176 [main] INFO org.foo.Bar - Located nearest gas station. |
| </pre> |
| |
| <p>The first field is the number of milliseconds elapsed since the |
| start of the program. The second field is the thread making the log |
| request. The third field is the level of the log statement. The |
| fourth field is the name of the logger associated with the log |
| request. The text after the '-' is the message of the statement. |
| |
| <p>Just as importantly, log4j will render the content of the log |
| message according to user specified criteria. For example, if you |
| frequently need to log <code>Oranges</code>, an object type used in |
| your current project, then you can register an |
| <code>OrangeRenderer</code> that will be invoked whenever an orange |
| needs to be logged. |
| |
| <p>Object rendering follows the class hierarchy. For example, assuming |
| oranges are fruits, if you register an <code>FruitRenderer</code>, all |
| fruits including oranges will be rendered by the |
| <code>FruitRenderer</code>, unless of course you registered an orange |
| specific <code>OrangeRenderer</code>. |
| |
| <p>Object renderers have to implement the |
| <a href="api/org/apache/log4j/or/ObjectRenderer.html">ObjectRenderer</a> |
| interface. |
| |
| |
| <h2>Configuration</h2> |
| |
| <p>Inserting log requests into the application code requires a fair |
| amount of planning and effort. Observation shows that approximately 4 |
| percent of code is dedicated to logging. Consequently, even moderately |
| sized applications will have thousands of logging statements embedded |
| within their code. Given their number, it becomes imperative to |
| manage these log statements without the need to modify them manually. |
| |
| <p>The log4j environment is fully configurable programmatically. |
| However, it is far more flexible to configure log4j using |
| configuration files. Currently, configuration files can be written in |
| XML or in Java properties (key=value) format. |
| |
| <p>Let us give a taste of how this is done with the help of an |
| imaginary application <code>MyApp</code> that uses log4j. |
| |
| <p><table bgcolor="CCCCCC"><tr><td> |
| <pre> |
| import com.foo.Bar; |
| |
| // Import log4j classes. |
| <b>import org.apache.log4j.Logger; |
| import org.apache.log4j.BasicConfigurator;</b> |
| |
| public class MyApp { |
| |
| // Define a static logger variable so that it references the |
| // Logger instance named "MyApp". |
| <strong>static</strong> Logger logger = <strong>Logger.getLogger(MyApp.class);</strong> |
| |
| public static void main(String[] args) { |
| |
| // Set up a simple configuration that logs on the console. |
| <strong>BasicConfigurator.configure();</strong> |
| |
| logger.info("Entering application."); |
| Bar bar = new Bar(); |
| bar.doIt(); |
| logger.info("Exiting application."); |
| } |
| } |
| </pre> |
| </table> |
| |
| <p><code>MyApp</code> begins by importing log4j related classes. It |
| then defines a static logger variable with the name |
| <code>MyApp</code> which happens to be the fully qualified name of the |
| class. |
| |
| <p><code>MyApp</code> uses the <code>Bar</code> class defined in the |
| package <code>com.foo</code>. |
| |
| <p><table bgcolor="CCCCCC"><tr><td> |
| <pre> |
| <b>package com.foo;</b> |
| import org.apache.log4j.Logger; |
| |
| public class Bar { |
| <strong>static</strong> Logger logger = <strong>Logger.getLogger(Bar.class);</strong> |
| |
| public void doIt() { |
| logger.debug("Did it again!"); |
| } |
| } |
| </pre> |
| </table> |
| |
| <p>The invocation of the <a |
| href="api/org/apache/log4j/BasicConfigurator.html#configure()">BasicConfigurator.configure</a> |
| method creates a rather simple log4j setup. This method is hardwired |
| to add to the root logger a <a |
| href="api/org/apache/log4j/ConsoleAppender.html"> |
| ConsoleAppender</a>. The output will be formatted using a <a |
| href="api/org/apache/log4j/PatternLayout.html">PatternLayout</a> set |
| to the pattern "%-4r [%t] %-5p %c %x - %m%n". |
| |
| <p>Note that by default, the root logger is assigned to |
| <code>Level.DEBUG</code>. |
| |
| <p>The output of MyApp is: |
| <pre> |
| 0 [main] INFO MyApp - Entering application. |
| 36 [main] DEBUG com.foo.Bar - Did it again! |
| 51 [main] INFO MyApp - Exiting application. |
| </pre> |
| |
| <p>The figure below depicts the object diagram of <code>MyApp</code> |
| after just having called the <code>BasicConfigurator.configure</code> |
| method. |
| |
| <p> |
| <center> |
| <img src="od.gif" align="center" > |
| </center> |
| |
| <p>As a side note, let me mention that in log4j child loggers link |
| only to their existing ancestors. In particular, the logger named |
| <code>com.foo.Bar</code> is linked directly to the <code>root</code> |
| logger, thereby circumventing the unused <code>com</code> or |
| <code>com.foo</code> loggers. This significantly increases |
| performance and reduces log4j's memory footprint. |
| |
| |
| <p>The <code>MyApp</code> class configures log4j by invoking |
| <code>BasicConfigurator.configure</code> method. Other classes only |
| need to import the <code>org.apache.log4j.Logger</code> class, |
| retrieve the loggers they wish to use, and log away. |
| |
| <p>The previous example always outputs the same log information. |
| Fortunately, it is easy to modify <code>MyApp</code> so that the log |
| output can be controlled at run-time. Here is a slightly modified |
| version. |
| |
| <p><table bgcolor="CCCCCC"><tr><td> |
| <pre> |
| import com.foo.Bar; |
| |
| import org.apache.log4j.Logger; |
| <b>import org.apache.log4j.PropertyConfigurator;</b> |
| |
| public class MyApp { |
| |
| static Logger logger = Logger.getLogger(MyApp.class.getName()); |
| |
| public static void main(String[] args) { |
| |
| |
| // BasicConfigurator replaced with PropertyConfigurator. |
| <strong>PropertyConfigurator.configure(args[0]);</strong> |
| |
| logger.info("Entering application."); |
| Bar bar = new Bar(); |
| bar.doIt(); |
| logger.info("Exiting application."); |
| } |
| } |
| </pre> |
| </table> |
| |
| <p>This version of <code>MyApp</code> instructs |
| <code>PropertyConfigurator</code> to parse a configuration file and |
| set up logging accordingly. |
| |
| <p>Here is a sample configuration file that results in exactly same |
| output as the previous <code>BasicConfigurator</code> based example. |
| |
| <p><table bgcolor="CCAAAA"><tr><td> |
| <pre> |
| # Set root logger level to DEBUG and its only appender to A1. |
| log4j.rootLogger=DEBUG, A1 |
| |
| # A1 is set to be a ConsoleAppender. |
| log4j.appender.A1=org.apache.log4j.ConsoleAppender |
| |
| # A1 uses PatternLayout. |
| log4j.appender.A1.layout=org.apache.log4j.PatternLayout |
| log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n |
| </pre> |
| </table> |
| <!-- <p>Please note that if you copy and paste the examples, then result is |
| likely to include trailing spaces on some lines. These trailing spaces |
| are not trimmed out but interpreted by the PropertyConfigurator. By |
| the time you read this article the problem should be corrected. |
| --> |
| |
| <p>Suppose we are no longer interested in seeing the output of any |
| component belonging to the <code>com.foo</code> package. The following |
| configuration file shows one possible way of achieving this. |
| |
| <p><table bgcolor="CCAAAA"><tr><td> |
| <pre> |
| log4j.rootLogger=DEBUG, A1 |
| log4j.appender.A1=org.apache.log4j.ConsoleAppender |
| log4j.appender.A1.layout=org.apache.log4j.PatternLayout |
| |
| # <strong>Print the date in ISO 8601 format</strong> |
| log4j.appender.A1.layout.ConversionPattern=<strong>%d</strong> [%t] %-5p %c - %m%n |
| |
| # Print only messages of level WARN or above in the package com.foo. |
| <strong>log4j.logger.com.foo=WARN</strong> |
| </pre> |
| </table> |
| |
| <p>The output of <code>MyApp</code> configured with this file is shown below. |
| |
| <pre> |
| <strong>2000-09-07 14:07:41,508</strong> [main] INFO MyApp - Entering application. |
| <strong>2000-09-07 14:07:41,529</strong> [main] INFO MyApp - Exiting application. |
| </pre> |
| |
| <p>As the logger <code>com.foo.Bar</code> does not have an assigned |
| level, it inherits its level from <code>com.foo</code>, which |
| was set to WARN in the configuration file. The log statement from the |
| <code>Bar.doIt</code> method has the level DEBUG, lower than the |
| logger level WARN. Consequently, <code>doIt()</code> method's log |
| request is suppressed. |
| |
| <p>Here is another configuration file that uses multiple appenders. |
| |
| <p><table bgcolor="CCAAAA"><tr><td> |
| <pre> |
| log4j.rootLogger=debug, <strong>stdout, R</strong> |
| |
| log4j.appender.<strong>stdout</strong>=org.apache.log4j.ConsoleAppender |
| log4j.appender.stdout.layout=org.apache.log4j.PatternLayout |
| |
| # Pattern to output the caller's file name and line number. |
| log4j.appender.stdout.layout.ConversionPattern=%5p [%t] <strong>(%F:%L)</strong> - %m%n |
| |
| log4j.appender.<strong>R</strong>=org.apache.log4j.RollingFileAppender |
| log4j.appender.R.File=example.log |
| |
| log4j.appender.R.MaxFileSize=<strong>100KB</strong> |
| # Keep one backup file |
| log4j.appender.R.MaxBackupIndex=1 |
| |
| log4j.appender.R.layout=org.apache.log4j.PatternLayout |
| log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n |
| </pre> |
| </table> |
| |
| <p>Calling the enhanced MyApp with the this configuration file will |
| output the following on the console. |
| |
| <pre> |
| INFO [main] <strong>(MyApp2.java:12)</strong> - Entering application. |
| DEBUG [main] (Bar.java:8) - Doing it again! |
| INFO [main] (MyApp2.java:15) - Exiting application. |
| </pre> |
| |
| <p>In addition, as the root logger has been allocated a second |
| appender, output will also be directed to the <code>example.log</code> |
| file. This file will be rolled over when it reaches 100KB. When |
| roll-over occurs, the old version of <code>example.log</code> is |
| automatically moved to <code>example.log.1</code>. |
| |
| <p>Note that to obtain these different logging behaviors we did not |
| need to recompile code. We could just as easily have logged to a UNIX |
| Syslog daemon, redirected all <code>com.foo</code> output to an NT |
| Event logger, or forwarded logging events to a remote log4j server, |
| which would log according to local server policy, for example by |
| forwarding the log event to a second log4j server. |
| |
| <a name="defaultInit"><h2>Default Initialization Procedure</h2> |
| |
| <p>The log4j library does not make any assumptions about its |
| environment. In particular, there are no default log4j |
| appenders. Under certain well-defined circumstances however, the |
| static inializer of the <code>Logger</code> class will attempt to |
| automatically configure log4j. The Java language guarantees that the |
| static initializer of a class is called once and only once during the |
| loading of a class into memory. It is important to remember that |
| different classloaders may load distinct copies of the same |
| class. These copies of the same class are considered as totally |
| unrelated by the JVM. |
| |
| <p>The default initialization is very useful in environments where the |
| exact entry point to the application depends on the runtime |
| environment. For example, the same application can be used as a |
| stand-alone application, as an applet, or as a servlet under the |
| control of a web-server. |
| |
| <p>The exact default initialization algorithm is defined as follows: |
| |
| <ol> |
| |
| <li>Setting the <b>log4j.defaultInitOverride</b> system property to |
| any other value then "false" will cause log4j to skip the default |
| initialization procedure (this procedure). |
| |
| <p><li>Set the <code>resource</code> string variable to the value of |
| the <b>log4j.configuration</b> system property. <em>The preferred |
| way to specify the default initialization file is through the |
| <b>log4j.configuration</b> system property.</em> In case the system |
| property <b>log4j.configuration</b> is not defined, then set the |
| string variable <code>resource</code> to its default value |
| "log4j.properties". |
| |
| <p><li>Attempt to convert the <code>resource</code> variable to a |
| URL. |
| |
| <p><li>If the resource variable cannot be converted to a URL, for |
| example due to a <code>MalformedURLException</code>, then search for |
| the <code>resource</code> from the classpath by calling |
| <code>org.apache.log4j.helpers.Loader.getResource(resource, |
| Logger.class)</code> which returns a URL. Note that the string |
| "log4j.properties" constitutes a malformed URL. |
| |
| <p>See <a |
| href="api/org/apache/log4j/helpers/Loader.html#getResource(java.lang.String)">Loader.getResource(java.lang.String)</a> |
| for the list of searched locations. |
| |
| <p><li>If no URL could not be found, abort default |
| initialization. Otherwise, configure log4j from the URL. |
| |
| <p>The <a |
| href="api/org/apache/log4j/PropertyConfigurator.html">PropertyConfigurator</a> |
| will be used to parse the URL to configure log4j unless the URL ends |
| with the ".xml" extension, in which case the <a |
| href="api/org/apache/log4j/xml/DOMConfigurator.html">DOMConfigurator</a> |
| will be used. You can optionaly specify a custom configurator. The |
| value of the <b>log4j.configuratorClass</b> system property is taken |
| as the fully qualified class name of your custom configurator. The |
| custom configurator you specify <em>must</em> implement the <a |
| href="api/org/apache/log4j/spi/Configurator.html">Configurator</a> |
| interface. |
| |
| </ol> |
| |
| <h2>Example Configurations</h2> |
| |
| |
| |
| <h2>Default Initialization under Tomcat</h2> |
| |
| <p>The default log4j initialization is particularly useful in |
| web-server environments. Under Tomcat 3.x and 4.x, you should place |
| the <code>log4j.properties</code> under the |
| <code>WEB-INF/classes</code> directory of your web-applications. Log4j |
| will find the properties file and initialize itself. This is easy to |
| do and it works. |
| |
| <p>You can also choose to set the system property |
| <b>log4j.configuration</b> before starting Tomcat. For Tomcat 3.x The |
| <code>TOMCAT_OPTS</code> environment variable is used to set command |
| line options. For Tomcat 4.0, set the <code>CATALINA_OPTS</code> |
| environment variable instead of <code>TOMCAT_OPTS</code>. |
| |
| <p><b>Example 1</b> |
| |
| <p>The Unix shell command |
| <pre> |
| export TOMCAT_OPTS="-Dlog4j.configuration=foobar.txt" |
| </pre> |
| |
| tells log4j to use the file <code>foobar.txt</code> as the default |
| configuration file. This file should be place under the |
| <code>WEB-INF/classes</code> directory of your web-application. The |
| file will be read using the <a |
| href="api/org/apache/log4j/xml/PropertyConfigurator.html">PropertyConfigurator</a>. Each |
| web-application will use a different default configuration file because |
| each file is relative to a web-application. |
| |
| |
| <p><b>Example 2</b> |
| |
| <p>The Unix shell command |
| <pre> |
| export TOMCAT_OPTS="-Dlog4j.debug -Dlog4j.configuration=foobar.xml" |
| </pre> |
| |
| tells log4j to output log4j-internal debugging information and to use |
| the file <code>foobar.xml</code> as the default configuration |
| file. This file should be place under the <code>WEB-INF/classes</code> |
| directory of your web-application. Since the file ends with a |
| <code>.xml</code> extension, it will read using the <a |
| href="api/org/apache/log4j/xml/DOMConfigurator.html">DOMConfigurator</a>. Each |
| web-application will use a different default configuration file because |
| each file is relative to a web-application. |
| |
| <p><b>Example 3</b> |
| |
| <p>The Windows shell command |
| <pre> |
| set TOMCAT_OPTS=-Dlog4j.configuration=foobar.lcf -Dlog4j.configuratorClass=com.foo.BarConfigurator |
| </pre> |
| |
| tells log4j to use the file <code>foobar.lcf</code> as the default |
| configuration file. This file should be place under the |
| <code>WEB-INF/classes</code> directory of your web-application. Due to |
| the definition of the <b>log4j.configuratorClass</b> system property, |
| the file will be read using the <code>com.foo.BarConfigurator</code> |
| custom configurator. Each web-application will use a different |
| default configuration file because each file is relative to a |
| web-application. |
| |
| <p><b>Example 4</b> |
| |
| <p>The Windows shell command |
| <pre> |
| set TOMCAT_OPTS=-Dlog4j.configuration=file:/c:/foobar.lcf</pre> |
| |
| tells log4j to use the file <code>c:\foobar.lcf</code> as the default |
| configuration file. The configuration file is fully specified by the |
| URL <code>file:/c:/foobar.lcf</code>. Thus, the same configuration |
| file will be used for all web-applications. |
| |
| |
| <p>Different web-applications will load the log4j classes through |
| their respective classloaderss. Thus, each image of the log4j |
| environment will act independetly and without any mutual |
| synchronization. For example, <code>FileAppenders</code> defined |
| exactly the same way in multiple web-application configurations will |
| all attempt to write the same file. The results are likely to be less |
| than satisfactory. You must make sure that log4j configurations of |
| different web-applications do not use the same underlying system |
| resource. |
| |
| |
| <p><b>Initialization servlet</b> |
| |
| <p>It is also possible to use a special servlet for log4j |
| initialization. Here is an example, |
| |
| <p><table bgcolor="CCCCCC"><tr><td> |
| <pre> |
| package com.foo; |
| |
| import org.apache.log4j.PropertyConfigurator; |
| import javax.servlet.http.HttpServlet; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| import java.io.PrintWriter; |
| import java.io.IOException; |
| |
| public class Log4jInit extends HttpServlet { |
| |
| public |
| void <b>init()</b> { |
| String prefix = getServletContext().getRealPath("/"); |
| String file = getInitParameter("log4j-init-file"); |
| // if the log4j-init-file is not set, then no point in trying |
| if(file != null) { |
| PropertyConfigurator.configure(prefix+file); |
| } |
| } |
| |
| public |
| void doGet(HttpServletRequest req, HttpServletResponse res) { |
| } |
| } |
| </pre> |
| </table> |
| |
| <p>Define the following servlet in the web.xml file for your web-application. |
| |
| <p><table bgcolor="CCAAAA"><tr><td> |
| <pre> |
| <servlet> |
| <servlet-name>log4j-init</servlet-name> |
| <servlet-class>com.foo.Log4jInit</servlet-class> |
| |
| <init-param> |
| <param-name>log4j-init-file</param-name> |
| <param-value>WEB-INF/classes/log4j.lcf</param-value> |
| </init-param> |
| |
| <b><load-on-startup>1</load-on-startup></b> |
| </servlet> |
| </pre> |
| </table> |
| |
| <p>Writing an initialization servlet is the most flexible way for |
| initializing log4j. There are no constraints on the code you can place |
| in the <code>init()</code> method of the servlet. |
| |
| |
| |
| <h2> Nested Diagnostic Contexts</h2> |
| |
| <p>Most real-world systems have to deal with multiple clients |
| simultaneously. In a typical multithreaded implementation of such a |
| system, different threads will handle different clients. Logging is |
| especially well suited to trace and debug complex distributed |
| applications. A common approach to differentiate the logging output of |
| one client from another is to instantiate a new separate logger for |
| each client. This promotes the proliferation of loggers and |
| increases the management overhead of logging. |
| |
| <p>A lighter technique is to uniquely stamp each log request initiated |
| from the same client interaction. Neil Harrison described this method |
| in the book "Patterns for Logging Diagnostic Messages," in <em>Pattern |
| Languages of Program Design 3</em>, edited by R. Martin, D. Riehle, |
| and F. Buschmann (Addison-Wesley, 1997). |
| |
| |
| |
| <p> To uniquely stamp each request, the |
| user pushes contextual information into the NDC, the abbreviation of |
| <em>Nested Diagnostic Context</em>. The NDC class is shown below. |
| |
| <pre> |
| public class NDC { |
| // Used when printing the diagnostic |
| public <strong>static</strong> String get(); |
| |
| // Remove the top of the context from the NDC. |
| public <strong>static</strong> String pop(); |
| |
| // Add diagnostic context for the current thread. |
| public <strong>static</strong> void push(String message); |
| |
| // Remove the diagnostic context for this thread. |
| public <strong>static</strong> void remove(); |
| } |
| </pre> |
| |
| <p>The NDC is managed per thread as a <em>stack</em> of contextual |
| information. Note that all methods of the <code>org.apache.log4j.NDC</code> |
| class are static. Assuming that NDC printing is turned on, every time |
| a log request is made, the appropriate log4j component will include |
| the <em>entire</em> NDC stack for the current thread in the log |
| output. This is done without the intervention of the user, who is |
| responsible only for placing the correct information in the NDC by |
| using the <code>push</code> and <code>pop</code> methods at a few |
| well-defined points in the code. In contrast, the per-client logger |
| approach commands extensive changes in the code. |
| |
| <p>To illustrate this point, let us take the example of a servlet |
| delivering content to numerous clients. The servlet can build the NDC |
| at the very beginning of the request before executing other code. The |
| contextual information can be the client's host name and other |
| information inherent to the request, typically information contained |
| in cookies. Hence, even if the servlet is serving multiple clients |
| simultaneously, the logs initiated by the same code, i.e. belonging to |
| the same logger, can still be distinguished because each client |
| request will have a different NDC stack. Contrast this with the |
| complexity of passing a freshly instantiated logger to all code |
| exercised during the client's request. |
| |
| <p>Nevertheless, some sophisticated applications, such as virtual |
| hosting web servers, must log differently depending on the virtual |
| host context and also depending on the software component issuing the |
| request. Recent log4j releases support multiple hierarchy trees. This |
| enhancement allows each virtual host to possess its own copy of the |
| logger hierarchy. |
| |
| |
| <a name="performance"><h2>Performance</h2> |
| |
| <p>One of the often-cited arguments against logging is its |
| computational cost. This is a legitimate concern as even moderately |
| sized applications can generate thousands of log requests. Much |
| effort was spent measuring and tweaking logging performance. Log4j |
| claims to be fast and flexible: speed first, flexibility second. |
| |
| <p>The user should be aware of the following performance issues. |
| |
| <ol> |
| <b><li>Logging performance when logging is turned off.</b> |
| |
| <p>When logging is turned |
| off entirely or just for a <a |
| href="api/org/apache/log4j/Hierarchy.html#setThreshold(java.lang.String)">set |
| of levels</a>, the cost of a log request consists of a method |
| invocation plus an integer comparison. On a 233 MHz Pentium II |
| machine this cost is typically in the 5 to 50 nanosecond range. |
| |
| <p>However, The method invocation involves the "hidden" cost of |
| parameter construction. |
| |
| <p>For example, for some logger <code>cat</code>, writing, |
| <pre> |
| logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); |
| </pre> |
| |
| incurs the cost of constructing the message parameter, i.e. |
| converting both integer <code>i</code> and <code>entry[i]</code> |
| to a String, and concatenating intermediate strings, |
| regardless of whether the message will be logged or not. |
| |
| This cost of parameter construction can be quite high and it |
| depends on the size of the parameters involved. |
| |
| |
| <p>To avoid the parameter construction cost write: |
| <pre> |
| if(logger.isDebugEnabled() { |
| logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); |
| } |
| </pre> |
| |
| <p>This will not incur the cost of parameter |
| construction if debugging is disabled. On the other hand, if |
| the logger is debug-enabled, it will incur twice the cost of |
| evaluating whether the logger is enabled or not: once |
| in <code>debugEnabled</code> and once in |
| <code>debug</code>. This is an insignificant |
| overhead because evaluating a logger takes about 1% |
| of the time it takes to actually log. |
| |
| <p>In log4j, logging requests are made to instances of the Logger |
| class. Logger is a class and not an interface. This measurably |
| reduces the cost of method invocation at the cost of some |
| flexibility. |
| |
| |
| <p>Certain users resort to preprocessing or compile-time |
| techniques to compile out all log statements. This leads to perfect |
| performance efficiency with respect to logging. However, since the |
| resulting application binary does not contain any log statements, |
| logging cannot be turned on for that binary. In my opinion this is |
| a disproportionate price to pay in exchange for a small performance |
| gain. |
| |
| |
| <p><b><li>The performance of deciding whether to log or not to log when |
| logging is turned on.</b> |
| </p> |
| |
| <p>This is essentially the performance of walking the logger |
| hierarchy. When logging is turned on, log4j still needs to compare |
| the level of the log request with the level of the request |
| logger. However, loggers may not have an assigned |
| level; they can inherit them from the logger hierarchy. Thus, |
| before inheriting a level, the logger may need to search its |
| ancestors. |
| |
| <p>There has been a serious effort to make this hierarchy walk to |
| be as fast as possible. For example, child loggers link only to |
| their existing ancestors. In the <code>BasicConfigurator</code> |
| example shown earlier, the logger named <code>com.foo.Bar</code> is |
| linked directly to the root logger, thereby circumventing the |
| nonexistent <code>com</code> or <code>com.foo</code> loggers. This |
| significantly improves the speed of the walk, especially in "sparse" |
| hierarchies. |
| |
| <p>The typical cost of walking the hierarchy is typically 3 |
| times slower than when logging is turned off entirely. |
| |
| <p><b><li>Actually outputting log messages</b> |
| |
| <p>This is the cost of formatting the log output and sending it to |
| its target destination. Here again, a serious effort was made to |
| make layouts (formatters) perform as quickly as possible. The same |
| is true for appenders. The typical cost of actually logging is |
| about 100 to 300 microseconds. |
| |
| See <a |
| href="api/org/apache/log4j/performance/Logging.html">org.apache.log4.performance.Logging</a> |
| for actual figures. |
| |
| </ol> |
| |
| <p>Although log4j has many features, its first design goal was speed. |
| Some log4j components have been rewritten many times to improve |
| performance. Nevertheless, contributors frequently come up with new |
| optimizations. You should be pleased to know that when configured with |
| the <a |
| href="api/org/apache/log4j/SimpleLayout.html">SimpleLayout</a> |
| performance tests have shown log4j to log as quickly as |
| <code>System.out.println</code>. |
| |
| <h2>Conclusions</h2> |
| |
| <p>Log4j is a popular logging package written in Java. One of its |
| distinctive features is the notion of inheritance in loggers. Using |
| a logger hierarchy it is possible to control which log statements |
| are output at arbitrary granularity. This helps reduce the volume of |
| logged output and minimize the cost of logging. |
| |
| <p>One of the advantages of the log4j API is its manageability. Once |
| the log statements have been inserted into the code, they can be |
| controlled with configuration files. They can be selectively enabled |
| or disabled, and sent to different and multiple output targets in |
| user-chosen formats. The log4j package is designed so that log |
| statements can remain in shipped code without incurring a heavy |
| performance cost. |
| |
| <h2>Acknowledgments</h2> |
| |
| Many thanks to N. Asokan for reviewing the article. He is also one of |
| the originators of the logger concept. I am indebted to Nelson Minar |
| for encouraging me to write this article. He has also made many useful |
| suggestions and corrections to this article. Log4j is the result of a |
| collective effort. My special thanks go to all the authors who have |
| contributed to the project. Without exception, the best features in |
| the package have all originated in the user community. |
| |
| </body> </html> |