
Author: seb Date: Thu Jul 27 18:52:41 2006 New Revision: 361 Added: logback/classic/trunk/src/site/xdocTemplates/shortIntro.xml Modified: logback/classic/trunk/src/site/xdocTemplates/documentation.xml Log: first commit of a short introduction to logback classic Modified: logback/classic/trunk/src/site/xdocTemplates/documentation.xml ============================================================================== --- logback/classic/trunk/src/site/xdocTemplates/documentation.xml (original) +++ logback/classic/trunk/src/site/xdocTemplates/documentation.xml Thu Jul 27 18:52:41 2006 @@ -12,16 +12,20 @@ <h2>Documentation</h2> </div> + <p>Here are some documents about ${pom.name}.</p> <p> - Here are some documents about ${pom.name}. - </p> - <p> - This section is pretty light at the moment, but will grow with the developping - of ${pom.name}. + This section is pretty light at the moment, but will grow + with the developping of ${pom.name}. </p> <ul> <li> + <a href="shortIntro.html"> + A Short Introduction to logback classic + </a> + + </li> + <li> <a href="apidocs/index.html">${pom.name} Javadoc</a> </li> </ul> Added: logback/classic/trunk/src/site/xdocTemplates/shortIntro.xml ============================================================================== --- (empty file) +++ logback/classic/trunk/src/site/xdocTemplates/shortIntro.xml Thu Jul 27 18:52:41 2006 @@ -0,0 +1,924 @@ +<document> + <body> + <div class="section"> + <h2>Short introduction</h2> + </div> + <div class="author"> + Authors: Ceki Gülcü, Sébastien Pennec + </div> + <p> + Copyright © 2000-2006, The Apache Software Foundation. + Licensed under the Apache License, Version 2.0. The present + short manual also borrows some text from "The complete log4j + manual", which contains more detailed and up to date + information, by Ceki Gülcü. + </p> + + <div class="section"> + <h2>Introduction</h2> + </div> + <p> + Logging is a low-tech way of debugging your code. It might + also be the only way, when debuggers are not available or + applicable. Logback classic can help you insert logging + functionalities in your code without polluting its + readability with useless statements, or diminishing its + performance. + </p> + <p> + Logback is intended as a successor to the popular log4j + project. It was also designed by Ceki Gülcü, the + founder of the log4j project. It builds upon experience + gained in building industrial-strength logging systems going + back as far as 1999. + </p> + <p> + Logback's basic architecture is sufficiently generic so as + to apply under different circumstances. At present time, + logback is divided into three modules, Core, Classic and + Access. + </p> + <p> + The Core module lays the groundwork for the other two + modules. The Classic module can be assimilated to an + improved version of log4j. Logback Classic natively + implements the + <a href="http://www.slf4j.org">SLF4J API</a> + so that you can readily switch back and forth between + logback and other logging systems such as log4j or JDK14 + Logging. The Access module integrates with Servlet + containers to provide HTPP-access log functionality. Note + that you can easily build your own modules on top of the + Core module. + </p> + <p> + Before rushing to install and configure logback classic on + your own application, here is a presentation of how things + work. + </p> + + <div class="section"> + <h2>Logback architecture</h2> + + <p> + Logback's basic architecture is sufficiently generic so + as to apply under different circumstances. At present + time, logback is divided into three modules, Core, + Classic and Access. + </p> + <p> + The Core module lays the groundwork for the other two + modules. The Classic module extends the core module, it + can be assimilated to an improved version of log4j. + Logback Classic natively implements the SLF4J API so + that you can readily switch back and forth between + logback and other logging systems such as log4j or JDK14 + Logging. The Access module also extends the core + functionnalities and integrates with Servlet containers + to provide HTPP-access log functionality. + </p> + <p> + Note that you can easily build your own modules on top + of the Core module. + </p> + </div> + + <div class="section"> + <h2>Logger, Appenders and Layouts</h2> + </div> + <p> + Logback classic has three main components: Loggers, + Appenders and Layouts. 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> + <p> + The Loggers are defined in the classic module. On the other + hand, Appenders and Layouts are defined in the core module + of logback. + </p> + + <div class="section"> + <h3>Logger hierarchy</h3> + </div> + <p> + The first and foremost advantage of any logging API over + plain System.out.println 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. + Loggers are named entities. + </p> + <p> + Logger names are case-sensitive and they follow the + hierarchical naming rule: + </p> + <div class="definition"> + <div class="deftitle">Named Hierarchy</div> + <p> + A logger is said to be an ancestor of another logger if + its name followed by a dot is a prefix of the descendant + logger name. A logger is said to be a parent of a child + logger if there are no ancestors between itself and the + descendant logger. + </p> + </div> + + <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: + </p> + <ol> + <li>it always exists,</li> + <li>it cannot be retrieved by name.</li> + </ol> + All other loggers are retrieved with the class static + LoggerFactory.getLogger method. This method takes the name of + the desired logger as a parameter. Some of the basic methods in + the Logger interface are listed below. + <div class="source"> + <p>package org.slf4j;</p> + + <p>public interface Logger {</p> + <p> + // Creation and retrieval method: + <br /> + public static Logger getLogger(String name); + <br /> + </p> + <p> + // printing methods: + <br /> + public void debug(Object message); + <br /> + public void info(Object message); + <br /> + public void warn(Object message); + <br /> + public void error(Object message); + <br /> + public void fatal(Object message); + <br /> + </p> + <p>}</p> + </div> + <p> + Loggers may be assigned levels. The set of possible levels, + that is DEBUG, INFO, WARN, ERROR and FATAL are defined in + the org.apache.log4j.Level class. Although we do not + encourage you to do so, you may define your own levels by + sub-classing the Level 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> + + <div class="definition"> + <div class="deftitle">Level Inheritance</div> + <p> + The inherited level for a given logger C, is equal to + the first non-null level in the logger hierarchy, + starting at C and proceeding upwards in the hierarchy + towards the root logger. + </p> + </div> + <p> + To ensure that all loggers can eventually inherit a level, + the root logger always has an assigned level. + </p> + <p> + Below are four examples with various assigned level values + and the resulting inherited levels according to the above + rule. + </p> + + <table class="exampleTable"> + <tr> + <th> + Logger + <br /> + name + </th> + <th> + Assigned + <br /> + level + </th> + + <th> + Inherited + <br /> + level + </th> + </tr> + <tr> + <td>root</td> + <td>Proot</td> + <td>Proot</td> + </tr> + <tr> + <td>X</td> + <td>none</td> + <td>Proot</td> + </tr> + + <tr> + <td>X.Y</td> + <td>none</td> + <td>Proot</td> + </tr> + <tr> + <td>X.Y.Z</td> + <td>none</td> + <td>Proot</td> + </tr> + </table> + <p> + In example 1 above, only the root logger is assigned a + level. + </p> + 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> + <table class="exampleTable"> + <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> + </table> + + <p> + In example 2, all loggers have an assigned level value. + There is no need for level inheritence. + </p> + + <table class="exampleTable"> + <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> + </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> + . + </p> + <table class="exampleTable"> + + <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> + </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> + In a more graphic way, here is how you the logger hierarchy + works: + </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> + <div class="definition"> + <div class="deftitle">Basic Selection Rule</div> + + <p> + A log request of level + <em>p</em> + in a logger with (either assigned or inherited, + whichever is appropriate) level + <em>q</em> + , is enabled if + <em>p >= q</em> + . + </p> + + </div> + + <p> + This rule is at the heart of logback classic. It assumes + that levels are ordered. For the standard levels, we have + <code>DEBUG < INFO < WARN < ERROR</code> + . + </p> + <p>Here is an example of this rule.</p> + + <div class="source"> + <p> + // get a logger instance named "com.foo", with an + <span class="blue">INFO</span> + level. + <br /> + Logger logger = LoggerFactory.getLogger("com.foo"); + <br /> + </p> + <p> + Logger barlogger = + LoggerFactory.getLogger("com.foo.Bar"); + <br /> + </p> + <p> + // This request is enabled, because + <span class="green">WARN</span> + >= + <span class="blue">INFO</span> + . + <br /> + logger. + <span class="green">warn</span> + ("Low fuel level."); + <br /> + </p> + <p> + // This request is disabled, because + <span class="green">DEBUG</span> + < + <span class="blue">INFO</span> + . + <br /> + logger. + <span class="green">debug</span> + ("Starting search for nearest gas station."); + <br /> + </p> + <p> + // The logger instance barlogger, named "com.foo.Bar", + <br /> + // will inherit its level from the logger named + <br /> + // "com.foo" Thus, the following request is enabled + <br /> + // because + <span class="green">INFO</span> + >= + <span class="blue">INFO</span> + . + <br /> + barlogger. + <span class="green">info</span> + ("Located nearest gas station."); + <br /> + </p> + <p> + // This request is disabled, because + <span class="green">DEBUG</span> + < + <span class="blue">INFO</span> + . + <br /> + barlogger. + <span class="green">debug</span> + ("Exiting gas station search"); + <br /> + </p> + </div> + + <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</p> + <div class="source"> + Logger x = LoggerFactory.getLogger("wombat"); + <br /> + Logger y = LoggerFactory.getLogger("wombat"); + </div> + <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, logback classic 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 logback environment is typically done + at application initialization. The preferred way is by + reading a configuration file. This approach will be + discussed shortly. + </p> + <p> + Logback 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. Logback 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> + + <div class="section"> + <h3>Appenders and Layouts</h3> + </div> + <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 appender. Currently, appenders exist for the + console, files, GUI components, remote socket servers, JMS, + NT Event Loggers, and remote UNIX Syslog daemons. It is also + possible to log asynchronously. + </p> + <p>More than one appender can be attached to a logger.</p> + <p> + The addAppender method adds an appender to a given logger. + 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. 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 C, then enabled logging requests for C and C's + children will print on a file and on the console. It is + possible to override this default behavior so that appender + accumulation is no longer additive by setting the additivity + flag to false. + </p> + <p> + The rules governing appender additivity are summarized + below. + </p> + <div class="definition"> + <div class="deftitle">Appender Additivity</div> + <p> + The output of a log statement of logger + <em>C</em> + will go to all the appenders in + <em>C</em> + and its ancestors. This is the meaning of the term + "appender additivity". + </p> + <p> + However, if an ancestor of logger + <em>C</em> + , say + <em>P</em> + , has the additivity flag set to false, then + <em>C</em> + 's output will be directed to all the appenders in + <em>C</em> + and it's ancestors upto and including + <em>P</em> + but not the appenders in any of the ancestors of + <em>P</em> + . + </p> + <p> + Loggers have their additivity flag set to true by + default. + </p> + </div> + The table below shows an example: + + <table class="bodyTable"> + <tr> + <th>Logger Name</th> + <th>Added Appenders</th> + <th>Additivity Flag</th> + <th>Output Targets</th> + <th>Comment</th> + </tr> + <tr> + <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> + <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> + <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> + <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> + <td>security</td> + <td>A-sec</td> + <td class="blue">false</td> + <td>A-sec</td> + <td> + No appender accumulation since the additivity flag + is set to + <code>false</code> + . + </td> + </tr> + <tr> + <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. The PatternLayout, 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: + </p> + + <div class="source"> + 176 [main] INFO org.foo.Bar - Located nearest gas station. + </div> + + <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 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> + <p> + Object renderers have to implement the ObjectRenderer + interface. + </p> + + <h4>More sophitsicated ways of logging</h4> + + <p> + If you are a SLF4J user (if not, you should be...), you'll + notice that the methods used to request logging do not only + take a String as a parameter. Some methods allow more + sophisticated parameter configurations. + </p> + + <p> + For some Logger + <code>logger</code> + , writing, + </p> + <div class="source"> + logger.debug("Entry number: " + i + " is " + + String.valueOf(entry[i])); + </div> + + <p> + incurs the cost of constructing the message parameter, that + is converting both integer + <code>i</code> + and + <code>entry[i]</code> + to a String, and concatenating intermediate strings. This, + regardless of whether the message will be logged or not. + </p> + + <p> + One possible way to avoid the cost of parameter construction + is by surrounding the log statement with a test. Here is an + example. + </p> + + <div class="source"> + if(logger.isDebugEnabled()) { + <br /> + logger.debug("Entry number: " + i + " is " + + String.valueOf(entry[i])); + <br /> + } + </div> + + + <p> + This way you will not incur the cost of parameter + construction if debugging is disabled for + <code>logger</code> + . On the other hand, if the logger is enabled for the DEBUG + level, you will incur the cost of evaluating whether the + logger is enabled or not, twice: once in + <code>debugEnabled</code> + and once in + <code>debug</code> + . This is an insignificant overhead because evaluating a + logger takes less than 1% of the time it takes to actually + log a statement. + </p> + + <h4>Better alternative based on format messages</h4> + + <p> + There exists a very convenient alternative based on message + formats. Assuming + <code>entry</code> + is an object, you can write: + </p> + + + <div class="source"> + Object entry = new SomeObject(); + <br /> + logger.debug("The entry is {}.", entry); + </div> + + <p> + After evaluting whether to log or not, and only if the + decision is affirmative, will the logger implementation + format the message and replace the '{}' pair with the string + value of + <code>entry</code> + . In other words, tis form does not incur the cost of + parameter construction in case the log statement is + disabled. + </p> + + + <p> + The following two lines will yield the exact same output. + However, the second form will outperform the first form by a + factor of at least 30, in case of a + <em>disabled</em> + logging statement. + </p> + + <div class="source"> + logger.debug("The new entry is "+entry+"."); + <br /> + logger.debug("The new entry is {}.", entry); + </div> + + + <p> + A two argument variant is also availalble. For example, you + can write: + </p> + + <div class="source"> + logger.debug("The new entry is {}. It replaces {}.", entry, + oldEntry); + </div> + + <p> + If three or more arguments need to be passed, an + <code>Object[]</code> + variant is also availalble. For example, you can write: + </p> + + + <div class="source"> + logger.debug("Value {} was inserted between {} and {}.", new + Object[] {newVal, below, above}); + </div> + + + + + + + </body> +</document>