svn commit: r1262 - in logback/trunk: logback-examples/src/main/java/chapter1 logback-examples/src/main/java/chapter2 logback-site/src/site/xdocTemplates/manual

Author: seb Date: Mon Jan 22 16:58:04 2007 New Revision: 1262 Added: logback/trunk/logback-examples/src/main/java/chapter2/ logback/trunk/logback-examples/src/main/java/chapter2/Bar.java logback/trunk/logback-examples/src/main/java/chapter2/HelloWorld2.java logback/trunk/logback-examples/src/main/java/chapter2/MyAppWithConfigFile.java logback/trunk/logback-examples/src/main/java/chapter2/sample-config-1.xml logback/trunk/logback-examples/src/main/java/chapter2/sample-config-2.xml logback/trunk/logback-examples/src/main/java/chapter2/sample-config-3.xml logback/trunk/logback-site/src/site/xdocTemplates/manual/architecture.xml logback/trunk/logback-site/src/site/xdocTemplates/manual/introduction.xml Removed: logback/trunk/logback-examples/src/main/java/chapter1/Bar.java logback/trunk/logback-examples/src/main/java/chapter1/MyApp.java logback/trunk/logback-examples/src/main/java/chapter1/MyAppWithConfigFile.java logback/trunk/logback-examples/src/main/java/chapter1/sample-config-1.xml logback/trunk/logback-examples/src/main/java/chapter1/sample-config-2.xml logback/trunk/logback-examples/src/main/java/chapter1/sample-config-3.xml Modified: logback/trunk/logback-site/src/site/xdocTemplates/manual/index.xml Log: Split of the short intro into a chapter1: introduction and chapter2: architecture. Moved examples accordingly Added: logback/trunk/logback-examples/src/main/java/chapter2/Bar.java ============================================================================== --- (empty file) +++ logback/trunk/logback-examples/src/main/java/chapter2/Bar.java Mon Jan 22 16:58:04 2007 @@ -0,0 +1,21 @@ +/** + * Logback: the generic, reliable, fast and flexible logging framework. + * + * Copyright (C) 1999-2006, QOS.ch + * + * 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. + */ +package chapter2; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class Bar { + Logger logger = LoggerFactory.getLogger(Bar.class); + + public void doIt() { + logger.debug("doing my job"); + } +} \ No newline at end of file Added: logback/trunk/logback-examples/src/main/java/chapter2/HelloWorld2.java ============================================================================== --- (empty file) +++ logback/trunk/logback-examples/src/main/java/chapter2/HelloWorld2.java Mon Jan 22 16:58:04 2007 @@ -0,0 +1,24 @@ +/** + * Logback: the generic, reliable, fast and flexible logging framework. + * + * Copyright (C) 1999-2006, QOS.ch + * + * 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. + */ +package chapter2; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.util.LoggerStatusPrinter; + +public class HelloWorld2 { + + public static void main(String[] args) { + Logger logger = LoggerFactory.getLogger("chapter2.HelloWorld2"); + logger.debug("Hello world."); + LoggerStatusPrinter.printStatusInDefaultContext(); + } +} Added: logback/trunk/logback-examples/src/main/java/chapter2/MyAppWithConfigFile.java ============================================================================== --- (empty file) +++ logback/trunk/logback-examples/src/main/java/chapter2/MyAppWithConfigFile.java Mon Jan 22 16:58:04 2007 @@ -0,0 +1,41 @@ +/** + * Logback: the generic, reliable, fast and flexible logging framework. + * + * Copyright (C) 1999-2006, QOS.ch + * + * 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. + */ +package chapter2; + +//Import SLF4J classes. +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.core.joran.spi.JoranException; +import ch.qos.logback.core.util.StatusPrinter; + +public class MyAppWithConfigFile { + + public static void main(String[] args) { + Logger logger = LoggerFactory.getLogger(MyAppWithConfigFile.class); + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + + try { + JoranConfigurator configurator = new JoranConfigurator(); + lc.shutdownAndReset(); + configurator.setContext(lc); + configurator.doConfigure(args[0]); + } catch (JoranException je) { + StatusPrinter.print(lc.getStatusManager()); + } + logger.info("Entering application."); + Bar bar = new Bar(); + bar.doIt(); + logger.info("Exiting application."); + + } +} Added: logback/trunk/logback-examples/src/main/java/chapter2/sample-config-1.xml ============================================================================== --- (empty file) +++ logback/trunk/logback-examples/src/main/java/chapter2/sample-config-1.xml Mon Jan 22 16:58:04 2007 @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<configuration> + + <appender name="STDOUT" + class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> + </layout> + </appender> + + <root> + <level value="debug" /> + <appender-ref ref="STDOUT" /> + </root> +</configuration> Added: logback/trunk/logback-examples/src/main/java/chapter2/sample-config-2.xml ============================================================================== --- (empty file) +++ logback/trunk/logback-examples/src/main/java/chapter2/sample-config-2.xml Mon Jan 22 16:58:04 2007 @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<configuration> + + <appender name="STDOUT" + class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern> + </layout> + </appender> + + <appender name="FILE" + class="ch.qos.logback.core.FileAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern> + </layout> + <File>sample-log.txt</File> + </appender> + + <root> + <level value="debug" /> + <appender-ref ref="STDOUT" /> + <appender-ref ref="FILE" /> + </root> +</configuration> Added: logback/trunk/logback-examples/src/main/java/chapter2/sample-config-3.xml ============================================================================== --- (empty file) +++ logback/trunk/logback-examples/src/main/java/chapter2/sample-config-3.xml Mon Jan 22 16:58:04 2007 @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<configuration> + + <appender name="STDOUT" + class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern> + </layout> + </appender> + + <appender name="FILE" + class="ch.qos.logback.core.FileAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern> + </layout> + <File>sample-log.txt</File> + </appender> + + <logger name="chapter2"> + <level value="info" /> + </logger> + + <root> + <level value="debug" /> + <appender-ref ref="STDOUT" /> + <appender-ref ref="FILE" /> + </root> +</configuration> Added: logback/trunk/logback-site/src/site/xdocTemplates/manual/architecture.xml ============================================================================== --- (empty file) +++ logback/trunk/logback-site/src/site/xdocTemplates/manual/architecture.xml Mon Jan 22 16:58:04 2007 @@ -0,0 +1,1037 @@ +<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>Chapter 2: Architecture</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-sa/2.5/"> + <img alt="Creative Commons License" + style="border-width: 0" + src="http://creativecommons.org/images/public/somerights20.png" /> + </a> + </td> + <td> + <p>Copyright © 2000-2006, QOS.ch</p> + + <p> + <!--Creative Commons License--> + This work is licensed under a + <a rel="license" + href="http://creativecommons.org/licenses/by-nc-sa/2.5/"> + Creative Commons + Attribution-NonCommercial-ShareAlike 2.5 + License + </a> + . + <!--/Creative Commons License--> + </p> + </td> + </tr> + </table> + + + <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 <em>core</em> module lays the groundwork for the other two + modules. The <em>classic</em> module extends <em>core</em>. The + classic module corresponds to a significantly 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 third module called + <em>access</em> integrates with Servlet containers to provide + HTTP-access log functionality. The access module will be covered + in a <a href="access.html">separate document</a>. + </p> + <p> + In the reminder of this document, we will write "logback" to refer to the + logback classic module. + </p> + + <h2>Logger, Appenders and Layouts</h2> + + <p> + Logback has three main types: <code>Logger</code>, + <code>Appender</code> and <code>Layout</code>. 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 Logger class is part of the classic module. On the other + hand, the <code>Appender</code> and <code>Layout</code> interfaces + are part of the core module. For the sake of genericity, + logback-core has no notion of loggers. + </p> + + <h3>Logger context</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. In logback, this + categorization is an inherent part of loggers. + </p> + + <p> + Loggers are named entities. Their 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 that it is part of every hierarchy at its + inception. Like every logger, it can be retrieved by its name, + as follows: + </p> + <div class="source"><pre>Logger rootLogger = LoggerFactory.getLogger(<a href="apidocs/constant-values.html#ch.qos.logback.classic.LoggerContext.ROOT_NAME">LoggerContext.<em>ROOT_NAME</em></a>);</pre></div> + + <p> + All other loggers are also retrieved with the class static + <code>getLogger</code> method found in the <a + href="http://www.slf4j.org/api/org/slf4j/Logger.html">org.slf4j.LoggerFactory</a> + class. This method takes the name of the desired logger as a + parameter. Some of the basic methods in the <code>Logger</code> + interface are listed below. + </p> + + <div class="source"><pre>package org.slf4j; +public interface Logger { + + // Printing methods: + public void debug(String message); + public void info(String message); + public void warn(String message); + public void error(String message); + public void fatal(String message); +}</pre></div> + + <p> + Loggers may be assigned levels. The set of possible levels, that + is DEBUG, INFO, WARN and ERROR are defined in the + <code>ch.qos.logback.classic.Level</code> class. Note that in + logback, the level class is final and cannot be derived, as a + much more flexible 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 effective level for a given logger <em>L</em>, is equal to + the first non-null level in its hierarchy, starting at + <em>L</em> itself 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. By default, this level + is DEBUG. + </p> + <p> + Below are four examples with various assigned level values and + the resulting effective (inherited) levels according to the + level inheritance rule. + </p> + + <em>Example 1</em> + <table> + <tr> + <th> + Logger name + </th> + <th> + Assigned level + </th> + + <th> + Effective level + </th> + </tr> + <tr> + <td>root</td> + <td>DEBUG</td> + <td>DEBUG</td> + </tr> + <tr> + <td>X</td> + <td>none</td> + <td>DEBUG</td> + </tr> + + <tr> + <td>X.Y</td> + <td>none</td> + <td>DEBUG</td> + </tr> + <tr> + <td>X.Y.Z</td> + <td>none</td> + <td>DEBUG</td> + </tr> + </table> + + <p> In example 1 above, only the root logger is assigned a level. + This level value, <code>DEBUG</code>, is inherited by the other + loggers <code>X</code>, <code>X.Y</code> and <code>X.Y.Z</code> + </p> + + <em>Example 2</em> + <table> + <tr> + <th> + Logger name + </th> + <th> + Assigned level + </th> + + <th> + Effective level + </th> + </tr> + <tr align="left"> + <td>root</td> + <td>ERROR</td> + <td>ERROR</td> + </tr> + <tr align="left"> + <td>X</td> + <td>INFO</td> + <td>INFO</td> + </tr> + + <tr align="left"> + <td>X.Y</td> + <td>DEBUG</td> + <td>DEBUG</td> + </tr> + <tr align="left"> + <td>X.Y.Z</td> + <td>WARN</td> + <td>WARN</td> + </tr> + </table> + + <p>In example 2 above, all loggers have an assigned level value. + Level inheritence does not come into play. + </p> + + <em>Example 3</em> + <table> + <tr> + <th> + Logger name + </th> + <th> + Assigned level + </th> + <th> + Effective level + </th> + </tr> + <tr align="left"> + <td>root</td> + <td>DEBUG</td> + <td>DEBUG</td> + </tr> + + <tr align="left"> + <td>X</td> + <td>INFO</td> + <td>INFO</td> + </tr> + <tr align="left"> + <td>X.Y</td> + <td>none</td> + <td>INFO</td> + </tr> + <tr align="left"> + <td>X.Y.Z</td> + <td>ERROR</td> + <td>ERROR</td> + </tr> + </table> + <p> + In example 3 above, the loggers <code>root</code>, <code>X</code> + and <code>X.Y.Z</code> are assigned the levels <code>DEBUG</code>, + <code>INFO</code> and <code>ERROR</code> + respectively. Logger <code>X.Y</code> + inherits its level value from its parent <code>X</code>. + </p> + <em>Example 4</em> + <table> + + <tr> + <th> + Logger name + </th> + <th> + Assigned level + </th> + <th> + Effective level + </th> + </tr> + <tr align="left"> + <td>root</td> + <td>DEBUG</td> + <td>DEBUG</td> + </tr> + + <tr align="left"> + <td>X</td> + <td>INFO</td> + <td>INFO</td> + </tr> + <tr align="left"> + <td>X.Y</td> + <td>none</td> + <td>INFO</td> + </tr> + <tr align="left"> + <td>X.Y.Z</td> + <td>none</td> + <td>INFO</td> + </tr> + </table> + + + <p>In example 4 above, the loggers <code>root</code> and + <code>X</code> and are assigned the levels <code>DEBUG</code> and + <code>INFO</code> respectively. The loggers <code>X.Y</code> and + <code>X.Y.Z</code> inherit their level value from their nearest + parent <code>X</code>, which has 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 statement 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 an + effective 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 as follows: + <code>DEBUG < INFO < WARN < ERROR< OFF</code>. + </p> + + <p>In a more graphic way, here is how the selection rule works. In + the following table, the vertical header shows the the level of + the logging request, designated by <em>p</em>, while the + horizontal header shows effective level of the logger, designated + by <em>q</em>. + </p> + + <table> + <tr> + <th><span style="align:center"><em>p</em>/<em>q</em></span></th> + <th>DEBUG</th> + <th>INFO</th> + <th>WARN</th> + <th>ERROR</th> + <th>OFF</th> + </tr> + <tr> + <th>DEBUG</th> + <td><span class="greenBold">YES</span></td> + <td><span class="redBold">NO</span></td> + <td><span class="redBold">NO</span></td> + <td><span class="redBold">NO</span></td> + <td><span class="redBold">NO</span></td> + </tr> + <tr> + <th>INFO</th> + <td><span class="greenBold">YES</span></td> + <td><span class="greenBold">YES</span></td> + <td><span class="redBold">NO</span></td> + <td><span class="redBold">NO</span></td> + <td><span class="redBold">NO</span></td> + </tr> + <tr> + <th>WARN</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="redBold">NO</span></td> + <td><span class="redBold">NO</span></td> + </tr> + <tr> + <th>ERROR</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> + <td><span class="redBold">NO</span></td> + </tr> + </table> + + <p>Here is an example of the basic selection rule.</p> + + <div class="source"><pre>// get a logger instance named "com.foo", with an <span class="blue">INFO</span> level. +Logger logger = LoggerFactory.getLogger("com.foo"); +//set its Level to <span class="blue">INFO</span> +logger.setLevel(Level. <span class="blue">INFO</span>); +Logger barlogger = LoggerFactory.getLogger("com.foo.Bar"); + +// This request is enabled, because <span class="green bold">WARN</span> >= <span class="blue">INFO</span> +logger.<span class="green bold">warn</span>("Low fuel level."); + +// This request is disabled, because <span class="green bold">DEBUG</span> < <span class="blue">INFO</span>. +logger.<span class="green bold">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 bold">INFO</span> >= <span class="blue">INFO</span>. +barlogger.<span class="green bold">info</span>("Located nearest gas station."); + +// This request is disabled, because <span class="green bold">DEBUG</span> < <span class="blue">INFO</span>. +barlogger.<span class="green bold">debug</span>("Exiting gas station search");</pre></div> + + <h3>Retrieving Loggers</h3> + <p> + Calling the <code><a href="/apidocs/org/slf4j/LoggerFactory.html#getLogger(java.lang.String)">LoggerFactory.getLogger</a></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"><pre>Logger x = LoggerFactory.getLogger("wombat"); +Logger y = LoggerFactory.getLogger("wombat");</pre></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 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. As a developer, you are free to name loggers as you + wish. + </p> + + <p>Nevertheless, naming loggers after the class where they are + located seems to be the best general 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, to MySQL, PostgreSQL, Oracle and other + databases, 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 <code><a href="apidocs/ch/qos/logback/classic/Logger.html#addAppender(ch.qos.logback.core.Appender)">addAppender</a></code> 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 <em>L</em>, + then enabled logging requests for <em>L</em> and <em>L</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 setting the additivity flag + of a logger 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>Attached 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>Since the root logger stands at the top of the logger + hiearchy, the additivity flag does not apply to it. + </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 of 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 of 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 of "x.y.z", "x" and of root.</td> + </tr> + <tr> + <td>security</td> + <td>A-sec</td> + <td class="blue"><span class="blue">false</span></td> + <td>A-sec</td> + + <td> + No appender accumulation since the additivity flag is set to + <code>false</code>. Only appender A-sec will be used. + </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 <code>PatternLayout</code>, 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 + "%-4relative [%thread] %-5level %logger{32} - %msg%n" will output something akin to: + </p> + + <div class="source"><pre>176 [main] DEBUG chapter2.HelloWorld2 - Hello world.</pre></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 request. The fourth field is the name of the logger + associated with the log request. The text after the '-' is + the message of the request. + </p> + + <h3>Parameterized logging</h3> + + <p> + Given that loggers in logback-classic implement the <a + href="http://www.slf4j.org/api/org/slf4j/Logger.html">SLF4J's + Logger interface</a>, certain printing methods admit more than + one parameter. These printing method variants are mainly + intended to improve performance while minimizing the impact on + the readability of the code. + </p> + + <p> + For some Logger <code>logger</code>, writing, + </p> + + <div class="source"><pre>logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));</pre></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"><pre>if(logger.isDebugEnabled()) { + logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); +}</pre></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 request. + </p> + + + + <h4>Better alternative</h4> + + <p> + There exists a convenient alternative based on message + formats. Assuming <code>entry</code> is an object, you can write: + </p> + + + <div class="source"><pre>Object entry = new SomeObject(); +logger.debug("The entry is {}.", entry);</pre></div> + + <p> + After evaluting whether to log or not, and only if the decision + is positive, will the logger implementation format the message + and replace the '{}' pair with the string value of + <code>entry</code>. In other words, this 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, in case of a <em>disabled</em> + logging statement, the second variant will outperform the first variant by a + factor of at least 30. + </p> + + <div class="source"><pre>logger.debug("The new entry is "+entry+"."); +logger.debug("The new entry is {}.", entry);</pre></div> + + + <p> + A two argument variant is also availalble. For example, you + can write: + </p> + + <div class="source"><pre>logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);</pre></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"><pre>Object[] paramArray = {newVal, below, above}; +logger.debug("Value {} was inserted between {} and {}.", paramArray);</pre></div> + + <h3>Configuration</h3> + + <p>Inserting log requests into the application code requires a + fair amount of planning and effort. Observation shows that + approximately four percent of code is dedicated to + logging. Consequently, even moderately sized applications will + contain thousands of logging statements embedded within its + 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. In logback, configuration files are written + in XML format. + </p> + + <p>Existing log4j users can convert their + <em>log4j.properties</em> files to <em>logback.xml</em> using our <a + href="http://logback.qos.ch/translator/">PropertiesTranslator</a> + web-application. + </p> + + <p> + Configuring logback from a XML file is an easy task. One just needs to + instanciate a <code>JoranConfigurator</code> and pass the configuration + file, as the following example demonstrate. + </p> + + <em>Example 1.4: Logback configuration from file ((<a + href="xref/chapter2/MyAppWithConfigFile.html">logback-examples/src/main/java/chapter2/MyAppWithConfigFile.java</a>)</em> + +<div class="source"><pre>package chapter2; + +//Import SLF4J classes. +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.core.util.StatusPrinter; + +public class MyAppWithConfigFile { + + public static void main(String[] args) { + Logger logger = LoggerFactory.getLogger(MyAppWithConfigFile.class); + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + + JoranConfigurator configurator = new JoranConfigurator(); + configurator.setContext(lc); + configurator.doConfigure(args[0]); + + logger.info("Entering application."); + Bar bar = new Bar(); + bar.doIt(); + logger.info("Exiting application."); + + StatusPrinter.print(lc.getStatusManager()); + } +}</pre></div> + + + <p>This class defines a logger instance variable. + It then instantiates a <code>Bar</code> + object. The <code>Bar</code> class is listed below: + </p> + + <em>Example 1.3: Sample logging class (<a href="xref/chapter2/Bar.html">logback-examples/src/main/java/chapter2/Bar.java</a>)</em> +<div class="source"><pre>package chapter2; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class Bar { + + Logger logger = LoggerFactory.getLogger(Bar.class); + + public void doIt() { + logger.debug("doing my job"); + } +}</pre></div> + + <p><em>MyAppWithConfigFile</em> configures logback by using the + <code>JoranConfigurator</code>. Joran is a XML interpreter, similar to the + commons-digester API, but offering several advantages over + commons-digester. Here, it parses the xml file and runs actions + depending on the tags it finds. To setup the <code>JoranConfigurator</code> + properly, we passed the <code>LoggerContext</code>. A + <code>LoggerContext</code> is the class that creates and manages + Loggers in logback. It is also the class that implements the + <code>org.slf4j.ILoggerFactory</code> interface. + </p> + <p> + All + other classes only need to retrieve an instance of + <code>org.slf4j.Logger</code> by calling + <code>LoggerFactory.getLogger()</code>, and then log away. For + example, the only dependence of the <code>Bar</code> class is on + <code>org.slf4j.Logger</code> and + <code>org.slf4j.LoggerFactory</code>. Except code that configures + logback (if such code exists) user code does not need to depend on + logback, but on SLF4J instead. + </p> + + <p>Let us configure logback with the + next XML configuration file:</p> + + <em>Example 1.5: Basic configuration with a xml file (logback-examples/src/main/java/chapter2/sample-config-1.xml)</em> +<div class="source"><pre><?xml version="1.0" encoding="UTF-8" ?> + +<configuration> + + <appender name="STDOUT" + class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> + </layout> + </appender> + + <root> + <level value="debug" /> + <appender-ref ref="STDOUT" /> + </root> +</configuration></pre></div> + + <p>We first created an <code>Appender</code>, named <em>STDOUT</em> + that is of <code>ConsoleAppender</code> type. Its layout is managed + by a <code>PatternLayout</code>, that uses the value of the <em>pattern</em> parameter + to generate the logging statement. We then configured the root + logger, set its level to DEBUG, and linked the newly configured + <code>ConsoleAppender</code> 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 example, use this command:</p> + +<div class="source"><pre>java chapter2.MyAppWithConfigFile src/main/java/chapter2/sample-config-1.xml</pre></div> + + <p> + Here is what you should see in the console: + </p> + +<div class="source"><pre>18:15:26.718 [main] INFO chapter2.MyAppWithConfigFile - Entering application. +18:15:26.718 [main] DEBUG chapter2.Bar - doing my job +18:15:26.718 [main] INFO chapter2.MyAppWithConfigFile - Exiting application.</pre></div> + + + <p>Logging to the console is a rather simple example. Let's now + configure logback so that it logs on the console, but also to a + custom file.</p> + +<em>Example 1.6: Configuring logback with multiple appenders (logback-examples/src/main/java/chapter2/sample-config-2.xml)</em> +<div class="source"><pre><?xml version="1.0" encoding="UTF-8" ?> + +<configuration> + + <appender name="STDOUT" + class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern> + </layout> + </appender> + + <appender name="FILE" + class="ch.qos.logback.core.FileAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern> + </layout> + <File>sample-log.txt</File> + </appender> + + <root> + <level value="debug" /> + <appender-ref ref="STDOUT" /> + <appender-ref ref="FILE" /> + </root> +</configuration></pre></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 rather small. The options + are declared as xml element, in either Appender configuration. They are + read and their value are assigned 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 chapter2 package anymore. This is done by adding the following + bold xml snippet to the configuration file, right before the + <code><root></code> element.</p> + +<em>Example 1.7: Configuring a specific logger (logback-examples/src/main/java/chapter2/sample-config-3.xml)</em> +<div class="source"><pre><?xml version="1.0" encoding="UTF-8" ?> + +<configuration> + + <appender name="STDOUT" + class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern> + </layout> + </appender> + + <appender name="FILE" + class="ch.qos.logback.core.FileAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern> + </layout> + <File>sample-log.txt</File> + </appender> +<b> + <logger name="chapter2"> + <level value="info" /> + </logger> +</b> + <root> + <level value="debug" /> + <appender-ref ref="STDOUT" /> + <appender-ref ref="FILE" /> + </root> +</configuration> +</pre></div> + + <p>Once done, the output is modified to show only statements of level INFO and higher:</p> + +<div class="source"><pre>0 [main] INFO chapter2.MyAppWithConfigFile - Entering application. +0 [main] INFO chapter2.MyAppWithConfigFile - Exiting application.</pre></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 chapter2 output + to a log visualizer, 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> + + + <p> + Until now, we always had to specifically load the configuration file and pass it + to a logback component. However, this step is not necessary in most cases. When logback + is not configured by instanciating <code>JoranConfigurator</code> objects, it follows + a simple policy to configure itself. + </p> + + <ul> + <p>Logback first tries to find a file called <em>logback.xml</em> within the classpath.</p> + <p>If no such file is found, it checks for another file called <em>logback-test.xml</em>.</p> + <p>In case none of these files are found, logback configures itself automatically using the + <a href="../xref/ch/qos/logback/classic/BasicConfigurator.html"><code>BasicConfigurator</code> + </a> class.</p> + </ul> + + <p> + The first two checks allow for two environments to cooperate nicely. When the application + using logback is in development and test process, a special file can be used to setup + a logging environment that is developer-friendly. Once in production environment, the + presence of a <em>logback.xml</em> file overrides any <em>logback-test.xml</em> + configuration. + </p> + + <p> + The last step is meant to provide very basic logging functionnality in case no configuration + file is provided. In that case, the logging requests are output to the console. + </p> + + <p> + Letting logback load its configuration file is the most often used way of + configuring. It allows the user to only import SLF4J classes in her code. + </p> + + <p> + The last step of logback's configuration policy permits the use of a minimal + logging configuration right out of the box. Remember the very first example of + this short introduction. The output was generated due to this feature. + </p> + </body> +</document> Modified: logback/trunk/logback-site/src/site/xdocTemplates/manual/index.xml ============================================================================== --- logback/trunk/logback-site/src/site/xdocTemplates/manual/index.xml (original) +++ logback/trunk/logback-site/src/site/xdocTemplates/manual/index.xml Mon Jan 22 16:58:04 2007 @@ -61,6 +61,12 @@ <ul> <li><p> + <a href="introduction.html"><b>Chapter 1: Introduction to logback</b></a> + </p></li> + <li><p> + <a href="joran.html"><b>Chapter 2: Architecture</b></a> + </p></li> + <li><p> <a href="joran.html"><b>Chapter 3: Logback configuration with Joran</b></a> </p></li> Added: logback/trunk/logback-site/src/site/xdocTemplates/manual/introduction.xml ============================================================================== --- (empty file) +++ logback/trunk/logback-site/src/site/xdocTemplates/manual/introduction.xml Mon Jan 22 16:58:04 2007 @@ -0,0 +1,265 @@ +<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>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-sa/2.5/"> + <img alt="Creative Commons License" + style="border-width: 0" + src="http://creativecommons.org/images/public/somerights20.png" /> + </a> + </td> + <td> + <p>Copyright © 2000-2006, QOS.ch</p> + + <p> + <!--Creative Commons License--> + This work is licensed under a + <a rel="license" + href="http://creativecommons.org/licenses/by-nc-sa/2.5/"> + Creative Commons + Attribution-NonCommercial-ShareAlike 2.5 + License + </a> + . + <!--/Creative Commons License--> + </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 log4j founder. + It builds upon a decade long experience gained in + designing industrial-strength logging systems. The resulting + product, logback is faster with a smaller footprint than all + 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. These are only few examples of useful + features logback has to offer. For its own error reporting, + logback relies on <code>Status</code> objects, which greatly + facilitate troubleshooting. You may wish to rely on Status + objects in contexts other than logging. Logback-core bundles + Joran, a powerful and generic configuration system, which can be + put to use in your own projects to great effect. + </p> + + <h2>First Baby Step</h2> + + <div class="highlight"> + <p> + In order to run the examples in this introduction, you need + to make sure that certain jar files are present on the + classpath. + Please refer to the <a href="setup.html">setup page</a> + for further details. + </p> + </div> + + <h3>Requirements</h3> + + <p>Logback-classic module requires the presence + <em>slf4j-api.jar</em>, <em>logback-core.jar</em> in addition to + <em>logback-classic.jar</em> on the classpath. + </p> + + + <p>Let us now begin experimenting with logback.</p> + +<em>Example 1.1: Basic template for logging (<a href="xref/chapter1/HelloWorld1.html">logback-examples/src/main/java/chapter1/HelloWorld1.java</a>)</em> +<div class="source"><pre>package chapter1; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HelloWorld1 { + + public static void main(String[] args) { + + Logger logger = LoggerFactory.getLogger("chapter1.HelloWorld1"); + logger.debug("Hello world."); + + } +}</pre></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 defined in the SLF4J API, more specifically within the <code>org.slf4j</code> + package. + </p> + + + <p> + On the first line of the main() method, 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 the + <code>debug</code> method of this logger passing "Hello World" as an argument. + We say that the main + method contains a logging statement of level debug with 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>You can launch the first + sample application, <em>chapter1.HelloWord1</em> with the command: + </p> + <div class="source"><pre>java chapter1.HelloWorld1</pre></div> + + <p> + Launching the <code>HelloWorld1</code> + application will output a single line on the console. By virtue of + to logback's default configuration policy, when no default file + is found to configure logback explicitely, logback will add a + <code>ConsoleAppender</code> to the root logger. + </p> + +<div class="source"><pre>20:49:07.962 [main] DEBUG chapter1.HelloWorld1 - Hello world.</pre></div> + + <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 instruct logback to print its + internal state. This is accomplished by a static method in + the <code>LoggerStatusPrinter</code> + class. + </p> + +<em>Example 1.2: Printing Logger Status (<a href="xref/chapter1/HelloWorld2.html">logback-examples/src/main/java/chapter1/HelloWorld2.java</a>)</em> +<div class="source"><pre>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("chapter1.HelloWorld2"); + logger.debug("Hello world."); + <b>LoggerStatusPrinter.printStatusInDefaultContext();</b> + } +}</pre></div> + + + <p>Running the <code>HelloWorld2</code> application will produce + the following output:</p> + +<div class="source"><pre>20:49:07.962 [main] DEBUG chapter1.HelloWorld2 - Hello world. +|-INFO in ch.qos.logback.classic.BasicConfigurator@1c1ea29 - Setting up default configuration.</pre></div> + + + <p> + Logback explains that it configured itself using its default + policy, which is a basic <code>ConsoleAppender</code>. + An <code>Appender</code> is a class that can be + seen as an output destination. Appenders exist for many different + destinations including the console, files, Syslog, TCP Socket, JMS and + many more. Users can also easily create their own Appenders as + appropriate for their specific situation. + </p> + + <p> + The previous examples are rather simple. However, actual logging + in a larger application would not be any different. The general + pattern logging statements will not change. Only the configuration + process will be different since you will certainly need a more + specific configuration than what logback provides by default. + As you will see later on in this document, + configuring logback can be done in different flexible and + powerfull ways. Note that, normally, you won't need to invoke + <code>LoggerStatusPrinter</code> + after your log statements. + </p> + + <p> + Here is a list of the three required steps in order to enable + logging in your application. + </p> + + <ol> + + <li>Configure the logback environment. You can do so in several + more or less sophisticated ways. More on this later.</li> + + <li>In every class where you wish to perform logging, retrieve a + <code>Logger</code> instance by invoking the + <code>org.slf4j.LoggerFactory</code> class' + <code>getLogger()</code> method, passing the current class name + or the class itself as parameter.</li> + + <li>Use this logger instance by invoking its printing methods, + namely the debug(), info(), warn() and error(). This will + produce logging output on the configured appenders.</li> + </ol> + + <h2>Building logback</h2> + +<p> +Like many java applications today, logback relies on <a href="http://maven.apache.org"> +Maven 2</a> as its build tool. Maven 2 is a free open source build tool that requires +one or more build files names <em>pom.xml</em> which already ship with logback +distributions. +</p> + +<p> +Building all logback components is mostly done by issuing the <em>mvn compile</em> +line in a terminal or command window. Maven 2 will automatically download the required +external libraries and use them. However, a library cannot be downloaded from +the Maven 2 repository. Libraries such as <code>JMS</code> +from sun require a separate download and to issue a command to install their +jars into your local repository. The required command will be presented +by Maven 2 in your console when trying to compile logback. +</p> + +<p> +Logback distributions contain complete source code such that you can modify parts +of logback library and build your own version of it. You may even +redistribute the modified version, as long as you adhere to the conditions +of the LGPL License. In particular you may not call the modified version <em>logback</em> +or claim that it is endorsed by the QOS.ch. +</p> + + + + + + + + + </body> +</document>
participants (1)
-
noreply.seb@qos.ch