
Author: seb Date: Wed Aug 9 19:30:13 2006 New Revision: 438 Added: logback/trunk/logback-site/src/site/xdocTemplates/documentation.xml logback/trunk/logback-site/src/site/xdocTemplates/license.xml logback/trunk/logback-site/src/site/xdocTemplates/shortIntro.xml Modified: logback/trunk/logback-site/pom.xml logback/trunk/logback-site/src/site/site.xml logback/trunk/logback-site/src/site/xdocTemplates/download.xml logback/trunk/logback-site/src/site/xdocTemplates/repos.xml Log: modified files so that the project can be used in a multi-module environment Modified: logback/trunk/logback-site/pom.xml ============================================================================== --- logback/trunk/logback-site/pom.xml (original) +++ logback/trunk/logback-site/pom.xml Wed Aug 9 19:30:13 2006 @@ -2,14 +2,19 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <groupId>ch.qos.logback</groupId> + <artifactId>logback</artifactId> + <version>0.2-SNAPSHOT</version> + </parent> <modelVersion>4.0.0</modelVersion> <groupId>ch.qos.logback</groupId> - <artifactId>lb-topLevel</artifactId> + <artifactId>site</artifactId> <packaging>jar</packaging> - <version>0.1</version> - <name>Logback Home</name> + <version>${parent.version}</version> + <name>Logback Site</name> <url>http://logback.qos.ch</url> @@ -18,8 +23,7 @@ <url>http://www.qos.ch</url> </organization> <inceptionYear>2005</inceptionYear> - - + <build> <resources> <resource> @@ -33,13 +37,6 @@ </resource> </resources> - <extensions> - <extension> - <groupId>org.apache.maven.wagon</groupId> - <artifactId>wagon-ssh</artifactId> - <version>1.0-beta-1</version> - </extension> - </extensions> </build> <reporting> @@ -51,9 +48,10 @@ <xdocDirectory> ${project.build.outputDirectory}/generated-site </xdocDirectory> + <outputDirectory>${project.parent.basedir}/target/site</outputDirectory> </configuration> </plugin> - <!-- plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId> maven-project-info-reports-plugin @@ -61,19 +59,11 @@ <reportSets> <reportSet> <reports> - <report>index</report> </reports> </reportSet> </reportSets> - </plugin --> + </plugin> </plugins> </reporting> - - <distributionManagement> - <site> - <id>pixie</id> - <url>scp://pixie/var/www/logback.qos.ch/htdocs/</url> - </site> - </distributionManagement> </project> \ No newline at end of file Modified: logback/trunk/logback-site/src/site/site.xml ============================================================================== --- logback/trunk/logback-site/src/site/site.xml (original) +++ logback/trunk/logback-site/src/site/site.xml Wed Aug 9 19:30:13 2006 @@ -15,19 +15,23 @@ </bannerLeft> <body> + <!-- <links> <item name="Core Module" href="http://logback.qos.ch/core/" /> <item name="Classic Module" href="http://logback.qos.ch/classic/"/> <item name="Access Module" href="http://logback.qos.ch/access/"/> </links> + --> <menu name="${project.name}"> <item name="Introduction" href="index.html"/> <item name="News" href="news.html" /> <item name="Download" href="download.html" /> + <item name="Documentation" href="documentation.html" /> <item name="Mailing Lists" href="mailinglist.html" /> - <item name="Source Repositories" href="repos.html" /> + <item name="Source Repository" href="repos.html" /> <item name="Bug Report" href="bugreport.html"/> + <item name="License" href="license.html" /> </menu> </body> </project> \ No newline at end of file Added: logback/trunk/logback-site/src/site/xdocTemplates/documentation.xml ============================================================================== --- (empty file) +++ logback/trunk/logback-site/src/site/xdocTemplates/documentation.xml Wed Aug 9 19:30:13 2006 @@ -0,0 +1,31 @@ +<?xml version="1.0"?> +<document> + + <properties> + <author email="ceki at qos ddoott ch ">Ceki Gulcu</author> + <title>Logback project Docs</title> + </properties> + + <body> + + <div class="section"> + <h2>Documentation</h2> + </div> + + <p>Here are some documents about the logback project modules.</p> + <p> + This section is pretty light at the moment, but will grow + with the developping of $logback. + </p> + + <ul> + <li> + <a href="apidocs/index.html">Logback Javadoc</a> + </li> + <li> + <a href="shortIntro.html">A short introduction to logback classic</a> + </li> + </ul> + + </body> +</document> \ No newline at end of file Modified: logback/trunk/logback-site/src/site/xdocTemplates/download.xml ============================================================================== --- logback/trunk/logback-site/src/site/xdocTemplates/download.xml (original) +++ logback/trunk/logback-site/src/site/xdocTemplates/download.xml Wed Aug 9 19:30:13 2006 @@ -3,30 +3,60 @@ <properties> <author email="ceki at qos ddoott ch ">Ceki Gulcu</author> - <title>${pom.name} download</title> + <title>Logback project download</title> </properties> <body> - <h2>Download links</h2> - <p> - Logback Modules can be downloaded by visiting their specific - download pages: - </p> + <div class="section"> + <h2>Download links</h2> + </div> <p> - <a href="core/download.html">Core Module download page</a> - </p> - <p> - <a href="classic/download.html"> - Classic Module download page - </a> - </p> - <p> - <a href="access/download.html"> - Access Module download page - </a> + Logback modules are available as downloads including full source code, class files + and documentation. </p> + <ul> + <li> + <a href="dist/logback-core-${pom.version}.zip"> + logback-core-${pom.version}.zip + </a> + </li> + + <li> + <a href="dist/logback-core-${pom.version}.tar.gz"> + logback-core-${pom.version}.tar.gz + </a> + </li> + </ul> + <ul> + <li> + <a href="dist/logback-classic-${pom.version}.zip"> + logback-classic-${pom.version}.zip + </a> + </li> + + <li> + <a href="dist/logback-classic-${pom.version}.tar.gz"> + logback-classic-${pom.version}.tar.gz + </a> + </li> + </ul> + <ul> + <li> + <a href="dist/logback-access-${pom.version}.zip"> + logback-access-${pom.version}.zip + </a> + </li> + + <li> + <a href="dist/logback-access-${pom.version}.tar.gz"> + logback-access-${pom.version}.tar.gz + </a> + </li> + </ul> + + </body> -</document> +</document> \ No newline at end of file Added: logback/trunk/logback-site/src/site/xdocTemplates/license.xml ============================================================================== --- (empty file) +++ logback/trunk/logback-site/src/site/xdocTemplates/license.xml Wed Aug 9 19:30:13 2006 @@ -0,0 +1,40 @@ +<?xml version="1.0"?> +<document> + + <properties> + <author email="ceki at qos ddoott ch ">Ceki Gulcu</author> + <title>Logback project License</title> + </properties> + + <body> + + <div class="section"> + <h2>Logback License</h2> + </div> + + <p> + Logback source code and binaries are distributed + under the + <a href="http://www.gnu.org/licenses/lgpl.html"> + GNU Lesser General Public License + </a> + as published by the Free Software Foundation. + </p> + + <div class="source"> + <p> +Logback: the reliable, generic, fast and flexible +logging library for Java.<br/> + +Copyright (C) 2000-2006, QOS.ch <br/> + +This library is free software, you can redistribute it +and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software +Foundation. + </p> + </div> + + + </body> +</document> \ No newline at end of file Modified: logback/trunk/logback-site/src/site/xdocTemplates/repos.xml ============================================================================== --- logback/trunk/logback-site/src/site/xdocTemplates/repos.xml (original) +++ logback/trunk/logback-site/src/site/xdocTemplates/repos.xml Wed Aug 9 19:30:13 2006 @@ -2,30 +2,82 @@ <document> <properties> - Authors: Ceki Gülcü, Sébastien Pennec - <title>logback source repositories</title> + <author email="ceki at qos ddoott ch ">Ceki Gulcu</author> + <title>Logback source repository</title> </properties> <body> - <h2>Download links</h2> + + <div class="section"> + <h2>Source Repository</h2> + </div> <p> - Logback source repositories can be accessed by visiting their specific pages: + To enable logback developers to work together, we + keep the source code in revision control systems called + Subversion. Developers have write access to the Subversion + repository, enabling them to make changes to the source + code. Everyone has read access to the repositories, so you + may download the most up-to-date development version of the + software. Note that the latest version in the Subversion + repository many not work as expected, it may not even + compile properly. If you are looking for a stable release of + the source code, you should download an official + distribution instead of the latest version in the Subversion + repositories. + + There are several ways to access the Subversion + repositories: </p> + <div class="section"> + <h2>Web Access</h2> + </div> <p> - <a href="core/repos.html">Core source repository</a> + If you just wish to browse around or download a few + individual files, the best tool is the web-based ViewCVS + interface for CVS repositories and ViewCVS interface for + Subversion or go straight to the public repositories at: </p> <p> - <a href="classic/repos.html"> - Classic source repository + <a href="http://svn.qos.ch/viewcvs/logback/core/trunk"> + Logback core SVN Repository </a> </p> <p> - <a href="access/repos.html"> - Access source repository + <a href="http://svn.qos.ch/viewcvs/logback/classic/trunk"> + Logback classic SVN Repository + </a> + </p> + <p> + <a href="http://svn.qos.ch/viewcvs/logback/access/trunk"> + Logback access SVN Repository </a> </p> + <div class="section"> + <h2>Checking out a read-only copy</h2> + </div> + <p> + To access the Subversion repositories anonymously, you will + need a Subversion client. + + To check out one of the logback project modules, issue one of the following commands: + </p> + + <div class="source">svn co http://svn.qos.ch/repos/logback/core/trunk</div> + + <div class="source">svn co http://svn.qos.ch/repos/logback/classic/trunk</div> + + <div class="source">svn co http://svn.qos.ch/repos/logback/access/trunk</div> + + <div class="section"> + <p> + Note that anonymous access allows read-only access only. + For read-write access please contact the logback + <a href="../mailinglist.html">developer list</a> + . + </p> + </div> </body> -</document> +</document> \ No newline at end of file Added: logback/trunk/logback-site/src/site/xdocTemplates/shortIntro.xml ============================================================================== --- (empty file) +++ logback/trunk/logback-site/src/site/xdocTemplates/shortIntro.xml Wed Aug 9 19:30:13 2006 @@ -0,0 +1,1147 @@ +<document> + <!-- + + Warning: do not use any auto-format function on this file. + Since "source" divs use pre as white-space, it affects the + look of the code parts in this document. + + --> + + + <body> + <h2>Short introduction</h2> + <div class="author"> + Authors: Ceki Gülcü, Sébastien Pennec + </div> + + + <table> + <tr> + <td valign="top" align="top"> + <a rel="license" + href="http://creativecommons.org/licenses/by-nc-nd/2.5/"> + <img alt="Creative Commons License" border="0" + valign="top" align="top" + src="http://creativecommons.org/images/public/somerights20.png" /> + </a> + </td> + <td> + <p>Copyright © 2000-2006, QOS.ch</p> + + <p> + This work is licensed under a + <a rel="license" + href="http://creativecommons.org/licenses/by-nc-nd/2.5/"> + Creative Commons Attribution-Noncommercial-No + Derivative Works 2.5 License + </a> + . + </p> + </td> + </tr> + </table> + + <h2>Introduction</h2> + + <p> + Logback is intended as a successor to the popular log4j project. + It was designed by Ceki Gülcü, the founder of the + log4j project. It builds upon a decade long experience gained in + designing industrial-strength logging systems. The resulting + product is at faster and has a smaller footprint than all the + existing logging systems, sometimes by a wide margin. Logback + also offers unique and rather useful features such as Markers, + parameterized logging statements, conditional stack tracing and + powerful event filtering, to cite a few. For its own error + reporting, logback relies on + <code>Status</code> + objects which come in handy in contexts other than logging. + </p> + + <p> + This document presents the more basic concepts in logback, + probably just enough to get you started. + </p> + + <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 Core. Classic 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. The Access module will be covered + in a separate document. + </p> + <p> + In this document, we will use the word logback to refer to the + logback classic module. + </p> + + <h2>First Baby Step</h2> + + <p> + After you have added the jar files + <em>logback-core.jar</em> + and + <em>logback-classic.jar</em> + to your classpath, you can begin experimenting with logback. + </p> + +<div class="source"><em>Example 1.1: Basic template for logging (examples/chapter1/HelloWorld1.java)</em> +package chapter1; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HelloWorld1 { + + public static void main(String[] args) { + + Logger logger = LoggerFactory.getLogger(HelloWorld1.class); + logger.debug("Hello world."); + + } +}</div> + + <p> + The <code>HelloWorld</code> class is defined in the + <code>chapter1</code> package. It starts by importing the <code>Logger</code> + and <code>LoggerFactory</code> + classes as defined in the SLF4J API, more specifically in the <code>org.slf4j</code> + package. + </p> + + + <p> + On line 10, the variable named <code>logger</code> + is assigned a <code>Logger</code> + instance retreived by invoking the static method <code>getLogger</code> + in the <code>LoggerFactory</code> class. + This logger is named "chapter1/HelloWorld1". The main method proceeds to call its + <code>debug</code> method with the argument "Hello world." We say that the main + method contains a logging statement of level debug containing the message “Hello world”. + </p> + + <p> + You will note that the above example does not reference any + logback classes. In most cases, as far as logging is + concerned, your classes will need to import only SLF4J + classes. In principle, you will have to import logback + classes only for configuring logback. Thus, the vast + majority of your classes will only be cognizant of SLF4J API + and oblivious to the existence of logback. + </p> + + + <p> + <b>ceki: compile?</b> + You can compile and run this class with the command: + </p> + + <div class="source">java chapter1.HelloWorld1</div> + + <p> + Suprisingly enough, launching the <code>HelloWorld1</code> + application will not produce <em>any</em> output. + Logback does not posses a default configuration. + Without a valid configuration, logback will be as silent as a mummy. + </p> + + <p> + Logback can report information about its internal state + using a built-in status system. Important events occuring + during logback's lifetime can be accessed through a + <code>StatusManager</code>. For the time being, let us tell logback to print its + internal state. This is accomplished by a static method in + the <code>LoggerStatusPrinter</code> + class. + </p> + +<div class="source"><em>Example 1.2: Printing Logger Status (examples/chapter1/HelloWorld2.java)</em> +package chapter1; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +<b>import ch.qos.logback.classic.util.LoggerStatusPrinter;</b> + +public class HelloWorld2 { + + public static void main(String[] args) { + Logger logger = LoggerFactory.getLogger(HelloWorld2.class); + logger.debug("Hello world."); + <b>LoggerStatusPrinter.printStatusInDefaultContext();</b> + } +}</div> + + + <p>Running the <code>HelloWorld2</code> application will produce + the following output:</p> + +<div class="source">ERROR in Logger[chapter1.HelloWorld2] - \ +No appenders present in context [default] for logger [chapter1.HelloWorld2].</div> + + + <!-- ========= CEKI: STOPPED HERE =================== --> + + <p> + Logback is complaining that no appenders were configured for the + default context. An Appender is a class that can be seen as an + output destination. Appenders exist for many different + destinations including the console, files, and many more. Users + can also easily create their own Appenders for any specific + situation. + </p> + + <p> + Configuring logback can be done a different ways. The + simplest but less flexible way is by calling the + <code>BasicConfigurator</code> class, like in the following code snippet. + </p> + <div class="source"><em>Example 1.3: Configuring before logging (examples/chapter1/HelloWorld3.java)</em> +package chapter1; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +<b>import ch.qos.logback.BasicConfigurator;</b> +import ch.qos.logback.classic.util.LoggerStatusPrinter; + +public class HelloWorld3 { + + public static void main(String[] args) { + Logger logger = LoggerFactory.getLogger(HelloWorld3.class); + <b>BasicConfigurator.configureDefaultContext();</b> + logger.debug("Hello world."); + LoggerStatusPrinter.printStatusInDefaultContext(); + + } +}</div> + + <p> + Let's run the <code>HelloWorld3</code> + application again. Now, the <code>BasicConfigurator</code> + will create a simple <code>ConsoleAppender</code>. + The logging request will then be propagated to the + Appender and the console will output the following: + </p> +<div class="source">0 [main] DEBUG chapter1.HelloWorld3 - Hello world.</div> + + <p> + This example is very simple. However, actual logging in a larger + application is not much more complicated. The logging statement + will barely change. Only the configuration process will be + different, since you don't need (nor should) configure the + logging context in each and every class that will require + logging. As well, the LoggerStatusPrinter will certainly not be + used after all the logging statements. + </p> + + <p> + These are the three steps that are required to allow full logging in any application. + </p> + + <ol> + <li>Configure the logback environment. You can do it using several + sophisticated ways. The BasicConfigurator is the simplest but also least flexible.</li> + <li>In every class where you wish to perform logging, retrieve a Logger + instance by invoking the LoggerFactory and passing the current class as the parameter.</li> + <li>Use this logger instance by invoking its printing methods, namely + the debug(), info(), warn() and error() methods. This will produce logging on the + configured devices.</li> + </ol> + + <div class="section"> + <h2>Logger, Appenders and Layouts</h2> + </div> + <p> + Logback 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> + Loggers are defined in the classic module. On the other + hand, Appenders and Layouts are defined in the core module + of logback. + </p> + + <h3>Logger context</h3> + + <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. + </p> + + <p> + In logback, Loggers are named entities. Their names are case-sensitive and they follow the + contextual naming rule: + </p> + <div class="definition"> + <div class="deftitle">Named Context</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 context. + It is exceptional in a way that is always exists. Like every + logger, it can be retrieved by its name, like this: + </p> + <div class="source">Logger rootLogger = LoggerFactory.getLogger("root");</div> + + <p> + 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. + </p> + + <div class="source">package org.slf4j; +public interface Logger { + + // 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); +}</div> + + <p> + Loggers may be assigned levels. The set of possible levels, + that is DEBUG, INFO, WARN and ERROR are defined in the + <em>ch.qos.logback.classic.Level</em> class. The level class cannot + be sub-classed as a much better approach exist in the form + of Marker objects. + </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 <em>L</em>, + is equal to the first non-null level in the logger context, starting at + <em>L</em> and proceeding upwards in the context 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> + <tr> + <th> + Logger + <br /> + name + </th> + <th> + Assigned + <br /> + level + </th> + + <th> + Inherited + <br /> + level + </th> + </tr> + <tr> + <td>root</td> + <td>L<sub>root</sub></td> + <td>L<sub>root</sub></td> + </tr> + <tr> + <td>X</td> + <td>none</td> + <td>L<sub>root</sub></td> + </tr> + + <tr> + <td>X.Y</td> + <td>none</td> + <td>L<sub>root</sub></td> + </tr> + <tr> + <td>X.Y.Z</td> + <td>none</td> + <td>L<sub>root</sub></td> + </tr> + </table> + <p> + In example 1 above, only the root logger is assigned a + level. + </p> + This level value, <code>L<sub>root</sub></code>, is inherited by the other loggers + <code>X</code>, <code>X.Y</code> and <code>X.Y.Z</code> + <table> + <tr> + <th> + Logger + <br /> + name + </th> + <th> + Assigned + <br /> + level + </th> + + <th> + Inherited + <br /> + level + </th> + </tr> + <tr align="left"> + <td>root</td> + <td>L<sub>root</sub></td> + <td>L<sub>root</sub></td> + </tr> + <tr align="left"> + <td>X</td> + <td>L<sub>x</sub></td> + <td>L<sub>x</sub></td> + </tr> + + <tr align="left"> + <td>X.Y</td> + <td>L<sub>xy</sub></td> + <td>L<sub>xy</sub></td> + </tr> + <tr align="left"> + <td>X.Y.Z</td> + <td>L<sub>xyz</sub></td> + <td>L<sub>xyz</sub></td> + </tr> + </table> + + <p> + In example 2, all loggers have an assigned level value. + There is no need for level inheritence. + </p> + + <table> + <tr> + <th> + Logger + <br /> + name + </th> + <th> + Assigned + <br /> + level + </th> + <th> + Inherited + <br /> + level + </th> + </tr> + <tr align="left"> + <td>root</td> + <td>L<sub>root</sub></td> + <td>L<sub>root</sub></td> + </tr> + + <tr align="left"> + <td>X</td> + <td>L<sub>x</sub></td> + <td>L<sub>x</sub></td> + </tr> + <tr align="left"> + <td>X.Y</td> + <td>none</td> + <td>L<sub>x</sub></td> + </tr> + <tr align="left"> + <td>X.Y.Z</td> + <td>L<sub>xyz</sub></td> + <td>L<sub>xyz</sub></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>L<sub>root</sub></code>, + <code>L<sub>x</sub></code> and <code>L<sub>xyz</sub></code> + respectively. The logger <code>X.Y</code> + inherits its level value from its parent <code>X</code>. + </p> + <table> + + <tr> + <th> + Logger + <br /> + name + </th> + <th> + Assigned + <br /> + level + </th> + <th> + Inherited + <br /> + level + </th> + </tr> + <tr align="left"> + <td>root</td> + <td>L<sub>root</sub></td> + <td>L<sub>root</sub></td> + </tr> + + <tr align="left"> + <td>X</td> + <td>L<sub>x</sub></td> + <td>L<sub>x</sub></td> + </tr> + <tr align="left"> + <td>X.Y</td> + <td>none</td> + <td>L<sub>x</sub></td> + </tr> + <tr align="left"> + <td>X.Y.Z</td> + <td>none</td> + <td>L<sub>x</sub></td> + </tr> + </table> + + <p> + In example 4, the loggers <code>root</code> and <code>X</code> + and are assigned the levels <code>L<sub>root</sub></code> and + <code>L<sub>x</sub></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> + + <h3>Printing methods</h3> + <p> + By definition, the printing method determines the level of a + logging request. For example, if <code>L</code> + is a logger instance, then the statement <code>L.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 context. 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. It assumes + that levels are ordered. For the standard levels, we have + <code>DEBUG < INFO < WARN < ERROR</code>. + </p> + + <p> + In a more graphic way, here is how the selection rule works: in the following + table, the horizontal header shows the level of the logging request, while the + vertical header shows the level of the logger. + </p> + + <table> + <tr> + <td></td> + <th>DEBUG</th> + <th>INFO</th> + <th>WARN</th> + <th>ERROR</th> + </tr> + <tr> + <th>DEBUG</th> + <td><span class="greenBold">YES</span></td> + <td><span class="greenBold">YES</span></td> + <td><span class="greenBold">YES</span></td> + <td><span class="greenBold">YES</span></td> + </tr> + <tr> + <th>INFO</th> + <td><span class="redBold">NO</span></td> + <td><span class="greenBold">YES</span></td> + <td><span class="greenBold">YES</span></td> + <td><span class="greenBold">YES</span></td> + </tr> + <tr> + <th>WARN</th> + <td><span class="redBold">NO</span></td> + <td><span class="redBold">NO</span></td> + <td><span class="greenBold">YES</span></td> + <td><span class="greenBold">YES</span></td> + </tr> + <tr> + <th>ERROR</th> + <td><span class="redBold">NO</span></td> + <td><span class="redBold">NO</span></td> + <td><span class="redBold">NO</span></td> + <td><span class="greenBold">YES</span></td> + </tr> + </table> + + <p>Here is an example of this rule.</p> + + <div class="source">// get a logger instance named "com.foo", with an <span class="blue">INFO</span>level. +Logger logger = LoggerFactory.getLogger("com.foo"); +Logger barlogger = LoggerFactory.getLogger("com.foo.Bar"); + +// This request is enabled, because <span class="green">WARN</span> >= <span class="blue">INFO</span> +logger.<span class="green">warn</span>("Low fuel level."); + +// This request is disabled, because <span class="green">DEBUG</span> < <span class="blue">INFO</span>. +logger.<span class="green">debug</span>("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 <span class="green">INFO</span> >= <span class="blue">INFO</span>. +barlogger.<span class="green">info</span>("Located nearest gas station."); + +// This request is disabled, because<span class="green">DEBUG</span> < <span class="blue">INFO</span>. +barlogger.<span class="green">debug</span>("Exiting gas station search");</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"); +Logger y = LoggerFactory.getLogger("wombat");</div> + + <p> + <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, logback 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> + + <h3>Appenders and Layouts</h3> + + <p> + The ability to selectively enable or disable logging + requests based on their logger is only part of the picture. + Logback allows logging requests to print to multiple + destinations. In logback speak, an output destination is + called an appender. Currently, appenders exist for the + console, files, remote socket servers, JMS, 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 context. In other words, appenders + are inherited additively from the logger context. 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>L</em>, then enabled logging requests for + <em>L</em> and <em>L</em>'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>L</em> + will go to all the appenders in <em>L</em> + and its ancestors. This is the meaning of the term + "appender additivity". + </p> + + <p> + However, if an ancestor of logger <em>L</em>, say + <em>P</em>, has the additivity flag set to false, then + <em>L</em>'s output will be directed to all the appenders in + <em>L</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 + logback 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> + + <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()) { + logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); +}</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(); 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+"."); +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> + + <h3>Configuration</h3> + + <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 logback environment is fully configurable programmatically. + However, it is far more flexible to configure logback using + configuration files. Currently, configuration files must be written in + XML format. + </p> + <p> + Let us give a taste of how this is done with the help of an + imaginary application MyApp that uses logback. + </p> +<div class="source"><em>Example 1.4: Basic configuration (examples/chapter1/MyApp.java)</em> +package chapter1; + +// Import SLF4J classes. +import org.slf4j.LoggerFactory; +import org.slf4j.Logger; + +import ch.qos.logback.BasicConfigurator; + +public class MyApp { + + public static void main(String[] args) { + + // Set up a simple configuration that logs on the console. + BasicConfigurator.configureDefaultContext(); + + Logger logger = LoggerFactory.getLogger(MyApp.class); + + logger.info("Entering application."); + Bar bar = new Bar(); + bar.doIt(); + logger.info("Exiting application."); + } +}</div> + <p> + This class begins by defining a static logger instance variable + with the name MyApp. It then uses the Bar class, defined as shown below: + </p> +<div class="source">class Bar { + + Logger logger = LoggerFactory.getLogger(Bar.class); + + public void doIt() { + logger.debug("doing my job"); + } +}</div> + <p> + The invocation of the BasicConfigurator create, as we have seen, + a simple yet sufficient logback setup. By default, + the root Logger is assigned to Level.DEBUG. + </p> + <p>The BasicConfigurator has to be called only once. Any other class that wishes to + issue log statements only has to import the <em>Logger class</em> and use it.</p> + <p> + The output of MyApp is: + </p> +<div class="source">0 [main] INFO ch.qos.logback.classic.examples.MyApp - Entering application. +0 [main] DEBUG ch.qos.logback.classic.examples.Bar - doing my job +0 [main] INFO ch.qos.logback.classic.examples.MyApp - Exiting application.</div> + + <p>Let's configure logback to do exactly the same output, this time + with an XML configuration file.</p> + +<div class="source"><?xml version="1.0" encoding="UTF-8" ?> + +<configuration> + + <appender name="STDOUT" + class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <param name="pattern" + value="%-4relative [%thread] %-5level %class - %msg%n" /> + </layout> + </appender> + + <root> + <level value="debug" /> + <appender-ref ref="STDOUT" /> + </root> +</configuration></div> + + <p>We first created an Appender, named <em>STDOUT</em> that is of ConsoleAppender tye. Its layout + is managed by a PatternLayout, that uses the value of the "pattern" parameter to generate + the logging statement. We then configured the root logger, set its level to DEBUG, + and linked the newly configured ConsoleAppender to the root logger.</p> + <p>Note that we've set the root logger level explicitly. Since root logger have a DEBUG level + by default we could have omitted this.</p> + + <p>To run this examle, use this command:</p> + +<div class="source">java MyApp sample-config-1.xml</div> + + <p>The console output will be exactly the same as before. However, this time, we didn't need + to import and call the BasicConfigurator class, as you can see in the following code section: + </p> +<div class="source"><em>Example 1.5: Logback configuration from file (examples/chapter1/MyAppWithConfigFile.java)</em> +package chapter1; + +//Import SLF4J classes. +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.Logger; +<b>import ch.qos.logback.classic.joran.JoranConfigurator;</b> + +public class MyAppWithConfigFile { + + public static void main(String[] args) throws Exception { + Logger logger = (Logger) LoggerFactory.getLogger(MyAppWithConfigFile.class); + + JoranConfigurator configurator = new JoranConfigurator(); + configurator.setContext(logger.getLoggerContext()); + configurator.doConfigure(args[0]); + + logger.info("Entering application."); + Bar bar = new Bar(); + bar.doIt(); + logger.info("Exiting application."); + } +}</div> + <p> + We used the JoranConfigurator class to parse the configuration file we just created. + Joran is a XML interpreter, similar to the commons-digester API, but offering several + small advantages over commons-digester. Here, it parses the xml file and runs actions depending + on the tags it finds. + </p> + + <p>Logging to the console is a rather simple example. Let's now configure logback + so that it logs to the console, but also to a custom file.</p> + +<div class="source"><?xml version="1.0" encoding="UTF-8" ?> + +<configuration> + + <appender name="STDOUT" + class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <param name="pattern" + value="%-4relative [%thread] %-5level %class - %msg%n" /> + </layout> + </appender> + + <appender name="FILE" + class="ch.qos.logback.core.FileAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <param name="pattern" + value="%-4relative [%thread] %-5level %class - %msg%n" /> + </layout> + <param name="File" + value="sample-log.txt" /> + </appender> + + <root> + <level value="debug" /> + <appender-ref ref="STDOUT" /> + <appender-ref ref="FILE" /> + </root> +</configuration></div> + + <p>Now, all the logging statements are directed to the console and to a file named <em>sample-log.txt</em>. + As you can see, the configuration needed to add an Appender is very small. The param element, in either + Appender configuration, reads the <em>name</em> attribute and assigns its value to the corresponding attribute + in the specified java class. + </p> + + <p>Suppose that we do not want to see the DEBUG level statements in the chapter1 package anymore. + This is done by adding a <em>logger</em> element, with a nested element specifying its level value.</p> + + <p>This done, the output is modified to show only statements of level INFO and higher.</p> + +<div class="source">0 [main] INFO chapter1.MyAppWithConfigFile - Entering application. +0 [main] INFO chapter1.MyAppWithConfigFile - Exiting application.</div> + + <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 chapter1 output + to an NT Event logger, or forwarded logging events to a remote logback server, + which would log according to local server policy, for example by forwarding the log event + to a second logback server.</p> + + </body> +</document>