mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
1275 lines
53 KiB
HTML
1275 lines
53 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
<title>Apache log4j 1.2 - Short introduction to log4j</title>
|
|
<style type="text/css" media="all">
|
|
@import url("./css/maven-base.css");
|
|
@import url("./css/maven-theme.css");
|
|
@import url("./css/site.css");
|
|
</style>
|
|
<link rel="stylesheet" href="./css/print.css" type="text/css" media="print" />
|
|
<meta name="author" content="Ceki Gülcü" />
|
|
</head>
|
|
<body class="composite">
|
|
<div id="banner">
|
|
<a href="../../" id="bannerLeft">
|
|
|
|
<img src="images/ls-logo.jpg" alt="" />
|
|
|
|
</a>
|
|
<a href=".." id="bannerRight">
|
|
|
|
<img src="images/logo.jpg" alt="" />
|
|
|
|
</a>
|
|
<div class="clear">
|
|
<hr/>
|
|
</div>
|
|
</div>
|
|
<div id="breadcrumbs">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="xleft">
|
|
Last Published: 2010-03-30
|
|
|
|
|
<a href="http://www.apache.org/" class="externalLink">Apache</a>
|
|
>
|
|
|
|
<a href="../../">Logging Services</a>
|
|
>
|
|
|
|
<a href="../">log4j</a>
|
|
>
|
|
|
|
<a href="http://logging.apache.org:80/log4j/1.2/" class="externalLink">1.2</a>
|
|
</div>
|
|
<div class="xright">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
<div class="clear">
|
|
<hr/>
|
|
</div>
|
|
</div>
|
|
<div id="leftColumn">
|
|
<div id="navcolumn">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h5>Get log4j 1.2</h5>
|
|
<ul>
|
|
|
|
<li class="none">
|
|
<a href="download.html">Download</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="changes-report.html">Changes</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="license.html">License</a>
|
|
</li>
|
|
</ul>
|
|
<h5>About log4j 1.2</h5>
|
|
<ul>
|
|
|
|
<li class="none">
|
|
<a href="index.html">What is log4j?</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="faq.html">FAQ</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="roadmap.html">Roadmap</a>
|
|
</li>
|
|
</ul>
|
|
<h5>Community</h5>
|
|
<ul>
|
|
|
|
<li class="none">
|
|
<a href="mail-lists.html">Mailing Lists</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="issue-tracking.html">Issue Tracking</a>
|
|
</li>
|
|
</ul>
|
|
<h5>Development</h5>
|
|
<ul>
|
|
|
|
<li class="none">
|
|
<a href="source-repository.html">Repository</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="jxr.html">Cross Reference</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="dependencies.html">Dependencies</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="integration.html">Continuous Integration</a>
|
|
</li>
|
|
</ul>
|
|
<h5>Documentation</h5>
|
|
<ul>
|
|
|
|
<li class="none">
|
|
<strong>Introduction</strong>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="apidocs/index.html">JavaDoc</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="publications.html">Publications</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="http://wiki.apache.org/logging-log4j" class="externalLink">Wiki</a>
|
|
</li>
|
|
</ul>
|
|
<h5>Apache</h5>
|
|
<ul>
|
|
|
|
<li class="none">
|
|
<a href="http://www.apache.org" class="externalLink">Home</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="http://www.apache.org/foundation/sponsorship.html" class="externalLink">Sponsorship</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="http://www.apache.org/foundation/thanks.html" class="externalLink">Thanks</a>
|
|
</li>
|
|
|
|
<li class="none">
|
|
<a href="http://www.apachecon.com" class="externalLink">Conferences</a>
|
|
</li>
|
|
</ul>
|
|
<a href="http://maven.apache.org/" title="Built by Maven" class="poweredBy">
|
|
<img alt="Built by Maven" src="./images/logos/maven-feather.png"></img>
|
|
</a>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
</div>
|
|
<div id="bodyColumn">
|
|
<div id="contentBox">
|
|
<div class="section"><h2><a name="Short_introduction_to_log4j:_Ceki_Gülcü_March_2002"></a>Short introduction to log4j: Ceki Gülcü, March 2002</h2>
|
|
<p>
|
|
Copyright © 2000-2002 The Apache Software Foundation. All
|
|
rights reserved. This software is published under the terms of
|
|
the Apache Software License version 2.0, a copy of which has
|
|
been included in the LICENSE file shipped with the log4j
|
|
distribution. This document is based on the article <a class="externalLink" 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 class="externalLink" href="https://www.qos.ch/shop/products/eclm/">"<em>The
|
|
complete log4j manual</em>"</a> by the same author (yours
|
|
truly).</p>
|
|
<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.</p>
|
|
<h2>Introduction</h2><p>Almost every large application includes its own logging or tracing
|
|
API. In conformance with this rule, the E.U. <a class="externalLink" 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">Apache Software License</a>, a
|
|
fully-fledged open source license certified by the <a class="externalLink" 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 class="externalLink" 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>
|
|
<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>
|
|
<p>Experience indicates that logging was an important component of the
|
|
development cycle. It offers 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>
|
|
<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>
|
|
<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.</p>
|
|
<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.</p>
|
|
<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>
|
|
<p>Loggers are named entities. Logger names are case-sensitive and
|
|
they follow the hierarchical naming rule:</p>
|
|
<p><table class="bodyTable"><tr class="a"><td><dl><dt><b>Named Hierarchy</b></dt>
|
|
<dd>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.</dd>
|
|
</dl>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<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>
|
|
<p>The root logger resides at the top of the logger hierarchy. It
|
|
is exceptional in two ways:
|
|
|
|
<ol type="1"><li> it always exists,</li>
|
|
<li> it cannot be retrieved by name.</li>
|
|
</ol>
|
|
</p>
|
|
<p>Invoking the class static <a href="apidocs/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="apidocs/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>
|
|
<p><table class="bodyTable"><tr class="b"><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 trace(Object message);
|
|
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>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p>Loggers <em>may</em> be assigned levels. The set of possible
|
|
levels, that is:<br />
|
|
<br />
|
|
<a href="apidocs/org/apache/log4j/Level.html#TRACE">TRACE</a>,<br />
|
|
<a href="apidocs/org/apache/log4j/Level.html#DEBUG">DEBUG</a>,<br />
|
|
<a href="apidocs/org/apache/log4j/Level.html#INFO">INFO</a>,<br />
|
|
<a href="apidocs/org/apache/log4j/Level.html#WARN">WARN</a>,<br />
|
|
<a href="apidocs/org/apache/log4j/Level.html#ERROR">ERROR</a> and<br />
|
|
<a href="apidocs/org/apache/log4j/Level.html#FATAL">FATAL</a><br />
|
|
<br />
|
|
|
|
|
|
are defined in the <code><a href="apidocs/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>
|
|
<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>
|
|
<p><table class="bodyTable"><tr class="a"><td><dl><dt><b>Level Inheritance</b></dt>
|
|
<dd>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.</dd>
|
|
</dl>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p>To ensure that all loggers can eventually inherit a level,
|
|
the root logger always has an assigned level.</p>
|
|
<p>Below are four tables with various assigned level values and the
|
|
resulting inherited levels according to the above rule.</p>
|
|
<p><table class="bodyTable"><tr class="b"><th>Logger<br />
|
|
name</th>
|
|
<th>Assigned<br />
|
|
level</th>
|
|
<th>Inherited<br />
|
|
level</th>
|
|
</tr>
|
|
<tr class="a"><td>root</td>
|
|
<td>Proot</td>
|
|
<td>Proot</td>
|
|
</tr>
|
|
<tr class="b"><td>X </td>
|
|
<td>none</td>
|
|
<td>Proot</td>
|
|
</tr>
|
|
<tr class="a"><td>X.Y </td>
|
|
<td>none</td>
|
|
<td>Proot</td>
|
|
</tr>
|
|
<tr class="b"><td>X.Y.Z</td>
|
|
<td>none</td>
|
|
<td>Proot</td>
|
|
</tr>
|
|
<caption align="bottom">Example 1</caption></table>
|
|
</p>
|
|
<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>
|
|
<p><table class="bodyTable"><tr class="a"><th>Logger<br />
|
|
name</th>
|
|
<th>Assigned<br />
|
|
level</th>
|
|
<th>Inherited<br />
|
|
level</th>
|
|
</tr>
|
|
<tr class="b"><td>root</td>
|
|
<td>Proot</td>
|
|
<td>Proot</td>
|
|
</tr>
|
|
<tr class="a"><td>X </td>
|
|
<td>Px</td>
|
|
<td>Px</td>
|
|
</tr>
|
|
<tr class="b"><td>X.Y </td>
|
|
<td>Pxy</td>
|
|
<td>Pxy</td>
|
|
</tr>
|
|
<tr class="a"><td>X.Y.Z</td>
|
|
<td>Pxyz</td>
|
|
<td>Pxyz</td>
|
|
</tr>
|
|
<caption align="bottom">Example 2</caption></table>
|
|
</p>
|
|
<p>In example 2, all loggers have an assigned level value. There
|
|
is no need for level inheritence.</p>
|
|
<p><table class="bodyTable"><tr class="b"><th>Logger<br />
|
|
name</th>
|
|
<th>Assigned<br />
|
|
level</th>
|
|
<th>Inherited<br />
|
|
level</th>
|
|
</tr>
|
|
<tr class="a"><td>root</td>
|
|
<td>Proot</td>
|
|
<td>Proot</td>
|
|
</tr>
|
|
<tr class="b"><td>X </td>
|
|
<td>Px</td>
|
|
<td>Px</td>
|
|
</tr>
|
|
<tr class="a"><td>X.Y </td>
|
|
<td>none</td>
|
|
<td>Px</td>
|
|
</tr>
|
|
<tr class="b"><td>X.Y.Z</td>
|
|
<td>Pxyz</td>
|
|
<td>Pxyz</td>
|
|
</tr>
|
|
<caption align="bottom">Example 3</caption></table>
|
|
</p>
|
|
<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>.</p>
|
|
<table class="bodyTable"><tr class="a"><th>Logger<br />
|
|
name</th>
|
|
<th>Assigned<br />
|
|
level</th>
|
|
<th>Inherited<br />
|
|
level</th>
|
|
</tr>
|
|
<tr class="b"><td>root</td>
|
|
<td>Proot</td>
|
|
<td>Proot</td>
|
|
</tr>
|
|
<tr class="a"><td>X </td>
|
|
<td>Px</td>
|
|
<td>Px</td>
|
|
</tr>
|
|
<tr class="b"><td>X.Y </td>
|
|
<td>none</td>
|
|
<td>Px</td>
|
|
</tr>
|
|
<tr class="a"><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>
|
|
<p>Logging requests are made by invoking one of the printing methods
|
|
of a logger instance. These printing methods are
|
|
|
|
<code><a href="apidocs/org/apache/log4j/Logger.html#debug(java.lang.Object)">debug</a>,
|
|
|
|
<a href="apidocs/org/apache/log4j/Logger.html#info(java.lang.Object)">info</a>,
|
|
|
|
<a href="apidocs/org/apache/log4j/Logger.html#warn(java.lang.Object)">warn</a>,
|
|
<a href="apidocs/org/apache/log4j//Logger.html#error(java.lang.Object)">error</a>,
|
|
<a href="apidocs/org/apache/log4j/Logger.html#fatal(java.lang.Object)">fatal</a>
|
|
and <a href="apidocs/org/apache/log4j/Logger.html#log(org.apache.log4j.Level, java.lang.Object)">log</a></code>.</p>
|
|
<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>
|
|
<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>
|
|
<p><a name="selectionRule"></a><table class="bodyTable"><tr class="b"><td><dl><dt><b>Basic Selection Rule</b></dt>
|
|
<dd>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>.</dd>
|
|
</dl>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<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>
|
|
<p>Here is an example of this rule.</p>
|
|
<p><table class="bodyTable"><tr class="a"><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></td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p>Calling the <code>getLogger</code> method with the same name will
|
|
always return a reference to the exact same logger object.</p>
|
|
<p>For example, in
|
|
|
|
<table class="bodyTable"><tr class="b"><td><pre>
|
|
Logger x = Logger.getLogger("wombat");
|
|
Logger y = Logger.getLogger("wombat");</pre></td>
|
|
</tr>
|
|
</table>
|
|
<code>x</code> and <code>y</code> refer to <em>exactly</em> the same
|
|
logger object.</p>
|
|
<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>
|
|
<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>
|
|
<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>
|
|
<p>Nevertheless, naming loggers after the class where they are
|
|
located seems to be the best strategy known so far.</p>
|
|
<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="apidocs/org/apache/log4j/ConsoleAppender.html">console</a>, <a href="apidocs/org/apache/log4j/FileAppender.html">files</a>, GUI
|
|
components, <a href="apidocs/org/apache/log4j/net/SocketAppender.html">remote socket</a>
|
|
servers, <a href="apidocs/org/apache/log4j/net/JMSAppender.html">JMS</a>,
|
|
|
|
<a href="apidocs/org/apache/log4j/nt/NTEventLogAppender.html"> NT
|
|
Event Loggers</a>, and remote UNIX <a href="apidocs/org/apache/log4j/net/SyslogAppender.html">Syslog</a>
|
|
daemons. It is also possible to log <a href="apidocs/org/apache/log4j/AsyncAppender.html">asynchronously</a>.</p>
|
|
<p>More than one appender can be attached to a logger.</p>
|
|
<p>The <a href="apidocs/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="apidocs/org/apache/log4j/Logger.html#setAdditivity(boolean)">setting
|
|
the additivity flag</a> to <code>false</code>.</p>
|
|
<p>The rules governing appender additivity are summarized below.</p>
|
|
<p><a name="additivity"></a><table class="bodyTable"><tr class="a"><td><dl><dt><b>Appender Additivity</b></dt>
|
|
<dd>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 its ancestors upto and including <i>P</i> but
|
|
not the appenders in any of the ancestors of <i>P</i>.</p>
|
|
<p>Loggers have their additivity flag set to
|
|
<code>true</code> by default.</p>
|
|
</dd>
|
|
</dl>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p>The table below shows an example:</p>
|
|
<p><table class="bodyTable"><tr class="b"><th>Logger<br />
|
|
Name </th>
|
|
<th>Added<br />
|
|
Appenders</th>
|
|
<th>Additivity<br />
|
|
Flag</th>
|
|
<th>Output Targets</th>
|
|
<th>Comment</th>
|
|
</tr>
|
|
<tr class="a"><td>root </td>
|
|
<td>A1 </td>
|
|
<td>not applicable </td>
|
|
<td>A1</td>
|
|
<td>The root logger is anonymous but can be accessed with the
|
|
Logger.getRootLogger() method. There is no default appender
|
|
attached to root.</td>
|
|
</tr>
|
|
<tr class="b"><td>x </td>
|
|
<td>A-x1, A-x2 </td>
|
|
<td>true </td>
|
|
<td>A1, A-x1, A-x2</td>
|
|
<td>Appenders of "x" and root.</td>
|
|
</tr>
|
|
<tr class="a"><td>x.y </td>
|
|
<td>none </td>
|
|
<td>true </td>
|
|
<td>A1, A-x1, A-x2</td>
|
|
<td>Appenders of "x" and root.</td>
|
|
</tr>
|
|
<tr class="b"><td>x.y.z </td>
|
|
<td>A-xyz1 </td>
|
|
<td>true </td>
|
|
<td>A1, A-x1, A-x2, A-xyz1</td>
|
|
<td>Appenders in "x.y.z", "x" and root.</td>
|
|
</tr>
|
|
<tr class="a"><td>security </td>
|
|
<td>A-sec </td>
|
|
<td><font color="blue">false</font></td>
|
|
<td>A-sec</td>
|
|
<td>No appender accumulation since the additivity flag is set to
|
|
<code>false</code>.</td>
|
|
</tr>
|
|
<tr class="b"><td>security.access </td>
|
|
<td>none </td>
|
|
<td> true </td>
|
|
<td> A-sec </td>
|
|
<td>Only
|
|
appenders of "security" because the additivity flag in "security" is
|
|
set to <code>false</code>.</td>
|
|
</tr>
|
|
</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.</p>
|
|
|
|
|
|
The <a href="apidocs/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>
|
|
<p>For example, the PatternLayout with the conversion pattern "%r [%t]
|
|
%-5p %c - %m%n" will output something akin to:<br />
|
|
<pre>
|
|
176 [main] INFO org.foo.Bar - Located nearest gas station.
|
|
</pre></p>
|
|
<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>
|
|
<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>
|
|
<p>Object rendering follows the class hierarchy. For example, assuming
|
|
oranges are fruits, if you register a <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>
|
|
<p>Object renderers have to implement the
|
|
<a href="apidocs/org/apache/log4j/or/ObjectRenderer.html">ObjectRenderer</a>
|
|
interface.</p>
|
|
<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>
|
|
<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>
|
|
<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>
|
|
<p><table class="bodyTable"><tr class="a"><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></td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<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>
|
|
<p><code>MyApp</code> uses the <code>Bar</code> class defined in the
|
|
package <code>com.foo</code>.</p>
|
|
<p><table class="bodyTable"><tr class="b"><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></td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p>The invocation of the <a href="apidocs/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="apidocs/org/apache/log4j/ConsoleAppender.html">
|
|
ConsoleAppender</a>. The output will be formatted using a <a href="apidocs/org/apache/log4j/PatternLayout.html">PatternLayout</a> set
|
|
to the pattern "%-4r [%t] %-5p %c %x - %m%n".</p>
|
|
<p>Note that by default, the root logger is assigned to
|
|
<code>Level.DEBUG</code>.</p>
|
|
<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>
|
|
<p>The figure below depicts the object diagram of <code>MyApp</code>
|
|
after just having called the <code>BasicConfigurator.configure</code>
|
|
method.</p>
|
|
<p><center><img src="images/od.gif" /></center></p>
|
|
<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>
|
|
<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>
|
|
<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>
|
|
<p><table class="bodyTable"><tr class="a"><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></td>
|
|
</tr>
|
|
</table>
|
|
<p>This version of <code>MyApp</code> instructs
|
|
<code>PropertyConfigurator</code> to parse a configuration file and
|
|
set up logging accordingly.</p>
|
|
<p>Here is a sample configuration file that results in identical
|
|
output as the previous <code>BasicConfigurator</code> based example.</p>
|
|
<p><table class="bodyTable"><tr class="b"><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></td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<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>
|
|
<p><table class="bodyTable"><tr class="a"><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></td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p>The output of <code>MyApp</code> configured with this file is shown below.</p>
|
|
<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>
|
|
<p>Here is another configuration file that uses multiple appenders.</p>
|
|
<p><table class="bodyTable"><tr class="b"><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></td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p>Calling the enhanced MyApp with the this configuration file will
|
|
output the following on the console.</p>
|
|
<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>
|
|
<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>
|
|
<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.</p>
|
|
<a name="defaultInit"></a><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>
|
|
<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>
|
|
<p>The exact default initialization algorithm is defined as follows:</p>
|
|
<ol type="1"><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).</li>
|
|
<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".</li>
|
|
<li>Attempt to convert the <code>resource</code> variable to a
|
|
URL.</li>
|
|
<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.
|
|
|
|
See <a href="apidocs/org/apache/log4j/helpers/Loader.html#getResource(java.lang.String)">Loader.getResource(java.lang.String)</a>
|
|
for the list of searched locations.</li>
|
|
<li>If no URL could not be found, abort default
|
|
initialization. Otherwise, configure log4j from the URL.
|
|
|
|
The <a href="apidocs/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="apidocs/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="apidocs/org/apache/log4j/spi/Configurator.html">Configurator</a>
|
|
interface.</li>
|
|
</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>
|
|
<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>
|
|
<p><b>Example 1</b></p>
|
|
<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="apidocs/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>
|
|
<p><b>Example 2</b></p>
|
|
<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="apidocs/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>
|
|
<p><b>Example 3</b></p>
|
|
<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>
|
|
<p><b>Example 4</b></p>
|
|
<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>
|
|
<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>
|
|
<p><b>Initialization servlet</b></p>
|
|
<p>It is also possible to use a special servlet for log4j
|
|
initialization. Here is an example,</p>
|
|
<p><table class="bodyTable"><tr class="a"><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></td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<p>Define the following servlet in the web.xml file for your web-application.</p>
|
|
<p><table class="bodyTable"><tr class="b"><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></td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
<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.</p>
|
|
<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>
|
|
<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>
|
|
<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>
|
|
<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>
|
|
<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>
|
|
<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.</p>
|
|
<a name="performance"></a><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>
|
|
<p>The user should be aware of the following performance issues.</p>
|
|
<ol type="1"><li><b>Logging performance when logging is turned off.</b><br />
|
|
When logging is turned
|
|
off entirely or just for a <a href="apidocs/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>
|
|
<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>
|
|
<p>To avoid the parameter construction cost write:
|
|
<pre>
|
|
if(logger.isDebugEnabled() {
|
|
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
|
|
}
|
|
</pre></p>
|
|
<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>
|
|
<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>
|
|
<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>
|
|
</li>
|
|
<li><b>The performance of deciding whether to log or not to log when
|
|
logging is turned on.</b><br />
|
|
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>
|
|
<p>The typical cost of walking the hierarchy is typically 3
|
|
times slower than when logging is turned off entirely.</p>
|
|
</li>
|
|
<li><b>Actually outputting log messages</b><br />
|
|
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="apidocs/org/apache/log4j/performance/Logging.html">org.apache.log4.performance.Logging</a>
|
|
for actual figures.
|
|
</li>
|
|
</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="apidocs/org/apache/log4j/SimpleLayout.html">SimpleLayout</a>
|
|
performance tests have shown log4j to log as quickly as
|
|
<code>System.out.println</code>.</p>
|
|
<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>
|
|
<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.</p>
|
|
<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.
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div class="clear">
|
|
<hr/>
|
|
</div>
|
|
<div id="footer">
|
|
<div class="xright">©
|
|
1999-2010
|
|
|
|
Apache Software Foundation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
<div class="clear">
|
|
<hr/>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|