[logback-dev] svn commit: r1304 - in logback/trunk: . logback-site logback-site/src/site logback-site/src/site/resources logback-site/src/site/resources/css logback-site/src/site/resources/images/logos logback-site/src/site/resources/manual logback-site/src/site/resources/templates logback-site/src/site/resources/templates/base logback-site/src/site/xdocTemplates src/site
noreply.seb at qos.ch
noreply.seb at qos.ch
Thu Feb 1 15:44:07 CET 2007
Author: seb
Date: Thu Feb 1 15:44:05 2007
New Revision: 1304
Added:
logback/trunk/logback-site/src/site/resources/access.html
logback/trunk/logback-site/src/site/resources/bridge.html
logback/trunk/logback-site/src/site/resources/bugreport.html
logback/trunk/logback-site/src/site/resources/codes.html
logback/trunk/logback-site/src/site/resources/css/print.css
logback/trunk/logback-site/src/site/resources/css/site.css
logback/trunk/logback-site/src/site/resources/demo.html
logback/trunk/logback-site/src/site/resources/documentation.html
logback/trunk/logback-site/src/site/resources/download.html
logback/trunk/logback-site/src/site/resources/faq.html
logback/trunk/logback-site/src/site/resources/images/logos/
logback/trunk/logback-site/src/site/resources/images/logos/lblogo.jpg (contents, props changed)
logback/trunk/logback-site/src/site/resources/images/logos/qosLogo.png (contents, props changed)
logback/trunk/logback-site/src/site/resources/index.html
logback/trunk/logback-site/src/site/resources/jmxConfig.html
logback/trunk/logback-site/src/site/resources/license.html
logback/trunk/logback-site/src/site/resources/mailinglist.html
logback/trunk/logback-site/src/site/resources/manual/appenders.html
logback/trunk/logback-site/src/site/resources/manual/architecture.html
logback/trunk/logback-site/src/site/resources/manual/contextSelector.html
logback/trunk/logback-site/src/site/resources/manual/filters.html
logback/trunk/logback-site/src/site/resources/manual/index.html
logback/trunk/logback-site/src/site/resources/manual/introduction.html
logback/trunk/logback-site/src/site/resources/manual/joran.html
logback/trunk/logback-site/src/site/resources/manual/layouts.html
logback/trunk/logback-site/src/site/resources/manual/mdc.html
logback/trunk/logback-site/src/site/resources/news.html
logback/trunk/logback-site/src/site/resources/repos.html
logback/trunk/logback-site/src/site/resources/setup.html
logback/trunk/logback-site/src/site/resources/team.html
logback/trunk/logback-site/src/site/resources/templates/
logback/trunk/logback-site/src/site/resources/templates/base/
logback/trunk/logback-site/src/site/resources/templates/base/footer.js
logback/trunk/logback-site/src/site/resources/templates/base/header.js
logback/trunk/logback-site/src/site/resources/templates/base/left.js
logback/trunk/logback-site/src/site/resources/templates/base/right.js
logback/trunk/logback-site/src/site/resources/templates/footer.js
logback/trunk/logback-site/src/site/resources/templates/header.js
logback/trunk/logback-site/src/site/resources/templates/left.js
logback/trunk/logback-site/src/site/resources/templates/right.js
Removed:
logback/trunk/logback-site/src/site/xdocTemplates/
Modified:
logback/trunk/logback-site/pom.xml
logback/trunk/logback-site/src/site/site.xml
logback/trunk/pom.xml
logback/trunk/src/site/site.xml
Log:
Changed the site organisation.
We now use html pages and not the xdoc anymore.
Modified: logback/trunk/logback-site/pom.xml
==============================================================================
--- logback/trunk/logback-site/pom.xml (original)
+++ logback/trunk/logback-site/pom.xml Thu Feb 1 15:44:05 2007
@@ -25,12 +25,12 @@
<build>
<resources>
<resource>
- <directory>src/site/xdocTemplates</directory>
+ <directory>src/site/resources</directory>
<!--
We're saving filtered xdocs in a temporary folder
and telling the site plug in to get the xdocs there.
-->
- <targetPath>generated-site</targetPath>
+ <targetPath>generated-site</targetPath>
<filtering>true</filtering>
</resource>
</resources>
Added: logback/trunk/logback-site/src/site/resources/access.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/access.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,443 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Logback Access</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+ <h2>Access log with logback, Jetty and Tomcat</h2>
+ <div class="author">
+ Authors: Ceki Gülcü, Sébastien Pennec
+ </div>
+
+
+ <table class="bodyTable">
+ <tr class="a">
+ <td>
+ <a 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"></img>
+ </a>
+ </td>
+ <td>
+ <p>Copyright © 2000-2006, QOS.ch</p>
+
+ <p>
+
+ This work is licensed under a
+ <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
+ Creative Commons
+ Attribution-NonCommercial-ShareAlike 2.5
+ License
+ </a>
+ .
+
+ </p>
+ </td>
+ </tr>
+ </table>
+
+
+ <h2>Introduction</h2>
+
+ <p>
+ Logback was designed as a modular framework from the start. Being
+ able to use logback's internal core in many situations, without
+ heavy coding or complex specific configuration was one of our
+ goals.
+ </p>
+
+ <p>
+ Lobgack access integrates with Servlet containers such as Jetty
+ and Tomcat to provide HTTP-access log functionality.
+ </p>
+
+ <h2>Logback Access and Tomcat</h2>
+
+ <p>
+ To use logback-access with Tomcat, after downlading the logback
+ distribution, place the files <em>logback-core-VERSION.jar</em>
+ and <em>logback-access-VERSION.jar</em> under $TOMCAT_HOME/server/lib
+ directory, where $TOMCAT_HOME is the folder where you have
+ installed Tomcat. We have tested logback-access module with Tomcat
+ version 5.5.20.
+ </p>
+
+ <h3>LogbackValve</h3>
+
+ <p>
+ The <a href="xref/ch/qos/logback/access/tomcat/LogbackValve.html">
+ <code>ch.qos.logback.access.tomcat.LogbackValve</code></a>
+ class extends Tomcat's <code><a href="http://tomcat.apache.org/tomcat-5.5-doc/catalina/docs/api/org/apache/catalina/valves/ValveBase.html">
+ ValveBase</a></code>
+ class. This class is used to allow external
+ components to be integrated into Tomcat.
+ </p>
+
+ <p>
+ To configure Tomcat in order to use
+ <code>LogbackValve</code>, add the following lines
+ to the tomcat server configuration file, namely <em>$TOMCAT_HOME/conf/server.xml</em>:
+ </p>
+ <div class="source"><pre><Valve className="ch.qos.logback.access.tomcat.LogbackValve"/></pre></div>
+ <p>
+ This line need to be nested in an <em>Engine</em> element.
+ </p>
+ <p>
+ By default, <code>LogbackValve</code> looks for a logback
+ configuration file called <em>logback-access.xml</em>, in the
+ same folder where <em>server.xml</em> is located, that is
+ in <em>$TOMCAT_HOME/conf/</em>. This
+ configuration file contains directives for configuring logback
+ components. Among others, you can specify the appenders where
+ the logging requests will be sent, and their format. Please refer
+ to the description below about logback access configuration for examples.
+ </p>
+
+ <h2>Logback Access and Jetty</h2>
+
+ <p>
+ To use logback-access with Jetty, after downlading the logback
+ distribution, place the files <em>logback-core-VERSION.jar</em>
+ and <em>logback-access-VERSION.jar</em> under $JETTY_HOME/lib
+ directory, where $JETTY_HOME is the folder where you have
+ installed Jetty. We have tested logback-access module with Jetty
+ version 6.0.1.
+ </p>
+
+ <h3>Logback's RequestLog implementation</h3>
+
+ <p>
+ The <a href="xref/ch/qos/logback/access/jetty/RequestLogImpl.html">
+ <code>ch.qos.logback.access.jetty.RequestLogImpl</code></a>
+ class implements jetty's <code><a href="http://jetty.mortbay.org/apidocs/org/mortbay/jetty/RequestLog.html">RequestLog</a></code>
+ interface. This interface is used by Jetty to allow external
+ components to manage request logging.
+ </p>
+
+ <p>
+ In logback, logging destinations are called Appenders. These classes
+ can be attached directly to <code>RequestLogImpl</code>.
+ </p>
+
+
+ <p>
+ To configure jetty in order to use logback's
+ <code>RequestLogImpl</code>, add the following lines
+ to the jetty configuration file, namely <em>$JETTY_HOME/etc/jetty.xml</em>:
+ </p>
+ <div class="source"><pre><Ref id="requestLog">
+ <Set name="requestLog">
+ <New id="requestLogImpl"
+ class="ch.qos.logback.access.jetty.RequestLogImpl">
+ </New>
+ </Set>
+</Ref></pre></div>
+ <p>
+ These lines reference the requestLog functionnality of Jetty, setting
+ the actual class that will be called at each logging request.
+ </p>
+ <p>
+ By default, <code>RequestLogImpl</code> looks for a logback
+ configuration file called <em>logback-access.xml</em>, in the
+ same folder where <em>jetty.xml</em> is located. This
+ configuration file contains directives for configuring logback
+ components. Among others, you can specify the appenders where
+ the logging requests will be sent, and their format.
+ </p>
+
+ <p>As long the path is specified, you can place the logback
+ configuration file in any location. Here is another example of
+ jetty configuration file, with a path to the logback access
+ configuration file.
+ </p>
+ <div class="source"><pre><Ref id="requestLog">
+ <Set name="requestLog">
+ <New id="requestLogImpl"
+ class="ch.qos.logback.access.jetty.RequestLogImpl">
+ </New>
+ <Set name="fileName">path/to/myaccess.xml</Set>
+ </Set>
+</Ref></pre></div>
+
+ <h2>Logback Access Configuration</h2>
+
+ <p>Altough similar, the <em>logback-access.xml</em> file is slightly
+ different than the usual logback classic configuration file.
+ Appenders and Layouts are declared the exact same way. However, in
+ the access module there is no notion of loggers and consequently
+ loggers elements are disallowed in configuraiton files for
+ logback-access.
+ </p>
+
+ <h3>Example 1: basic logback-access configuration</h3>
+ <p>
+ Here is a sample <em>logback-access.xml</em> file that you can
+ immediately put to use:
+ </p>
+<div class="source"><pre><configuration>
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout
+ class="ch.qos.logback.access.PatternLayout">
+ <Pattern>%h %l %u %user %date "%r" %s %b</Pattern>
+ </layout>
+ </appender>
+
+ <appender-ref ref="STDOUT" />
+</configuration></pre></div>
+ <p>
+ It declares a <code>ConsoleAppender</code> which directs its
+ output at the console. The <code>ConsoleAppender</code> contains
+ a <code>PatternLayout</code> format the output. The log format is
+ specied using the %h %l %u %user %date "%r" %s %b" pattern which
+ is the Commong Log Format (CLF). This format is recognized by log
+ analysers such as <a href="http://www.analog.cx/">Analog</a> or <a href="http://awstats.sourceforge.net/">AWStats</a>.
+ </p>
+
+ <p>Instead of specifying the complete pattern, the word "common"
+ or "clf" can be used as a shorthand. Thus, the following are all
+ equivalent
+ </p>
+
+ <div class="source"><pre><Pattern>%h %l %u %user %date "%r" %s %b</Pattern>
+<Pattern>common</Pattern>
+<Pattern>clf</Pattern></pre></div>
+
+ <p>The so called "combined" format is also widely recognized. It is
+ defined as the '%h %l %u %t "%r" %s %b "%i{Referer}"
+ "%i{User-Agent}"' pattern. As a facilitator, you can use the
+ "combined" as a shorthand. Thus, the following directive
+ </p>
+
+ <div class="source"><pre><layout class="ch.qos.logback.access.PatternLayout">
+ <Pattern>%h %l %u %t "%r" %s %b "%i{Referer}" "%i{User-Agent}"</Pattern>
+</layout></pre></div>
+
+ <p>is equivalent to:</p>
+
+ <div class="source"><pre><layout class="ch.qos.logback.access.PatternLayout">
+ <Pattern>combined</Pattern>
+</layout></pre></div>
+
+
+ <h3>Example 2: RollingFileAppender</h3>
+
+ <p>Another configuration file, using logback'
+ <code>RollingFileAppender</code>, could be:</p>
+<div class="source"><pre><configuration>
+ <appender name="FILE"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <File>access.log"</File>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>access.%d{yyyy-MM-dd}.log.zip</FileNamePattern>
+ </rollingPolicy>
+
+ <layout class="ch.qos.logback.access.PatternLayout">
+ <Pattern">combined</Pattern">
+ </layout>
+ </appender>
+
+ <appender-ref ref="FILE" />
+</configuration></pre></div>
+
+ <p>
+ Here, there is no output to the console. Instead, logback access
+ logs to the file named access.log. This file will be rolled over
+ every 24 hours. We specify in the configuration the name of the file
+ where the actual logging is added, and the pattern that the archived
+ files must match.
+ The newly archived file will be automatically compressed.
+ </p>
+
+ <p>
+ These two configuration examples should give you an idea of the
+ possibilities offered by the logback-access module. In
+ principle, most of the things that you can do with
+ logback-classic module are equally possible with logback-access.
+ </p>
+
+ <h3>PatternLayout</h3>
+
+ <p>
+ An http-specific implementation of <code>PatternLayout</code> is
+ included in the access module. The <a href="xref/ch/qos/logback/access/PatternLayout.html">
+ <code>ch.qos.logback.access.PatternLayout</code></a> provides a
+ way to format the logging output that is just as easy and
+ flexible as the <code>PatternLayout</code> found in logback
+ classic.
+ </p>
+
+ <p>
+ For detailled instructions on how to use the <code>PatternLayout</code> for
+ logback access, please refer to the
+ <a href="manual/layouts.html#AccessPatternLayout">corresponding chapter</a>
+ of the logback manual.
+ </p>
+
+ <h2>JMX Components</h2>
+
+ <p>Logback access easily integrates with JMX servers to publish useful information
+ about some of its components.
+ </p>
+
+ <p>
+ Both <code>RequestLogImpl</code> and <code>LogbackValve</code> can be
+ published and modified via JMX. A special filter, that we will cover
+ further down this document, publishes statistical views of access logs.
+ </p>
+
+
+ <h3>Configuring Tomcat</h3>
+
+ <p>
+ Accessing JMX components with Tomcat requires to add the following lines
+ to the <em>$TOMCAT_HOME/bin/catalina.sh</em> configuration file:
+ </p>
+
+<div class="source"><pre>CATALINA_OPTS="-Dcom.sun.management.jmxremote"
+CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
+CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"</pre></div>
+
+ <p>
+ Once started with these options, Tomcat's JMX compoenents can be accessed
+ with JConsole by issuing the following command in a shell:
+ </p>
+<div class="source"><pre>jconsole &</pre></div>
+
+ <p>
+ The user might prefer to access her components via a web-based solution using MX4J.
+ In that case, here are the required steps:
+ </p>
+
+ <p>
+ First, <a href="http://mx4j.sourceforge.net/">download MX4J</a>.
+ Place the <em>mx4j-impl.jar</em> file in
+ the <em>$TOMCAT_HOME/bin/</em> directory, and the <em>mx4j-tools.jar</em>
+ in the <em>$TOMCAT_HOME/common/lib/</em> directory.
+ </p>
+
+ <p>Then, add the following lines to the
+ <em>$TOMCAT_HOME/bin/catalina.sh</em> configuration file:
+ </p>
+
+<div class="source"><pre><!-- at the beginning of the file -->
+CATALINA_OPTS="-Dcom.sun.management.jmxremote"
+CATALINA_OPTS="$CATALINA_OPTS -Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder"
+
+<!-- in the "Add on extra jar files to CLASSPATH" section -->
+CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/mx4j-impl.jar</pre></div>
+
+ <p>
+ Finally, declare a new <code>Connector</code> in the
+ <em>$TOMCAT_HOME/conf/server.xml</em> file:
+ </p>
+
+<div class="source"><pre><Connector port="8050"
+ handler.list="mx"
+ mx.enabled="true"
+ mx.httpHost="localhost"
+ mx.httpPort="8082"
+ protocol="AJP/1.3" /></pre></div>
+
+ <p>
+ Once Tomcat is started, you should be ableo to reach the JMX components by
+ pointing a browser to the following URL:
+ </p>
+
+<div class="source"><pre>http://host_name:8082/</pre></div>
+
+ <h3>Configuring Jetty</h3>
+
+ <p>
+ Configuring Jetty to publish JMX components requires a few modifications to the
+ <em>$JETTY_HOME/etc/jetty.xml</em> configuration file. Here are the elements that need to be
+ added:
+ </p>
+
+<div class="source"><pre><Call id="MBeanServer" class="java.lang.management.ManagementFactory" name="getPlatformMBeanServer"/>
+<!-- initialize the Jetty MBean container -->
+<Get id="Container" name="container">
+ <Call name="addEventListener">
+ <Arg>
+ <New class="org.mortbay.management.MBeanContainer">
+ <Arg><Ref id="MBeanServer"/></Arg>
+ <Set name="managementPort">8082</Set>
+ <Call name="start" />
+ </New>
+ </Arg>
+ </Call>
+</Get></pre></div>
+
+ <p>
+ Once Jetty is started with this configuration, all available components can be reviewed
+ at this address:
+ </p>
+<div class="source"><pre>http://host_name:8082/</pre></div>
+
+ <p>
+ Logback's <code>RequestLogImpl</code> is available, and its <code>start()</code>
+ and <code>stop()</code> method can be called.
+ </p>
+
+
+ <h3>CountingFilter</h3>
+
+ <p>
+ Logback can provide a statistical view of the accesses to the server. This is done by using the
+ <a href="xref/ch/qos/logback/access/filter/CountingFilter.html"><code>CountingFilter</code></a> class.
+ </p>
+
+ <p>
+ To use the <code>CountingFilter</code>, one just needs to declare it, like any
+ other filter:
+ </p>
+
+<div class="source"><pre><configuration>
+ <b><filter class="ch.qos.logback.access.filter.CountingFilter">
+ <name>countingFilter</name>
+ </filter></b>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.access.PatternLayout">
+ <Pattern>%h %l %u %t \"%r\" %s %b</Pattern>
+ </layout>
+ </appender>
+
+ <appender-ref ref="STDOUT" />
+</configuration></pre></div>
+
+ <p>
+ This component registers itself to the JMX server and publishes
+ the following statistical figures:
+ </p>
+
+ <ul>
+ <p>Minute average</p>
+ <p>Last minute's count</p>
+ <p>Hourly average</p>
+ <p>Last hour's count</p>
+ <p>Daily average</p>
+ <p>Last day's count</p>
+ <p>Weekly average</p>
+ <p>Last week's count</p>
+ <p>Monthly average</p>
+ <p>Last month's count</p>
+ <p>Total accesses</p>
+ </ul>
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/bridge.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/bridge.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,94 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Log4j Bridge</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+ <h2>Log4j bridge</h2>
+
+ <p>As of version 0.7, logback ships with a new module called
+ <em>log4j-bridge</em>. It allows log4j users to use logback
+ without changing a single line of code in their application. All
+ that is needed to do is to replace the log4j.jar file with the
+ appropriate logback jars.
+ </p>
+
+ <h3>How does it work?</h3>
+
+ <p>The log4j-bridge module contains replacements of most widely
+ used log4j classes, namely <code>Category</code>,
+ <code>Level</code>, <code>Logger</code>, <code>MDC</code>,
+ <code>Priority</code>, <code>BasicConfigurator</code>
+ and <code>Log4jLoggerFactory</code>. These
+ replacement classes redirect loggging calls to the corresponding
+ logback methods.
+ </p>
+
+ <p>
+ To use log4j-bridge in your own application, the first step is
+ to locate and remove the <em>log4j.jar</em> file and replace it
+ with <em>log4j-bridge.jar</em> which ships with logback. Note
+ that you still need logback-classic and its dependencies for the
+ log4j-bridge to work properly. In summary, here is a list of the
+ required jars:
+ </p>
+
+ <ul>
+ <li>
+ log4j-bridge-<em>VERSION</em>.jar
+ </li>
+ <li>
+ logback-classic-<em>VERSION</em>.jar
+ </li>
+ <li>
+ logback-core-<em>VERSION</em>.jar
+ </li>
+ <li>
+ slf4j-api-<em>VERSION</em>.jar
+ </li>
+ </ul>
+
+
+ This is what it takes to make logback your logging implementation when using log4j.
+ It will use logback's automatic basic configuration, displaying the logging requests
+ in the console. More advanced use will require a configuration file and other jars
+ which are logback dependencies. A file called <em>logback.xml</em>,
+ placed in the application's classpath, will be automatically loaded by logback.
+
+
+ <h3>When does it not work?</h3>
+
+
+ The <em>log4-bridge</em> module does not work when the application calls
+ log4j components that are not present in the bridge.
+ For examples, direct creation of log4j <code>Appenders</code> or
+ <code>Filters</code> will not work.
+
+
+
+ However, in most situations, log4j finds its configuration file and
+ configures itself. In these cases, the application will only issue calls
+ to the classes that are contained in the <em>log4j-bridge</em>.
+
+
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/bugreport.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/bugreport.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,83 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Bug report</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+
+
+ <h2>Before you report a bug</h2>
+
+<p>
+The logback community consists of those who use logback and its modules,
+help answer questions on discussions lists, contribute documentation and patches,
+and those who develop and maintain the code for logback and its modules.
+Almost all those who assist on a day to day basis resolving bug reports do this for
+a wide variety of reasons, and almost all of them do this on their own time.
+</p>
+<p>
+Many bugs reported end up not being a bug in logback, but are due to misconfiguration,
+problems caused by installed applications, the operating system, etc.
+</p>
+<p>
+Before reporting a bug please make every effort to resolve the problem yourself.
+Just reporting a bug will not fix it. A good bug report includes a detailed description
+of the problem and a succinct test case which can reproduce the problem.
+</p>
+
+<h3>Review the documentation</h3>
+<p>
+Review the documentation for the version of component you are using.
+The problem you are having may already be addressed in the docs.
+</p>
+
+<h3>Search the mailing list archives</h3>
+<p>
+It is very likely you are not the first to run into a problem.
+Others may have already found a solution.
+Our various mailing lists are likely to have discussed this problem before.
+</p>
+
+<h3>Search Bugzilla</h3>
+
+<p>
+Please search the bug database to see if the bug you are seeing has already been reported.
+The bug may have already been fixed and is available in a later version.
+If someone else has reported the same bug, you could add supporting information to help reproduce and resolve the bug.
+</p>
+<ul>
+ <li><a href="http://bugzilla.qos.ch/query.cgi">Search for logback bugs</a></li>
+</ul>
+
+<h2>Reporting with Bugzilla</h2>
+
+Only after you have exhausted the aforementioned steps, should you file a formal report in bugzilla.
+
+<p>
+Please make sure you provide as much information as possible.
+Its very hard to fix a bug if the person looking into the problem can't reproduce it.
+</p>
+<ul>
+ <li><a href="http://bugzilla.qos.ch/enter_bug.cgi">Report new logback bug</a></li>
+</ul>
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/codes.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/codes.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,269 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Logback FAQ</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+ <h2><a name="top">Logback error messages and their meanings</a></h2><p><b>Generalities</b></p><ol type="1"><li><a href="#tbr_fnp_not_set">
+ The
+ <b>FileNamePattern</b>
+ option must be set before using
+ <code>TimeBasedRollingPolicy</code>
+ or
+ <code>FixedWindowRollingPolicy</code>
+ .
+ </a></li><li><a href="#fwrp_parentFileName_not_set">
+ <p>The File name option must be set before <code>FixedWindowRollingPolicy</code>.</p>
+ </a></li><li><a href="#socket_no_host">
+ No remote host or address is set for
+ <code>SocketAppender</code>
+ .
+ </a></li><li><a href="#socket_no_port">
+ No remote port is set for
+ <code>SocketAppender</code>
+ .
+ </a></li><li><a href="#smtp_no_layout">
+ No
+ <code>Layout</code>
+ is set for appender
+ </a></li><li><a href="#sbtp_size_format">
+ Specified number is not in proper int form, or
+ not expected format.
+ </a></li><li><a href="#rfa_no_tp">
+ No <code>TriggeringPolicy</code> was set for the
+ <code>RollingFileAppender</code>.
+ </a></li><li><a href="#rfa_no_rp">
+ No <code>RollingPolicy</code> was set for the
+ <code>RollingFileAppender</code>.
+ </a></li></ol>
+
+
+
+ <div class="section"><h2>Generalities</h2><dl><dt><a name="tbr_fnp_not_set">
+ The
+ <b>FileNamePattern</b>
+ option must be set before using
+ <code>TimeBasedRollingPolicy</code>
+ or
+ <code>FixedWindowRollingPolicy</code>
+ .
+ </a></dt><dd>
+ <p>
+ The
+ <b>FileNamePattern</b>
+ option for both
+ <code>TimeBasedRollingPolicy</code>
+ and
+ <code>FixedWindowRollingPolicy</code>
+ is mandatory.
+ </p>
+ <p>
+ See the
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/FixedWindowRollingPolicy.html">
+ FixedWindowRollingPolicy javadoc
+ </a>
+ for more information.
+ </p>
+ <table border="0"><tr><td align="right"><a href="#top">[top]</a></td></tr></table><hr /></dd><dt><a name="fwrp_parentFileName_not_set">
+ <p>The File name option must be set before <code>FixedWindowRollingPolicy</code>.</p>
+ </a></dt><dd>
+ <p>
+ The <span class="option">File</span> option is mandatory with <code>FixedWindowRollingPolicy</code>. Moreover, the File option must be
+ set before the declaration configuring <code>FixedWindowRollingPolicy</code>.
+ </p>
+ <p>
+ See the logback manual's chapter about
+ <a href="http://logback.qos.ch/manual/appenders.html#FixedWindowRollingPolicy">
+ FixedWindowRollingPolicy
+ </a>
+ for more information.
+ </p>
+ <table border="0"><tr><td align="right"><a href="#top">[top]</a></td></tr></table><hr /></dd><dt><a name="socket_no_host">
+ No remote host or address is set for
+ <code>SocketAppender</code>
+ .
+ </a></dt><dd>
+ <p>
+ A remote host or address is mandatory for
+ SocketAppender.
+ </p>
+ <p>
+ You can specify the remote host in the
+ configuration file like this:
+ </p>
+ <div class="source"><pre>
+<appender name="SOCKET" class="ch.qos.logback.classic.net.SocketAppender">
+ ...
+ <param name="remoteHost" value="127.0.0.1"></param>
+ ...
+</appender>
+ </pre></div>
+ <table border="0"><tr><td align="right"><a href="#top">[top]</a></td></tr></table><hr /></dd><dt><a name="socket_no_port">
+ No remote port is set for
+ <code>SocketAppender</code>
+ .
+ </a></dt><dd>
+ <p>
+ A remote port is mandatory for
+ SocketAppender.
+ </p>
+ <p>
+ You can specify the remote port in the
+ configuration file like this:
+ </p>
+ <div class="source"><pre>
+<appender name="SOCKET" class="ch.qos.logback.classic.net.SocketAppender">
+ ...
+ <param name="port" value="4560"></param>
+ ...
+</appender>
+ </pre></div>
+ <table border="0"><tr><td align="right"><a href="#top">[top]</a></td></tr></table><hr /></dd><dt><a name="smtp_no_layout">
+ No
+ <code>Layout</code>
+ is set for appender
+ </a></dt><dd>
+ <p>
+ A
+ <code>Layout</code>
+ is mandatory for
+ <code>SMTPAppender</code>
+ . It allows the appender format the logging
+ events before sending the email. Two layouts
+ are often used with
+ <code>SMTPAppender</code>
+ :
+ <code>PatternLayout</code>
+ and
+ <code>HTMLLayout</code>
+ .
+ </p>
+ <p>
+ You can specify the
+ <code>Layout</code>
+ in the configuration file like this:
+ </p>
+ <div class="source"><pre>
+<appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
+ ...
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <param name="pattern" value="%-4relative [%thread] %-5level %class - %msg%n"></param>
+ </layout>
+ ...
+</appender>
+ </pre></div>
+ <p>
+ You can see more examples in the
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/classic/html/HTMLLayout.html">
+ HTMLLayout javadoc
+ </a>
+ and the
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/classic/PatternLayout.html">
+ PatternLayout javadoc
+ </a>
+ .
+ </p>
+ <table border="0"><tr><td align="right"><a href="#top">[top]</a></td></tr></table><hr /></dd><dt><a name="sbtp_size_format">
+ Specified number is not in proper int form, or
+ not expected format.
+ </a></dt><dd>
+ <p>
+ When you specify the MaxFileSize to be used
+ by the SizeBasedRollingPolicy, logback
+ expects a rather precise format:
+ </p>
+ <ul>
+ <li>The number has to be an integer</li>
+ <li>
+ You can add 'KB', 'MB' or 'GB' after the
+ number.
+ </li>
+ </ul>
+ <p>
+ Here are some correct values: 500KB, 15MB,
+ 2GB.
+ </p>
+ <table border="0"><tr><td align="right"><a href="#top">[top]</a></td></tr></table><hr /></dd><dt><a name="rfa_no_tp">
+ No <code>TriggeringPolicy</code> was set for the
+ <code>RollingFileAppender</code>.
+ </a></dt><dd>
+ <p>
+ The <code>RollingFileAppender</code> must be set up with
+ a <code>TriggeringPolicy</code>. It permits the Appender
+ to know when the rollover must be activated.
+ </p>
+ <p>
+ To find more information about
+ <code>TriggeringPolicy</code> objects, please read the
+ following javadocs:
+ </p>
+ <ul>
+ <li>
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/SizeBasedTriggeringPolicy.html">
+ <code>SizeBasedTriggeringPolicy</code>
+ </a>
+ </li>
+ <li>
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/TimeBasedRollingPolicy.html">
+ <code>TimeBasedRollingPolicy</code>
+ </a>
+ </li>
+ </ul>
+ <p>
+ Please note that the <code>TimeBasedRollingPolicy</code>
+ is a TriggeringPolicy
+ <em>and</em>
+ and <code>RollingPolicy</code> at the same time.
+ </p>
+ <table border="0"><tr><td align="right"><a href="#top">[top]</a></td></tr></table><hr /></dd><dt><a name="rfa_no_rp">
+ No <code>RollingPolicy</code> was set for the
+ <code>RollingFileAppender</code>.
+ </a></dt><dd>
+ <p>
+ The <code>RollingFileAppender</code> must be set up with
+ a <code>RollingPolicy</code>. It permits the Appender
+ to know what to do when a rollover is requested.
+ </p>
+ <p>
+ To find more information about
+ <code>RollingPolicy</code> objects, please read the
+ following javadocs:
+ </p>
+ <ul>
+ <li>
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/FixedWindowRollingPolicy.html">
+ <code>FixedWindowRollingPolicy</code>
+ </a>
+ </li>
+ <li>
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/TimeBasedRollingPolicy.html">
+ <code>TimeBasedRollingPolicy</code>
+ </a>
+ </li>
+ </ul>
+ <p>
+ Please note that the <code>TimeBasedRollingPolicy</code>
+ is a <code>TriggeringPolicy</code>
+ <em>and</em>
+ and RollingPolicy at the same time.
+ </p>
+ <table border="0"><tr><td align="right"><a href="#top">[top]</a></td></tr></table></dd></dl></div>
+ </div>
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/css/print.css
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/css/print.css Thu Feb 1 15:44:05 2007
@@ -0,0 +1,38 @@
+/*
+ * Print css.
+ *
+*/
+body {
+ margin: 0px;
+ padding: 0px 0px 2px 0px;
+ line-height: 1.3em;
+ font-size: 12px;
+}
+
+#leftColumn {
+ width: 0px;
+ height: 0px;
+ visibility:hidden;
+}
+
+#bodyColumn {
+ margin-right: 1.5em;
+ margin-left: 0px; /*was: 197*/
+}
+
+pre {
+ white-space: pre-wrap; /* css-3 */
+ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+table.bodyTable td {
+ vertical-align: text-top;
+}
+
+table.bodyTable th {
+ vertical-align: text-top;
+ text-align:center;
+}
\ No newline at end of file
Added: logback/trunk/logback-site/src/site/resources/css/site.css
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/css/site.css Thu Feb 1 15:44:05 2007
@@ -0,0 +1,261 @@
+html {
+ padding:0px;
+ margin:0px;
+}
+
+body {
+ background-color: #fff;
+ font-family: Verdana, Arial, SunSans-Regular, Sans-Serif;
+ color:#564b47;
+ padding:0px;
+ margin:0px;
+ font-size: small;
+}
+
+p, h2, pre {
+ margin: 0px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ /*padding-left: 1ex;*/
+ /*padding: 5px 20px 5px 20px; */
+}
+
+
+a {
+ color: navy;
+ /*font-size: smaller;*/
+ background-color:transparent;
+ text-decoration: none;
+}
+
+#content a:hover {
+ text-decoration: underline;
+}
+
+.source {
+ border-top: 1px solid #DDDDDD;
+ border-bottom: 1px solid #DDDDDD;
+ background:#eee;
+ font-family: Courier, "MS Courier New", Prestige, Everson Monocourrier, monospace;
+ padding-bottom: 0.5ex;
+ padding-top: 0.5ex;
+ padding-left: 1ex;
+ /*white-space: pre;*/
+}
+
+pre {
+ color: #564b47;
+ background-color:transparent;
+ font-family: Courier, Monaco, Monospace;
+}
+
+.alignright {
+ margin-top: 0;
+ text-align: right;
+ font-size: 10px;
+}
+
+h1 {
+}
+
+h2 {
+ padding-top:10px;
+ color: #564b47;
+ background-color: transparent;
+ font-weight: 900;
+ font-size: x-large;
+}
+
+h3 {
+ padding-top:10px;
+ color: #564b47;
+ background-color: transparent;
+ font-weight: normal;
+ font-size: large;
+}
+
+h4 {
+ padding-top:5px;
+ color: navy;
+ background-color: transparent;
+ font-weight: large;
+ font-size: normal;
+}
+
+.footer {
+ text-align: right;
+ color: #564b47;
+ background-color: #90897a;
+ padding:0px;
+ margin:0px
+}
+
+
+
+strong {
+ /*font-size: 13px;*/
+ font-weight: bold;
+}
+
+/* positioning-layers static and absolute */
+
+#breadcrumbs {
+ padding: 3px 10px 3px 10px;
+ margin: 0px 4px 0px 4px;
+ font-size: small;
+ border: 1px solid #CCCCCC;
+ /*border-bottom: 1px solid #aaa;
+ /* background-color: #ccc; lime;
+ border-color: #663300;*/
+ background-color: #ffd0a0;
+ /*max-width: 77em;*/
+}
+
+#left {
+ position: absolute;
+ left: 0px;
+ width: 15em;
+ color: #564b47;
+ margin: 4px 0px 0px 4px;
+ padding: 0px;
+ /* background-color: #ffffff; */
+ border: 1px solid #cccccc;
+ /* background-color: #ffcc99; */
+ background-color: #ffffff;
+}
+
+#left a, #right a {
+ display: block;
+ width: 95.5%;
+ margin: 0px;
+ padding: 2px;
+ border: solid 1px #FFFFFF;
+ color: #0066cc;
+ text-decoration: none;
+}
+
+p.menu_header {
+ margin: 0px;
+ padding: 2px;
+ font-weight: normal;
+ background-color: #ffd0a0;
+ border-top: solid 1px #CCCCCC;
+ border-bottom: solid 1px #CCCCCC;
+}
+
+#left a:hover, #right a:hover {
+ border: solid 1px #FFFFFF;
+ background-color: #0066cc;
+ color: #ffffff;
+}
+
+#content {
+ margin: 0px 15em 0px 16em;
+ padding: 0px;
+ background-color: #ffffff;
+}
+
+#right {
+ position: absolute;
+ right: 0px;
+ width: 14em;
+ color: #564b47;
+ margin: 4px 4px 0px 0px;
+ padding: 0px;
+ background-color: #ffffff;
+ border: 1px solid #cccccc;
+}
+
+#left img {
+ display: block;
+ margin: 20px 0 20px 17px;
+ border: none;
+ width: 90px;
+ height: 30px;
+}
+
+#content img {
+ border:none;
+ margin-left: auto;
+ margin-right: auto;
+ display: block;
+}
+
+table.bodyTable {
+ padding: 0px;
+ width: 100%;
+ margin-left: -2px;
+ margin-right: -2px;
+}
+
+table.bodyTable th {
+ color: white;
+ background-color: #bbb;
+ font-weight: bold;
+}
+
+
+table.bodyTable tr.a {
+ background-color: #ddd;
+}
+
+table.bodyTable tr.b {
+ background-color: #eee;
+}
+
+.author {
+ text-align: left;
+ font-weight: bold;
+}
+
+.definition {
+ padding-left: 5px;
+ padding-right: 5px;
+ margin: 5px 50px 5px 50px;
+ text-align: justify;
+ background-color: #E6E64C;
+}
+
+.deftitle {
+ font-weight: bold;
+}
+
+.green {
+ color: green;
+}
+.blue {
+ color: blue;
+}
+
+.redBold {
+ color: red;
+ font-weight: bold;
+}
+.greenBold {
+ color: green;
+ font-weight: bold;
+}
+
+code {
+ font-family: Courier, monospace;
+}
+
+
+.option {
+ border: 1px solid black;
+ font-family: Arial, sans-serif;
+}
+
+.highlight {
+ width: 300px;
+ float: right;
+ display: inline;
+ font-weight: bolder;
+ border:1px solid #000;
+ background:#FFCC99;
+ padding-top: 0px;
+ padding-left: 1ex;
+ padding-right: 1ex;
+ margin-left: 3em;
+ margin-right: 3em;
+}
Added: logback/trunk/logback-site/src/site/resources/demo.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/demo.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,521 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Logback Demo</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+ <h2>Logback Demo</h2>
+
+<p>
+ Welcome to the logback demo! This document will take you to a tour
+ that will show you some of the major possibilities of logback.
+</p>
+
+<h3>Installation</h3>
+
+<p>
+ First, please download the logback demo. You will need to install a
+ <a href="http://subversion.tigris.org/">Subversion</a> client
+ and issue the following line in a command/terminal window:
+</p>
+
+<div class="source"><pre>svn co http://svn.qos.ch/repos/logback-demo/trunk logback-demo</pre></div>
+
+<p>
+This will checkout a copy of the logback demonstration web-app to a directory called
+<em>logback-demo</em>. The logback demo can be packaged as a <em>war</em> file and
+deployed to an application server. We strongly recommand the use of
+<a href="http://maven.apache.org/">Maven 2</a> to do this
+task, since all it will take to compile, package and run a server with the demo is
+a single command.
+</p>
+
+<p>
+ Using Maven, let's package the files and run the demo for the first time.
+ From the <em>logback-demo</em> directory, issue the following command:
+</p>
+
+<div class="source"><pre>mvn package jetty:run</pre></div>
+
+<p>
+ Then, visit <em>http://localhost:8080/logback-demo/</em> to view the main page of the logback demo.
+</p>
+
+<h3>Logback Classic</h3>
+
+<p>
+For now, logback uses two components: one <code>ConsoleAppender</code> and one
+<code>RollingFileAppender</code>. The <code>RollingFileAppender</code> sends logging events
+to a file called <em>logFile.log</em> and will rollover
+the active file every minute. The old file will be renamed and compressed to <em>zip</em>
+file. The <code>ConsoleAppender</code> will output the logging requests to the console,
+and shorten the logger names to gain some space in the console window, without making the
+names unreadable. For example, <code>ch.qos.logback.demo.prime.NumberCruncherImpl
+</code> will be displayed as <code>c.q.l.d.prime.NumberCruncherImpl</code>.
+</p>
+
+<p>You can study the configuration file that is used by editing the
+file called <em>logback.xml</em>, located in the <em>src/main/resources/</em> directory
+of the demo. You might want to keep this file in an editor window, since we will
+modify its content several times thoughout the demo.
+</p>
+
+<p>
+Let's now visit the <em>ViewStatii</em> page, via the navigation menu on the left hand
+of the navigator window. This page contains the content of the <code>Status</code> objects that were
+created until now. <code>Status</code> objects are a part of logback's powerful internal
+reporting framework. They allow you to see what is going on in logback, and check
+that a configuration file has been parsed correctly, or that a rollover has occured as
+expected.
+</p>
+
+<p>
+After you're back to the main window, visiting the <em>View logs</em> page does
+not impress much at the moment. Let us uncomment
+the <strong>two</strong> parts of the config file that are below the <em>Cyclic buffer</em> comment.
+A <code>CyclicBuffer</code> is a class that keeps track of logging events and holds these
+objects for immediate or differed display. The first element that you will need to uncomment
+is the <em>appender</em> element. This element describes and configures the <code>CyclicBuffer</code>.
+The second element, found at the end of the configuration file, is a <em>appender-ref</em> element.
+It is used to link the appender to a given logger.
+Now reload the web-app by exiting the previous command with <em>CTRL-C</em> and issuing it
+again: <em>mvn package jetty:run</em>.
+</p>
+
+<p>
+Now, the <em>View logs</em> page looks prettier. By virtue of the <code>CyclicBufferAppender</code>,
+this page can fetch the last events and present them through a servlet. We see that each 3 seconds
+a line is added to the logs. The formatting of this page is made with
+a <code>HTMLLayout</code>. This component creates a nice and readable table containing the logging
+events, based on a pattern that describes the information one wants to see in the table.
+</p>
+
+<p>
+Having the logs that we see on the web page cluttered with scheduled
+<em>Howdydy-diddly-ho</em> messages
+is not very comfortable. To get rid of these logs, now that we've verified that they
+work, we can add an <code>EvaluatorFilter</code> to the Appender. Uncomment the
+part named <em>Cyclic buffer with Evaluator</em>. You may then
+comment or delete the first Basic Cyclic buffer <em>appender</em> element.
+</p>
+<p>
+Let's take a look at the filter we've just added:
+</p>
+
+<div class="source"><pre><filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+ <evaluator name="loggingTaskEval">
+ <expression>
+ logger.getName().contains("LoggingTask") &amp;&amp;
+ message.contains("Howdydy-diddly-ho") &amp;&amp;
+ (timeStamp - event.getStartTime()) >= 20000
+ </expression>
+ </evaluator>
+ <OnMatch>DENY</OnMatch>
+</filter></pre></div>
+
+<p>
+The expression element contains a familiar java statement. This expression
+checks that the name of the logger contains the String <em>LoggingTask</em>, but
+also that the message accompagnying the log contains <em>Howdydy-diddly-ho</em>.
+Moreover, in order to be sure that the <em>Howdydy-diddly-ho</em> task actually
+works, we add to the expression a last statement that allows logs to be processed
+for the first 20 seconds after the application launch.
+The variables used in this statement (<code>logger</code>, <code>message</code> and
+<code>event</code>) are made available by logback before the filter
+evaluates the expression.
+The <em>OnMatch</em> element allows the user to choose the filter's behaviour once
+the expression was evaluated to true. A similar <em>OnMismatch</em> element exists.
+</p>
+
+<p>
+After a restart, the <em>Vew logs</em> page shows the
+<em>Howdydy-diddly-ho</em> logs for the first 20 seconds only. Trying a prime calculations
+on the <em>Prime number</em> page will add several lines to the <em>View logs</em> page.
+</p>
+
+<h4>Turbo Filters</h4>
+
+<p>
+Logback ships with a special category of filters: <code>TurboFilter</code> objects
+are ultra-fast, context-wide filters. They reveals themselves very useful to
+test MDC values, for examples and to add context-wide conditions to allow or deny
+logging events. Let's uncomment the part named
+<em>TurboFilter: MDC value</em> in the <em>logback.xml</em> file.
+</p>
+<p>
+This part adds a <code>TurboFilter</code> object to the context. It allows to
+have a typical output for every client that uses the demo application, but a different
+one for one given user. Here, the filter will accept all the requests that are
+associated with a MDC value of <em>sebastien</em> bound to the <em>username</em> key.
+</p>
+<p>
+To view the consequences of such a <code>TurboFilter</code>, we are going to
+stop all logging activity, except for a specific user. To achieve that, the simplest
+way is to set the root logger's level to <code>OFF</code>. Modify the <em>level</em>
+element, nested inside the <em>root</em> element of <em>logback.xml</em>. Its <em>value</em>
+attribute should be <em>OFF</em> instead of <em>DEBUG</em>. Next, restart the server
+as we've done previously.
+</p>
+
+<p>
+Once on the demo main webpage again, perform a few actions (i.e. calculate
+a few prime numbers) and watch the <em>View logs</em> page. The table should be
+empty.
+</p>
+
+<p>
+Now log in the application using the username <em>sebastien</em> and perform a few
+prime calculations again. The <em>View logs</em> page now shows the logs that were
+generated by the calculation classes. Moreover, each log is associated with the name
+of the user who provoked the logging event. Please log off before continuing the
+demo, using the <em>logout</em> button on the left.
+</p>
+
+<h4>Parametrized logging</h4>
+
+<p>
+Parametrized logging is a feature that will be a great asset for any performance-critical
+system. Usually, a logging request is issued like this:
+</p>
+
+<div class="source"><pre>logger.debug("Hello, my name is" + username + ", I am " + age + " years old.");</pre></div>
+
+<p>
+By issuing this line, the cost of constructing the String cannot be saved when the
+log request is not processed. For example, using the <code>debug()</code> method
+when, as we've just done, the root level is any value higher that <em>DEBUG</em> will
+result in a loss of time because all calls to the <code>debug()</code> method will
+eventually be dropped.
+</p>
+
+<p>
+Logback offers the following method:
+</p>
+
+<div class="source"><pre>logger.debug("Hello, my name is {}, I am {} years old", username, age);</pre></div>
+
+<p>
+As you can see, the variables are not inserted in the message yet. Both the message
+and the values will be saved and used later, if the logging event is processed.
+</p>
+
+<p>
+Let us now run a test to see what kind of gain can we expect from this different
+message formatting approach. First, go to the <em>Prime number</em> page and
+run a few calculations. Check the time it takes to compute the results. To
+see a clearer difference between the two formatting methods, you might want to
+try the two big integers that are listed below the prime number textbox.
+</p>
+
+<p>
+Now let us edit the <code>NumberCruncherImpl</code> class, to switch the log methods.
+You will find this class in the <em>src/main/java/ch/qos/logback/demo/prime/</em>
+directory. On line 54 and 55, just uncomment the parametrized logging line and
+comment out the other line. Restart the server with <em>mvn package jetty:run</em>
+and re-run the calculations you tried beforehand.
+</p>
+
+<p>
+The durations should be obviously different. Remember that we had turned off all
+logging in the previous step of this demo. With the initial formatting method,
+we were constructing the logging message (<em>"Trying "+i+" as a factor."</em>)
+a huge amount of times, actually each time a factor was tried for these big numbers.
+With the paramatrized logging, the construction of the message was postponed and, since
+logging was turned off, not processed. We see here that the cost of the <b>non-</b>logging
+was taken down to a very small figure, dividing the total cost of the calculation
+by a non-negligeable factor.
+</p>
+
+<h4>Markers</h4>
+
+<p>
+SLF4J allows the use of Marker objects.
+For example, one could use <em>TRACE</em> markers, to enrich some
+specific logging statements. In our demo applications, the <em>Howdydy-diddly-ho</em>
+logging statements are bound to a <em>TRACE</em> marker.
+On the other hand, one could want that such
+marked statements be dropped and not logged anywhere. <code>TurboFilter</code>
+objects can do that in an elegant and flexible way. Let us uncomment the
+<em>TurboFilter: Marker value</em> section in the <em>logback.xml</em> file as
+well as set the root logger's level back to <em>DEBUG</em>,
+and reload via the <em>Reload configuration</em> page.
+</p>
+<p>
+The logging statements that contained the <em>Howdydy-diddly-ho</em> do
+not appear anymore because they were associated with a <em>TRACE</em> marker. You
+can check that by visiting the <em>View Logs</em> page and reloading it every three
+seconds for several times.
+</p>
+
+<h3>Logback Access</h3>
+
+<p>
+Access logging is another important feature offered by logback. Give a
+look at what appears on the console while
+browsing the logback-demo website. Each access is logged to the console,
+with some information about the event. The configuration file
+that we will edit in the next few steps is called <em>logback-access.xml</em>
+and is located in the <em>src/etc/</em> directory.
+The necessary configuration is listed below:
+</p>
+
+<div class="source"><pre><configuration>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.access.PatternLayout">
+ <Pattern>%h %l %u %t \"%r\" %s %b</Pattern>
+ </layout>
+ </appender>
+
+ <appender-ref ref="STDOUT" />
+
+</configuration></pre></div>
+
+<p>
+To see more clearly the output produced by logback access,
+you might want set the root logger's level to <em>OFF</em>, in the first
+logback configuration file, called
+<em>logback.xml</em> and located in <em>src/main/resources/</em>. It will clear
+the console from the logs made by the demo application and only display those
+that are generated by logback access.
+</p>
+
+<p>
+To see the logs produced by logback access, just visit a few pages and
+look at your console. The information contained in each line has been
+specified in the configuration file. The <code>ConsoleAppender</code>
+named <em>STDOUT</em> contains a <code>PatternLayout</code> component.
+This very component that one uses in logback classic to display either
+the message, logger name or level of the request is used in logback
+access to display the request method, requested page, status code and many others.
+</p>
+
+<p>Here is a sample output of this appender.</p>
+
+<div class="source"><pre>127.0.0.1 - - 22/01/2007:14:35:40 +0100 GET /logback-demo/ViewStatii.do HTTP/1.1 200 3660
+127.0.0.1 - - 22/01/2007:14:35:41 +0100 GET /logback-demo/index.jsp HTTP/1.1 200 2389
+127.0.0.1 - - 22/01/2007:14:35:42 +0100 GET /logback-demo/lastLog/ HTTP/1.1 200 948
+127.0.0.1 - - 22/01/2007:14:35:42 +0100 GET /logback-demo/index.jsp HTTP/1.1 200 2389
+127.0.0.1 - - 22/01/2007:14:35:43 +0100 GET /logback-demo/prime.jsp HTTP/1.1 200 1296
+127.0.0.1 - - 22/01/2007:14:35:44 +0100 GET /logback-demo/index.jsp HTTP/1.1 200 2389
+127.0.0.1 - - 22/01/2007:14:35:45 +0100 GET /logback-demo/lottery.jsp HTTP/1.1 200 1209
+127.0.0.1 - - 22/01/2007:14:35:46 +0100 GET /logback-demo/index.jsp HTTP/1.1 200 2389
+127.0.0.1 - - 22/01/2007:14:35:48 +0100 GET /logback-demo/reload.jsp HTTP/1.1 200 1335
+127.0.0.1 - - 22/01/2007:14:35:49 +0100 GET /logback-demo/index.jsp HTTP/1.1 200 2389
+127.0.0.1 - - 22/01/2007:14:35:54 +0100 GET /logback-demo/login.jsp HTTP/1.1 200 1214
+127.0.0.1 - - 22/01/2007:14:35:55 +0100 GET /logback-demo/Logout.do HTTP/1.1 200 1000</pre></div>
+
+<h4>Filtering</h4>
+
+<p>
+In this next part, we are going to add some information to the console.
+Let us imagine that we want to log the numbers that are tried on the
+<em>Lottery</em> page. We will need a second <code>ConsoleAppender</code>
+that will only print a given information (e.g. the guessed number, along
+with some hints about the player). The appender will also have to
+print that information only when a certain page is accessed.
+</p>
+
+<p>
+The configuration lines that are necessary are listed below.
+</p>
+
+<div class="source"><pre><appender name="STDOUT_LOTTERY"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+ <evaluator name="lotto_eval">
+ <Expression>
+ url.matches(event.getRequestURL().toString())
+ </Expression>
+ <matcher name="url">
+ <regex>Lottery.do</regex>
+ <caseSensitive>false</caseSensitive>
+ </matcher>
+ </evaluator>
+ <OnMatch>ACCEPT</OnMatch>
+ <OnMismatch>DENY</OnMismatch>
+ </filter>
+ <layout class="ch.qos.logback.access.PatternLayout">
+ <Pattern>
+ LOTTERY: %A [%r] Guess=%reqParameter{guessed_number}
+ </Pattern>
+ </layout>
+</appender></pre></div>
+
+<p>
+This appender will use a <code>PatternLayout</code> to format its output.
+The <em>%reqParameter</em> conversion word is used to extract the guessed number
+from the request, and print it.
+</p>
+<p>
+It also uses an <code>EvaluatorFilter</code> that will prevent the appender
+to display anything when the access' request url does not match the
+given expression. You can see that it is easy to specify a RegExp, name
+it and use it in the expression that will be evaluated. In that case, we only
+entered the name of the <em>lottery.do</em> action.
+</p>
+
+<p>
+Let us uncomment the two elements with the <em>Lottery to Console</em> comments and
+restart the server. Now, try to play the lottery. You will see more lines in the
+Console that you've seen until now. At every try, logback will produce a log
+as shown below:
+</p>
+
+<div class="source"><pre>LOTTERY: 192.168.1.6 [POST /logback-demo/Lottery.do HTTP/1.1] Guess=321</pre></div>
+
+<h4>Sending emails</h4>
+
+<p>
+Logback access provides several components that are usually used by the classic
+module. For example, a <code>SMTPAppender</code> can be used to send an email when
+a specific event occurs. Here, we will contact the lottery administrator each time
+a winner is detected. To achieve this, we will add a <code>SMTPAppender</code> to
+the existing configuration. Please uncomment the part of <em>logback-access.xml</em>
+named <em>Lottery to Email</em>. Do not forget to uncomment the
+<em>appender-ref</em> element, at the end of the configuration file, referencing
+the appender called <em>SMTP</em>. In the appender element, notice the use of a
+<code>URLEvaluator</code>. This evaluator allows us to only specify one or more URLs
+that have to be watched. When one of them are accessed, an email is sent.
+</p>
+
+<p>
+A reload of the configuration has to be done before we can test this new
+component. Once done, try to play the lottery with the number <em>99</em>.
+You should see a congratulation message but, most importantly, the
+specified recipients should have a new mail in their mailbox. The content
+of the email is a nicely formatted HTML table with informations about
+the access that have occured before the triggering event.
+</p>
+
+<h3>JMX</h3>
+
+<p>
+Logback publishes several components via JMX. This allows you to see
+the status of certain objects, and change several configuration parameters.
+Publishing logback's components via JMX is possible with Jetty and Tomcat.
+</p>
+
+<p>
+To see logback access' components, visit the following page:
+</p>
+
+<div class="source"><pre>http://localhost:8082/</pre></div>
+
+<p>
+The domain <em>ch.qos.logback.access.jetty</em> contains an entry
+that allows you to see the <em>RequestLogImpl</em> component. This component
+is used to plug logback in Jetty's internal achitecture. Clicking on
+it reveals the status of several parameters, such as the started status, and
+two methods are available to start and stop the <em>RequestLogImpl</em>.
+</p>
+
+<p>
+To see the influence of the available operations, place the terminal window
+and your web browser such that you can see them both. Stop the <em>RequestLogImlp</em>
+and reload a few times the main page of the demo. Nothing should be displayed. If you start
+the <em>RequestLogImpl</em> again, the requests will be shown in the terminal
+window.
+</p>
+
+<p>
+In the <em>logback-access.xml</em> configuration file, uncomment the <em>JMX</em>
+part and restart the server. A <code>CountingFilter</code> will now be available in
+the <em>ch.qos.logback.access</em> domain. Clicking on it will display several statistical
+figures corresponding to server accesses. Loading some application pages will make
+these figures grow and show a time-sensitive picture of the server activity.
+</p>
+
+
+<p>
+These is more to discover with logback and JMX. In the <em>logback.xml</em> file,
+placed in the <em>src/main/resources</em> directory, uncomment the <code>JMXConfigurator</code>
+element. Once done, restart the server.
+</p>
+
+<p>
+By refreshing the previously loaded JMX page, you should see a new component,
+under the domain <em>ch.qos.logback.classic</em>. It is the <code>JMXConfigurator</code>.
+Clicking on it reveals its content. Its possibilities are listed below:
+</p>
+
+<ul>
+ <p>
+ Reload the configuration using the same file that was
+ previously used.
+ </p>
+ <p>
+ Reload the configuration using a file whose path is passed as
+ a parameter.
+ </p>
+ <p>
+ Reload the configuration using a file whose URL is passed as a
+ parameter.
+ </p>
+ <p>Get the level of a logger</p>
+ <p>Change the level setting of a specified logger.</p>
+ <p>Change a list of all declared loggers.</p>
+ <p>Change the level setting of a specified logger.</p>
+</ul>
+
+<p>
+ In the last case, you must specify the name of the logger you
+ wish to alter, and its new level.
+</p>
+
+<p>
+Checking the level of a logger is an easy task. Enter the name of the logger in
+the appropriate field and click the <em>Invoke</em> button. You should be able
+to verify that the logger named <em>root</em> has its level set to <em>OFF</em>.
+</p>
+
+
+<p>
+Let us test the level setting possibility of the configurator.
+The <em>Prime Number</em> page requests two types of logs. When the
+calculation checks if a number is a factor, a <em>DEBUG</em> log is displayed. When
+the calculation has found a factor, a <em>INFO</em> log is displayed.
+</p>
+
+<p>
+Let us first set the level of the logger named <em>ch.qos.logback.demo.prime</em>
+to <em>DEBUG</em>. Run a prime calculation directly, without restarting the server. The
+<em>View logs</em> page should show the <em>DEBUG</em> and <em>INFO</em> logs.
+</p>
+
+<p>
+Now, if you set the level of the <em>ch.qos.logback.demo.prime</em> logger to
+<em>INFO</em>, and run a prime calculation
+again, you should not see the <em>DEBUG</em> level logs anymore.
+</p>
+
+<p>
+This demo of logback is now over. Do not hesitate to play around with the configuration files.
+You might want to check the <a href="http://logback.qos.ch/documentation.html">
+logback documentation page</a> for more information about any component
+you'd like to test.
+</p>
+
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/documentation.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/documentation.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,78 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Documentation</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+ <h2>Logback documentation</h2>
+
+ <p>Below is a list of logback-related documentaiton currently
+ available.</p>
+
+ <ul>
+ <li><a href="manual/index.html"><b>The logback manual</b></a></li>
+
+ <li>
+ <a href="access.html">An introduction to logback-access for Jetty
+ and Tomcat</a>
+ </li>
+ <li>
+ <a href="faq.html">A Frequently Asked Questions list (FAQ)</a>
+ </li>
+ <li>
+ <a href="bridge.html">How to use the log4j bridge</a>
+ </li>
+ <li>
+ <a href="jmxConfig.html">How to use the logback JMX Configurator</a>
+ </li>
+ <li>
+ <a href="demo.html">A step-by-step document to experience the logback-demo webApp</a>
+ </li>
+ </ul>
+
+ Source code related documentation:
+
+ <ul>
+ <li>
+ <a href="apidocs/index.html"><b>Javadoc</b></a>
+ </li>
+ <li>
+ <a href="xref/index.html">Source code</a>
+ </li>
+ <li>
+ <a href="xref-test/index.html">Test classes source code</a>
+ </li>
+ </ul>
+
+
+ Recently, Ceki Gülcü presented the top 10 reasons for migrating your projects to logback.
+ Issues such as migration strategy, new APIs, SLF4J and Joran were be discussed. Emphasis was given to
+ practical aspects and a live demo rather than relatively theoretical considerations. If you were
+ not able to attend the presentation (or even if you were there), you can
+ <a href="10reasons.ppt">download the slides</a> that Ceki used.
+
+
+
+
+
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/download.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/download.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Download</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+
+ <div class="section">
+ <h2>Download links</h2>
+ </div>
+
+ <p>
+ Logback modules are available as downloads including full source code, class files
+ and documentation.
+ </p>
+
+ <ul>
+ <p>
+ <a href="dist/logback-${project.version}.zip">
+ logback-${project.version}.zip
+ </a>
+ </p>
+ <p>
+ <a href="dist/logback-${project.version}.tar.gz">
+ logback-${project.version}.tar.gz
+ </a>
+ </p>
+ </ul>
+
+
+ <p>If you wish to download an older version of logback, please visit the
+ <a href="http://logback.qos.ch/dist/">distributions directory</a>.</p>
+
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/faq.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/faq.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,258 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Logback FAQ</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+ <h2>
+ <a name="top">Logback Frequently Asked Questions</a>
+ </h2>
+
+ <p>
+ <b>Logback Classic</b>
+ </p>
+
+ <ol type="1">
+ <li>
+ <a href="#setup_jetty">
+ How can I use logback-classic with Jetty ?
+ </a>
+ </li>
+ <li>
+ <a href="#auto_config">
+ How does the automatic configuration work?
+ </a>
+ </li>
+ <li>
+ <a href="#intercept_calls_tomcat">
+ How can I intercept JCL calls in Tomcat?
+ </a>
+ </li>
+ <li>
+ <a href="#intercept_calls_jetty">
+ How can I intercept JCL calls in Jetty ?
+ </a>
+ </li>
+ </ol>
+
+ <div class="section">
+ <h2>Logback Classic</h2>
+ <dl>
+ <dt>
+ <a name="setup_jetty">
+ How can I use logback-classic with Jetty ?
+ </a>
+ </dt>
+ <dd>
+ <p>
+ The Jetty application server uses SLF4J for its internal
+ logging. Here are the required steps to install logback
+ as SLF4J's underlaying implementation.
+ </p>
+ <p>
+ A few jars must be present in the
+ <em>JETTY_HOME/lib</em>
+ directory.
+ </p>
+
+ <p>
+ Logback-classic is based on the SLF4J api. Therefore,
+ the
+ <em>slf4j-api-VERSION.jar</em>
+ jar must be present. This jar can be downloaded from the
+ <a href="http://www.slf4j.org/">SLF4J</a>
+ project.
+ </p>
+ <p>
+ Logback's own jars must also be present, namely
+ <em>logback-core-VERSION.jar</em>
+ and
+ <em>logback-classic-VERSION.jar</em>
+ .
+ </p>
+
+ <p>
+ To configure logback-classic, a file called
+ <em>logback.xml</em>
+ should be placed in the
+ <em>JETTY_HOME/resources</em>
+ directory. You can find configuration samples in the
+ <em>examples/src/chapter4/conf/</em>
+ directory, in the distribution of logback.
+ </p>
+ <table border="0">
+ <tr>
+ <td align="right">
+ <a href="#top">[top]</a>
+ </td>
+ </tr>
+ </table>
+ <hr />
+ </dd>
+ <dt>
+ <a name="auto_config">
+ How does the automatic configuration work?
+ </a>
+ </dt>
+ <dd>
+ <p>
+ If a file called
+ <em>logback.xml</em>
+ is found in the classpath, then it is used.
+ </p>
+ <p>
+ In case it is not found, a
+ <em>logback-test.xml</em>
+ file is searched, and used if available.
+ </p>
+ <p>
+ If none of these files are available, logback uses its
+ <code>BasicConfigurator</code>
+ class to create a simple default configuration that will
+ only log to the console.
+ </p>
+ <table border="0">
+ <tr>
+ <td align="right">
+ <a href="#top">[top]</a>
+ </td>
+ </tr>
+ </table>
+ <hr />
+ </dd>
+ <dt>
+ <a name="intercept_calls_tomcat">
+ How can I intercept JCL calls in Tomcat?
+ </a>
+ </dt>
+ <dd>
+ <p>
+ When a dependency of your webapp logs using Jakarta
+ Commons Logging (for example Struts), you can intercept
+ these calls and redirect them to logback.
+ </p>
+ <p>
+ This can be done by using
+ <em>jcl104-over-slf4j.jar</em>
+ , a module that is shipped with
+ <a href="http://www.slf4j.org">SLF4J</a>
+ .
+ </p>
+ <p>
+ If you have only one webapp, its
+ <em>WEB-INF/lib</em>
+ directory should already contain the logback jars,
+ namely
+ <em>logback-core-VERSION.jar</em>
+ ,
+ <em>logback-classic-VERSION.jar</em>
+ and
+ <em>slf4j-api-VERSION.jar</em>
+ . A logback configuration file, named
+ <em>logback.xml</em>
+ should be placed in the
+ <em>WEB-INF/classes/</em>
+ directory.
+ </p>
+ <p>
+ You now need to add
+ <code>jcl104-over-slf4j.jar</code>
+ to your
+ <em>WEB-INF/lib</em>
+ directory and remove
+ <code>commons-logging-1.0.4.jar</code>
+ . The logging that used to be directed to JCL should now
+ be handled by logback.
+ </p>
+
+ <p>
+ In case several webapps share the logback jars, you
+ might place the previously mentionned jars in the
+ <em>common/lib/</em>
+ directory of your Tomcat installation. The
+ <em>logback.xml</em>
+ file should then be placed in
+ <em>common/classes</em>
+ .
+ </p>
+ <table border="0">
+ <tr>
+ <td align="right">
+ <a href="#top">[top]</a>
+ </td>
+ </tr>
+ </table>
+ <hr />
+ </dd>
+ <dt>
+ <a name="intercept_calls_jetty">
+ How can I intercept JCL calls in Jetty ?
+ </a>
+ </dt>
+ <dd>
+ <p>
+ Using logback as the logging implementation of choice
+ for frameworks depending on JCL can also be done in
+ Jetty.
+ </p>
+ <p>
+ In case you have only one webapp, the required steps are
+ exactly the same as
+ <a href="#intercept_calls_tomcat">
+ those needed in Tomcat
+ </a>
+ .
+ </p>
+ <p>
+ In case several webapps share the logback jars, you
+ might place the necessary jars in the
+ <em>lib/</em>
+ directory of your Jetty installation. The
+ <em>logback.xml</em>
+ file should then be placed in the
+ <em>resources/</em>
+ directory.
+ </p>
+ <p>
+ However, due to
+ <a
+ href="http://docs.codehaus.org/display/JETTY/Classloading">
+ Jetty's internal Classloading mechanism
+ </a>
+ , the
+ <em>logback-classic-VERSION.jar</em>
+ and
+ <em>slf4j-api-VERSION.jar</em>
+ files should also be placed in the
+ <em>WEB-INF/lib/</em>
+ directory of your webapps.
+ </p>
+ <table border="0">
+ <tr>
+ <td align="right">
+ <a href="#top">[top]</a>
+ </td>
+ </tr>
+ </table>
+ </dd>
+ </dl>
+ </div>
+ </div>
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/images/logos/lblogo.jpg
==============================================================================
Binary file. No diff available.
Added: logback/trunk/logback-site/src/site/resources/images/logos/qosLogo.png
==============================================================================
Binary file. No diff available.
Added: logback/trunk/logback-site/src/site/resources/index.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/index.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,50 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Logback Home</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+ <h2>Logback Project</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 exerience gained in building
+ industrial-strength logging systems going back as far as 1999.
+ </p>
+ <p>
+ Logback's basic architecture is sufficiently generic so as to
+ apply under different circumstances. At present time, logback is
+ divided into three modules, logback-core, logback-classic and
+ logback-access.
+ </p>
+
+ <p>
+ The logback-core module lays the groundwork for the other two
+ modules. The logback-classic module can be assimilated to a
+ significantly improved version of log4j. Moreover,
+ 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 HTTP-access log functionality. Note that you can
+ easily build your own modules on top of the Core module.
+ </p>
+
+
+
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/jmxConfig.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/jmxConfig.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,208 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>JMX Configuration</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+
+ <h2>JMX Configurator</h2>
+
+ <p>
+ As of version 0.8, logback ships with a component that allows
+ configuration via JMX. Basically, it lets you reload the current
+ configuration, load a new one, list loggers and modify logger levels.
+ </p>
+
+ <h3>Configuring your server</h3>
+ <p>
+ The first step is to make sure that your application server will
+ allow the JMX Configurator to publish itself. In this document,
+ we'll cover the necessary steps in Tomcat and Jetty.
+ </p>
+
+ <h4>Configuring Tomcat</h4>
+ <p>
+ Accessing JMX components with Tomcat requires to add the following lines
+ to the <em>$TOMCAT_HOME/bin/catalina.sh</em> configuration file:
+ </p>
+
+<div class="source"><pre>CATALINA_OPTS="-Dcom.sun.management.jmxremote"
+CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
+CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"</pre></div>
+
+ <p>
+ Once started with these options, Tomcat's JMX compoenents can be accessed
+ with JConsole by issuing the following command in a shell:
+ </p>
+<div class="source"><pre>jconsole &</pre></div>
+
+ <p>
+ You might prefer to access your components via a web-based solution using MX4J.
+ In that case, here are the required steps:
+ </p>
+
+ <p>
+ First, <a href="http://mx4j.sourceforge.net/">download MX4J</a>.
+ Place the <em>mx4j-impl.jar</em> file in
+ the <em>$TOMCAT_HOME/bin/</em> directory, and the <em>mx4j-tools.jar</em>
+ in the <em>$TOMCAT_HOME/common/lib/</em> directory.
+ </p>
+
+ <p>Then, add the following lines to the
+ <em>$TOMCAT_HOME/bin/catalina.sh</em> configuration file:
+ </p>
+
+<div class="source"><pre><!-- at the beginning of the file -->
+CATALINA_OPTS="-Dcom.sun.management.jmxremote"
+CATALINA_OPTS="$CATALINA_OPTS -Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder"
+
+<!-- in the "Add on extra jar files to CLASSPATH" section -->
+CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/mx4j-impl.jar</pre></div>
+
+ <p>
+ Finally, declare a new <code>Connector</code> in the
+ <em>$TOMCAT_HOME/conf/server.xml</em> file:
+ </p>
+
+<div class="source"><pre><Connector port="8050"
+ handler.list="mx"
+ mx.enabled="true"
+ mx.httpHost="localhost"
+ mx.httpPort="8082"
+ protocol="AJP/1.3" /></pre></div>
+
+ <p>
+ Once Tomcat is started, you should be ableo to reach the JMX components by
+ pointing a browser to the following URL:
+ </p>
+
+<div class="source"><pre>http://host_name:8082/</pre></div>
+
+ <h4>Configuring Jetty</h4>
+
+ <p>
+ Configuring Jetty to publish JMX components requires a few modifications to the
+ <em>$JETTY_HOME/etc/jetty.xml</em> configuration file. Here are the elements that need to be
+ added:
+ </p>
+
+<div class="source"><pre><Call id="MBeanServer" class="java.lang.management.ManagementFactory" name="getPlatformMBeanServer"/>
+<!-- initialize the Jetty MBean container -->
+<Get id="Container" name="container">
+ <Call name="addEventListener">
+ <Arg>
+ <New class="org.mortbay.management.MBeanContainer">
+ <Arg><Ref id="MBeanServer"/></Arg>
+ <Set name="managementPort">8082</Set>
+ <Call name="start" />
+ </New>
+ </Arg>
+ </Call>
+</Get></pre></div>
+
+ <p>
+ Once Jetty is started with this configuration, all available components can be reviewed
+ at this address:
+ </p>
+<div class="source"><pre>http://host_name:8082/</pre></div>
+
+
+ <h3>Using the JMX Configurator</h3>
+
+ <p>
+ The next step is to declare the JMX Configurator in the logback configuration
+ file. This is done by adding a single element, as shown below:
+ </p>
+
+<div class="source"><pre><configuration>
+
+ <b><jmxConfigurator /></b>
+
+ <appender name="console" class="ch.qos.logback.classic.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%date [%thread] %-5level %logger{25} - %msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug"/>
+ <appender-ref ref="console" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ Once the JMX Configurator is displayed on your screen, there are
+ several operations available.
+ </p>
+
+ <ul>
+ <p>Display the logback Statuses
+ </p>
+ <p>Reload the configuration using the same file that was previously
+ used.
+ </p>
+ <p>Reload the configuration using a file whose path is passed as
+ a parameter.</p>
+ <p>
+ Reload the configuration using a file whose URL is passed as a
+ parameter.
+ </p>
+ <p>
+ Get the level of a logger
+ </p>
+ <p>
+ Change the level setting of a specified logger.
+ </p>
+ <p>
+ Change a list of all declared loggers.
+ </p>
+ <p>
+ Change the level setting of a specified logger.
+ </p>
+ </ul>
+
+ <p>
+ In the last case, you must specify the name of the logger you wish to
+ alter, and its new level.
+ </p>
+ <p>
+ The level of a logger is a value that can be null, if no specific level
+ has been configured for said logger. Its effective level, on the other
+ hand, is given with respect to the parent loggers' levels. This value cannot
+ be null, since all loggers are direct or indirect children of the root
+ logger, whose level is always set. When trying to get the level or effective
+ level of a logger, the name of the logger has to be passed as a parameter.
+ Note that trying to get the level or effective level for a nonexistent logger
+ will not return any result.
+ </p>
+
+ <p>
+ Displaying logback Statuses via JMX can help users check the internal state
+ of logback. It shows if anything has gone wrong, if rollovers occured
+ as expected, and many other useful informations. It is also very useful
+ when reloading a configuration, since the user can immediately see if
+ the configuration file was successfully processed.
+ </p>
+
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/license.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/license.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,58 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>License</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+ <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 big"><pre>Logback: the reliable, generic, fast and flexible logging library for Java.
+
+Copyright (C) 2000-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.</pre></div>
+
+ <p>Please note that logback is intended to be used behind the
+ SLF4J API, which is licensed under <a href="http://www.slf4j.org/license.html">an X11 type license</a>.
+ </p>
+
+ <p>If you wish to make a significant contribution to the logback
+ project, we invite you to file <a href="cla.txt">Contributor
+ License Agreement</a>. The purpose of this agreement is to
+ formalize the terms of your contribution and to protect the
+ project in case of litigation.
+ </p>
+
+
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/mailinglist.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/mailinglist.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,155 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Mailing lists</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+
+ <h2>Project Mailing Lists</h2>
+
+ <p>
+ A mailing list is an electronic discussion forum that anyone
+ can subscribe to. When someone sends an email message to the
+ mailing list, a copy of that message is broadcast to
+ everyone who is subscribed to that mailing list. Mailing
+ lists provide a simple and effective communication
+ mechanism. With potentially thousands of subscribers, there
+ is a common set of etiquette guidelines that you should
+ observe. Please keep on reading.
+ </p>
+ <h3>Respect the mailing list type</h3>
+ <p>
+ The "User" lists where you can send questions and comments
+ about configuration, setup, usage and other "user" types of
+ questions. The "Developer" lists where you can send
+ questions and comments about the actual software source code
+ and general "development" types of questions.
+ </p>
+ <p>
+ Some questions are appropriate for posting on both the
+ "user" and the "developer" lists. In this case, pick one and
+ only one. Do not cross post.
+ </p>
+ <p>
+ Please do your best to ensure that you are not sending HTML
+ or "Stylelized" email to the list. If you are using Outlook
+ or Outlook Express or Eudora, chances are that you are
+ sending HTML email by default. There is usually a setting
+ that will allow you to send "Plain Text" email.
+ </p>
+
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Name</th>
+ <th>Volume</th>
+ <th>Subscribe</th>
+ <th>Unsubscribe</th>
+ <th>Archives</th>
+ </tr>
+ <tr class="b">
+ <td>Logback Announce List</td>
+ <td>Low</td>
+ <td>
+ <a href="http://qos.ch/mailman/listinfo/logback-announce">
+ Subscribe
+ </a>
+ </td>
+ <td>
+ <a href="http://qos.ch/mailman/options/logback-announce">
+ Unsubscribe
+ </a>
+ </td>
+ <td>
+ <a href="http://www.qos.ch/pipermail/logback-announce/">
+ qos.ch
+ </a> |
+ <a href="http://marc.theaimsgroup.com/?l=logback-announce">
+ MARC
+ </a> |
+ <a href="http://www.nabble.com/Logback-Announce-f16251.html">
+ Nabble
+ </a>
+ </td>
+ </tr>
+ <tr class="a">
+ <td>Logback User List</td>
+ <td>Medium</td>
+ <td>
+ <a href="http://qos.ch/mailman/listinfo/logback-user">
+ Subscribe
+ </a>
+ </td>
+ <td>
+ <a href="http://qos.ch/mailman/options/logback-user">
+ Unsubscribe
+ </a>
+ </td>
+ <td>
+ <a href="http://www.qos.ch/pipermail/logback-user/">
+ qos.ch
+ </a> |
+ <a href="http://marc.theaimsgroup.com/?l=logback-user">
+ MARC
+ </a> |
+
+ <a href="http://www.nabble.com/Logback-User-f16252.html">
+ Nabble
+ </a>
+ </td>
+ </tr>
+ <tr class="b">
+ <td>Logback Dev List</td>
+ <td>Medium</td>
+ <td>
+ <a href="http://qos.ch/mailman/listinfo/logback-dev">
+ Subscribe
+ </a>
+ </td>
+ <td>
+ <a href="http://qos.ch/mailman/options/logback-dev">
+ Unsubscribe
+ </a>
+ </td>
+ <td>
+ <a href="http://www.qos.ch/pipermail/logback-dev/">
+ qos.ch
+ </a> |
+ <a href="http://marc.theaimsgroup.com/?l=logback-dev">
+ MARC
+ </a> |
+ <a href="http://www.nabble.com/Logback-Dev-f16253.html">
+ Nabble
+ </a>
+ </td>
+ </tr>
+ </table>
+
+ <h2>On IRC</h2>
+
+ <p>We can also be reached by IRC at <code><span class="big">irc.freenode.net#logback</span>.</code>
+ </p>
+
+
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/manual/appenders.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/manual/appenders.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,3172 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Chapter 4: Appenders</title>
+<link rel="stylesheet" type="text/css" media="screen" href="../css/site.css" />
+</head>
+<body>
+<script src="../templates/header.js"></script>
+<div id="left">
+
+<script src="../templates/left.js" language="JavaScript" type="text/javascript">
+</script>
+
+</div>
+<div id="right">
+ <script src="../templates/right.js"></script>
+</div>
+<div id="content">
+ <h2>Chapter 4: Appenders</h2>
+ <div class="author">
+ Authors: Ceki Gülcü, Sébastien Pennec
+ </div>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <td>
+ <a 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"></img>
+ </a>
+ </td>
+ <td>
+ <p>Copyright © 2000-2006, QOS.ch</p>
+
+ <p>
+
+ This work is licensed under a
+ <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
+ Creative Commons
+ Attribution-NonCommercial-ShareAlike 2.5
+ License
+ </a>.
+
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <div class="highlight">
+ <p>
+ In order to run the examples in this chapter, 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>
+
+ <h2>What is an Appender</h2>
+
+ <p>
+ Logback delegates the task of writing a logging event to appenders.
+ Appenders must implement the
+ <a href="../xref/ch/qos/logback/core/Appender.html"><code>ch.qos.logback.core.Appender</code></a> interface.
+ The salient methods of this interface are summarized below:
+ </p>
+ <div class="source"><pre>package ch.qos.logback.core;
+
+import ch.qos.logback.core.spi.ContextAware;
+import ch.qos.logback.core.spi.FilterAttachable;
+import ch.qos.logback.core.spi.LifeCycle;
+
+
+public interface Appender<E> extends LifeCycle, ContextAware, FilterAttachable {
+
+ public String getName();
+ <b>void doAppend(E event);</b>
+ public void setLayout(Layout<E> layout);
+ public Layout<E> getLayout();
+ public void setName(String name);
+
+}</pre></div>
+
+ <p>
+ Most of the methods in the <code>Appender</code> interface are made of setter
+ and getter methods. A notable exception is the <code>doAppend()</code>
+ method taking an Object instance as its only parameter.
+ This method is perhaps the most important in the logback framework.
+ It is responsible for outputting the logging events in a suitable format
+ to the appropriate output device. Appenders are named entities.
+ This ensures that they can be referenced by name, a quality confirmed
+ to be especially significant in configuration scripts.
+ An appender can contain multiple filters, thus the <code>Appender</code>
+ interface extending the <code>FilterAttachable</code> interface.
+ Filters are discussed in detail in a subsequent chapter.
+ </p>
+
+ <p>
+ Appenders are ultimately responsible for outputting logging events.
+ However, they may delegate the actual formatting of the event to a
+ <code>Layout</code> object.
+ Each layout is associated with one and only one appender, referred to
+ as the containing appender. Some appenders have a built-in or fixed
+ event format, such that they do not require a layout. For example, the
+ <code>SocketAppender</code> simply serialize logging events before
+ transmitting them over the wire.
+ </p>
+
+ <a name="AppenderBase"></a>
+ <h2>AppenderBase</h2>
+
+ <p>
+ The <a href="../xref/ch/qos/logback/core/AppenderBase.html">
+ <code>ch.qos.logback.core.AppenderBase</code></a> class is an abstract
+ class implementing the <code>Appender</code> interface.
+ It provides basic functionality shared by all appenders,
+ such as methods for getting or setting their name, their started status,
+ their layout and their filters.
+ It is the super-class of all appenders shipped with logback.
+ Although an abstract class, <code>AppenderBase</code> actually implements the
+ <code>doAppend()</code> method in the <code>Append</code> interface.
+ Perhaps the clearest way to discuss <code>AppenderBase</code> class is by
+ presenting a bit of its actual source code.
+ </p>
+
+<div class="source">
+ <pre>public synchronized void doAppend(E eventObject) {
+
+ // prevent re-entry.
+ if (guard) {
+ return;
+ }
+
+ try {
+ guard = true;
+
+ if (!this.started) {
+ if (statusRepeatCount++ < ALLOWED_REPEATS) {
+ addStatus(new WarnStatus(
+ "Attempted to append to non started appender [" + name + "].",this));
+ }
+ return;
+ }
+
+ if (getFilterChainDecision(eventObject) == FilterReply.DENY) {
+ return;
+ }
+
+ // ok, we now invoke derived class' implementation of append
+ this.append(eventObject);
+
+ } finally {
+ guard = false;
+ }
+}</pre>
+</div>
+
+ <p>
+ This implementation of the <code>doAppend()</code> method is synchronized.
+ It follows that logging to the same appender from different
+ threads is safe. While a thread, say <em>T</em>, is executing the <code>doAppend()</code>
+ method, subsequent calls by other threads are queued until <em>T</em>
+ leaves the <code>doAppend()</code> method, ensuring
+ <em>T</em>'s exclusive access to the appender.
+ </p>
+
+ <p>
+ The first thing the <code>doAppend()</code> method does is to set the
+ <code>guard</code> variable to <code>true</code>. This ensures that the method will not
+ call itself and create an infinite loop. Just imagine that a component, called somewhere
+ beyond the <code>append()</code>
+ method, wants to log something. Its call could be directed to the very same appender
+ that just called it, which would then call it again.
+ </p>
+
+ <p>
+ The first statement of the <code>doAppend()</code> method, once the <code>try</code> block
+ is reached, is to check whether the <code>started</code> field is true.
+ If it is not, <code>doAppend()</code> will send a warning message and return.
+ In other words, once stopped, it is impossible to write to a closed appender.
+ <code>Appender</code> objects implement the <code>LifeCycle</code> interface,
+ which implies that they implement <code>start()</code>, <code>stop()</code>
+ and <code>isStarted()</code> methods. After setting all the options of an appender,
+ Joran, logback's configuration framework, calls the <code>start()</code>
+ method to signal the appender to bind or activate its options.
+ Indeed, depending on the appender, certain options cannot be activated because
+ of interferences with other options, or appenders can even not start at all if
+ some options are missing.
+ For example, since file creation depends on truncation mode,
+ <code>FileAppender</code> cannot act on the value of its <code>File</code> option
+ until the value of the Append option is also known for certain.
+ </p>
+
+ <p>
+ If a warning message is sent due to incorrect calls to the <code>doAppend()</code>
+ method, logback's powerful <code>Status</code> error reporting system is used. In case
+ several incorrect calls on <code>doAppend()</code> are issued, <code>AppenderBase</code>
+ does not send an unlimited number of warnings. Once a certain limit is reached, the
+ <code>AppenderBase</code> instance stops its warnings.
+ </p>
+
+ <p>
+ The next <code>if</code> statement checks the result
+ of the attached <code>Filter</code> objects.
+ Depending on the decision resulting from the filter chain, events can be denied or
+ alternatively accepted.
+ In the absence of a decision by the filter chain, events are accepted by default.
+ </p>
+
+ <p>
+ Lastly, the <code>doAppend()</code> method invoke the derived classes' implementation
+ of the <code>append()</code> method, which does the actual work of appending the
+ event to the appropriate device.
+ </p>
+
+ <p>In appenders, the term option or property is reserved for named attributes
+ that are dynamically inferred using JavaBeans introspection. </p>
+
+ <h2>Logback Core</h2>
+
+ <p>
+ Core is logback's central module. It offers functionnalities that are available
+ to any other module based on logback core. The <code>Appender</code> classes
+ contained in the core module are can be used by any module without any customization.
+ </p>
+
+ <a name="WriterAppender"></a>
+ <h3>WriterAppender</h3>
+
+ <p>
+ <a href="../xref/ch/qos/logback/core/WriterAppender.html"><code>WriterAppender</code></a>
+ appends events to a <code>java.io.Writer</code>.
+ This class provides basic services that other appenders build upon.
+ Users do not usually instantiate <code>WriterAppender</code> objects directly.
+ Since <code>java.io.Writer</code> type cannot be mapped to a string, there is no
+ way to specify the target <code>Writer</code> object in a configuration script.
+ Simply put, you cannot configure a <code>WriterAppender</code> from a script.
+ However, this does not mean that <code>WriterAppender</code> lacks configurable options.
+ These options are described next.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">Encoding</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ The encoding specifies the method of conversion between 16-bit Unicode
+ characters into raw 8-bit bytes. This appender will use the local platform's
+ default encoding unless you specify otherwise using the
+ <span class="option">Encoding</span> option.
+ According to the <code>java.lang</code> package documentation, acceptable values
+ are dependent on the VM implementation although all implementations are
+ required to support at least the following encodings:
+ <em>US-ASCII</em>, <em>ISO-8859-1</em>, <em>UTF-8</em>, <em>UTF-16BE</em>,
+ <em>UTF-16LE</em> and <em>UTF-16</em>.
+ By default, the <span class="option">Encoding</span> option is
+ <code>null</code> such
+ that the platform's default encoding is used.
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">ImmediateFlush</span></b></td>
+ <td><code>boolean</code></td>
+ <td>
+ If set to true, each write of a logging event is followed by a flush operation
+ on the underlying <code>Writer</code> object. Conversely, if the option is set to false,
+ each write will not be followed by a flush.
+ In general, skipping the flush operation improves logging throughput by roughly 15%.
+ The downside is that if the application exits abruptly, the unwritten characters
+ buffered inside the <code>Writer</code> might be lost.
+ This can be particularly troublesome as those unwritten characters may contain
+ crucial information needed in identifying the reasons behind a crash.
+ By default, the <span class="option">ImmediateFlush</span> option is set to true.
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ In general, if you disable immediate flushing, then make sure to flush
+ any output streams when your application exits. Otherwise, log messages
+ will be lost as illustrated by the next example.
+ </p>
+
+ <em>Example 4.1: Exiting an application without flushing (<a href="../xref/chapter4/ExitWoes1.html">logback-examples/src/main/java/chapter4/ExitWoes1.java</a>)</em>
+<div class="source"><pre>package chapter4;
+
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.core.WriterAppender;
+import ch.qos.logback.core.layout.EchoLayout;
+
+public class ExitWoes1 {
+
+ public static void main(String[] args) throws Exception {
+ LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+ WriterAppender<LoggingEvent> writerAppender = new WriterAppender<LoggingEvent>();
+ writerAppender.setContext(lc);
+ writerAppender.setLayout(new EchoLayout<LoggingEvent>());
+
+ OutputStream os = new FileOutputStream("exitWoes1.log");
+ writerAppender.setWriter(new OutputStreamWriter(os));
+ writerAppender.setImmediateFlush(false);
+ writerAppender.start();
+
+ Logger logger = LoggerFactory.getLogger(ExitWoes1.class);
+
+ logger.debug("Hello world.");
+ }
+}</pre></div>
+
+ <p>
+ This example creates a <code>WriterAppender</code> that uses an
+ <code>OutputStreamWriter</code>
+ wrapping a <code>FileOutputStream</code> as its underlying <code>Writer</code> object,
+ with immediate flushing disabled. It then proceeds to log a single debug message.
+ According to <code>OutputStreamWriter</code> javadocs, each invocation of a
+ <code>write()</code>
+ method causes the encoding converter to be invoked on the given character(s).
+ The resulting bytes are accumulated in a buffer before being written
+ to the underlying output stream. As astonishing as this may seem,
+ running <code>ExitWoes1</code> will not produce any output in the file
+ <em>exitWoes1.log</em>
+ because the Java VM does not flush output streams when it exits.
+ Calling the <code>shutdownAndReset()</code> method of a <code>LoggerContext</code>
+ ensures that all
+ appenders in the hierarchy are closed and their buffers are flushed. The
+ <code>ExitWoes2</code> class uses this statement and outputs a logging
+ request.
+ </p>
+
+ <p>
+ The <code>WriterAppender</code> is the super class of four other appenders,
+ namely <code>ConsoleAppender</code>, <code>FileAppender</code> which in turn is
+ the super class of <code>RollingFileAppender</code>. The next figure illustrates
+ the class diagram for <code>WriterAppender</code> and its subclasses.
+ </p>
+
+ <img src="images/chapter4/fileAppenderUML.png" alt="A UML diagram showing FileAppender"></img>
+
+ <a name="ConsoleAppender"></a>
+ <h3>ConsoleAppender</h3>
+
+ <p>
+ The <a href="../xref/ch/qos/logback/core/ConsoleAppender.html">
+ <code>ConsoleAppender</code></a>, as the name indicates, appends on the console,
+ or more precisely on <em>System.out</em> or <em>System.err</em>, the former
+ being the default target. <code>ConsoleAppender</code> formats events with
+ a layout specified by the user. Both <em>System.out</em> and <em>System.err</em>
+ are <code>java.io.PrintStream</code> objects.
+ Consequently, they are wrapped inside an <code>OutputStreamWriter</code>
+ which buffers I/O operations but not character conversions.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">Encoding</span></b></td>
+ <td><code>String</code></td>
+ <td>See <code>WriterAppender</code> options.</td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">ImmediateFlush</span></b></td>
+ <td><code>boolean</code></td>
+ <td>See <code>WriterAppender</code> options.</td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">Target</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ One of the String values <em>System.out</em> or
+ <em>System.err</em>. The default target is <em>System.out</em>.
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ Here is a sample configuration that uses <code>ConsoleAppender</code>.
+ </p>
+
+<em>Example 4.2: ConsoleAppender configuration (logback-examples/src/main/java/chapter4/conf/logback-Console.xml)</em>
+<div class="source"><pre><configuration>
+
+ <b><appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</Pattern>
+ </layout>
+ </appender></b>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ To run this example, just issue the following command,
+ once in the <em>logback-examples</em> directory:
+ </p>
+
+<div class="source"><pre>java chapter4.ConfigurationTester src/main/java/chapter4/conf/logback-Console.xml</pre></div>
+
+ <a name="FileAppender"></a>
+ <h3>FileAppender</h3>
+
+ <p>
+ The <a href="../xref/ch/qos/logback/core/FileAppender.html"><code>FileAppender</code></a>,
+ a subclass of <code>WriterAppender</code>,
+ appends log events into a file. The file to write to is specified by
+ the <span class="option">File</span> option.
+ If the file already exists, it is either appended to, or truncated
+ depending on the value of the <span class="option">Append</span> option.
+ It uses a <code>FileOutputStream</code> which is wrapped by an <code>OutputStreamWriter</code>.
+ Note that <code>OutputStreamWriter</code> buffers I/O operations
+ but not character conversions. To optimize character conversions one
+ can set the <span class="option">BufferedIO</span> option to true
+ which effectively wraps the <code>OutputStreamWriter</code> with
+ a <code>BufferedWriter</code>. Options for <code>FileAppender</code> are summarized below.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">Append</span></b></td>
+ <td><code>boolean</code></td>
+ <td>If true, events are appended at the end of an existing file.
+ Otherwise, if <span class="option">Append</span> is false, any existing
+ file is truncated. The <span class="option">Append</span> option is set to true by default.</td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">Encoding</span></b></td>
+ <td><code>String</code></td>
+ <td>See <code>WriterAppender</code> options.</td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">BufferedIO</span></b></td>
+ <td><code>boolean</code></td>
+ <td>
+ The <span class="option">BufferedIO</span> option is set to false by default.
+ If set to true, the underlying <code>OutputStreamWriter</code> is wrapped
+ by a <code>BufferedWriter</code> object.
+ Setting <span class="option">BufferedIO</span> to true automatically
+ sets the <span class="option">ImmediateFlush</span> option to false.
+ The name <span class="option">BufferedIO</span> is slightly misleading because
+ buffered IO is already supported by <code>OutputStreamWriter</code>.
+ Setting <span class="option">BufferedIO</span> to true has the effect of
+ buffering I/O as well as character to raw byte conversions, saving a few
+ CPU cycles in the process.
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">BufferSize</span></b></td>
+ <td><code>int</code></td>
+ <td>Size of <code>BufferedWriter</code> buffer. The default value is 8192.</td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">File</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ The name of the file to write to. If the file does not exist, it is created. <br></br>
+ On the MS Windows platform users frequently forget to escape back slashes.
+ For example, the value <em>c:\temp\test.log</em> is not likely to be interpreted
+ properly as <em>'\t'</em> is an escape sequence interpreted as a single
+ tab character <em>(\u0009)</em>.
+ Correct values can be specified as <em>c:/temp/test.log</em> or
+ alternatively as <em>c:\\temp\\test.log</em>.
+ The <span class="option">File</span> option has no default value.
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">ImmediateFlush</span></b></td>
+ <td><code>boolean</code></td>
+ <td>
+ See <code>WriterAppender</code> options.
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ By default, <code>FileAppender</code> performs a flush operation for
+ each event, ensuring that events are immediately written to disk.
+ Setting the <span class="option">ImmediateFlush</span> option to false can drastically reduce
+ I/O activity by letting <code>OutputStreamWriter</code> buffer bytes
+ before writing them on disk. For short messages, we have observed 2 or 3
+ fold increases in logging throughput, i.e. the number of logs output
+ per unit of time. For longer messages, the throughput gains are somewhat
+ less dramatic, and range between 1.4 and 2 fold. Enabling the
+ <span class="option">BufferedIO</span>
+ option, that is buffering character to byte conversions, increases
+ performance by an additional 10% to 40% compared to only disk
+ I/O buffering (<span class="option">ImmediateFlush</span>=false).
+ Performance varies somewhat depending on the host machine as well as JDK version.
+ Throughput measurements are based on the <code>chapter4.IO</code> application.
+ Please refer to <a href="../xref/chapter4/IO.html">
+ <em>logback-examples/src/main/java/chapter4/IO.java</em></a>
+ for actual source code.
+ </p>
+
+ <p>
+ Configuring <code>FileAppender</code> can be done the following way:
+ </p>
+
+<em>Example 4.3: FileAppender configuration (logback-examples/src/main/java/chapter4/conf/logback-fileAppender.xml)</em>
+<div class="source"><pre><configuration>
+
+ <b><appender name="FILE" class="ch.qos.logback.core.FileAppender">
+ <File>testFile.log</File>
+ <Append>true</Append>
+ <Encoding>UTF-8</Encoding>
+ <BufferedIO>false</BufferedIO>
+ <ImmediateFlush>true</ImmediateFlush>
+
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</Pattern>
+ </layout>
+ </appender></b>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ To run this example, use the provided <code>ConfigurationTester</code> by
+ issuing the following command, once in the <em>logback-examples/target/classes</em>:
+ </p>
+
+<div class="source"><pre>java chapter4.ConfigurationTester src/main/java/chapter4/conf/logback-fileAppender.xml</pre></div>
+
+
+ <a name="RollingFileAppender"></a>
+ <h3>RollingFileAppender</h3>
+
+ <p>
+ <a href="../xref/ch/qos/logback/core/rolling/RollingFileAppender.html"><code>RollingFileAppender</code></a>
+ extends <code>FileAppender</code> by
+ allowing rolling from a log file to another. For example,
+ <code>RollingFileAppender</code> can log to a <em>log.txt</em> file and,
+ once a certain condition is met, change its logging target to another file.
+ </p>
+ <p>
+ There are two important logback componenents that interact with
+ <code>RollingFileAppender</code>. First, <code>RollingPolicy</code>
+ implementations define the procedure that will be followed when
+ the rollover happens. The second componenent is
+ <code>TriggeringPolicy</code> implementations that are used
+ to check wether the rollover must happen or not at a given time.
+ </p>
+
+ <p>
+ To be of any use, a <code>RollingFileAppender</code> must have
+ both a <code>RollingPolicy</code> and a <code>TriggeringPolicy</code>
+ set up. However, if its <code>RollingPolicy</code> also implements the
+ <code>TriggeringPolicy</code> interface, then only the former needs to be
+ set up.
+ </p>
+
+ <p>Here are the available options for <code>RollingFileAppender</code>:</p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">Append</span></b></td>
+ <td><code>boolean</code></td>
+ <td>See <code>FileAppender</code> options.</td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">BufferedIO</span></b></td>
+ <td><code>boolean</code></td>
+ <td>See <code>FileAppender</code> options.</td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">BufferSize</span></b></td>
+ <td><code>int</code></td>
+ <td>See <code>FileAppender</code> options.</td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">Encoding</span></b></td>
+ <td><code>String</code></td>
+ <td>See <code>WriterAppender</code> options.</td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">File</span></b></td>
+ <td><code>String</code></td>
+ <td>See <code>FileAppender</code> options.</td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">ImmediateFlush</span></b></td>
+ <td><code>boolean</code></td>
+ <td>See <code>WriterAppender</code> options.</td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">RollingPolicy</span></b></td>
+ <td><code>RollingPolicy</code></td>
+ <td>
+ This option is the component that will dictate
+ <code>RollingFileAppender</code>'s behaviour when rollover
+ occurs. See more information below.
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">TriggeringPolicy</span></b></td>
+ <td><code>TriggeringPolicy</code></td>
+ <td>
+ This option is the component that will tell
+ <code>RollingFileAppender</code> when to activate the rollover
+ procedure. See more information below.
+ </td>
+ </tr>
+ </table>
+
+ <h3>Rolling policies</h3>
+
+ <p><a href="../xref/ch/qos/logback/core/rolling/RollingPolicy.html"><code>RollingPolicy</code></a>
+ implementations are responsible for the
+ rollover procedure. They manage file renaming and in occasion file deleting.</p>
+
+ <p>The <code>RollingPolicy</code> interface is presented below:</p>
+
+<div class="source"><pre>package ch.qos.logback.core.rolling;
+
+import ch.qos.logback.core.FileAppender;
+import ch.qos.logback.core.spi.LifeCycle;
+
+public interface RollingPolicy extends LifeCycle {
+
+ <b>public void rollover() throws RolloverFailure;</b>
+ public String getNewActiveFileName();
+ public void setParent(FileAppender appender);
+}</pre></div>
+
+ <p>
+ The <code>rollover</code> method proceeds to the file change, renaming or deletion.
+ The <code>getNewActiveFileName()</code> method is called to compute a new file name, with
+ respect to the configuration elements that were injected in the <code>RollingPolicy</code>.
+ Lastly, a <code>RollingPolicy</code> knows about its parent.
+ </p>
+
+ <a name="FixedWindowRollingPolicy"></a>
+ <h4>FixedWindowRollingPolicy</h4>
+
+ <p>
+ When rolling over, <a href="../xref/ch/qos/logback/core/rolling/FixedWindowRollingPolicy.html">
+ <code>FixedWindowRollingPolicy</code></a>
+ renames files according to a fixed window algorithm as described below.
+ </p>
+ <p>
+ The <span class="option">File</span> option, which is configured in the
+ <code>FileAppender</code> element, is required. It represents the name of the file
+ to write to. The <span class="option">FileNamePattern</span>
+ option represents the file name pattern for the archived (rolled over) log files.
+ The <span class="option">FileNamePattern</span> option, which is also required, must include
+ an integer token, that is the string <em>%i</em>
+ somewhere within the pattern.
+ </p>
+
+ <p>
+ Here are the available options for <code>FixedWindowRollingPolicy</code>
+ </p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">FileNamePattern</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ This option represents the pattern that will be followed by
+ the <code>FixedWindowRollingPolicy</code> when renaming the
+ log files. If must contain the string <em>%i</em>, which will
+ indicate the position where to insert the file's index.
+ </p>
+ <p>
+ For example, using <em>MyLogFile%i.log</em>, associated with
+ minimum and maximum values of <em>1</em> and <em>3</em> will produce
+ files named <em>MyLogFile1.log</em>, <em>MyLogFile2.log</em> and
+ <em>MyLogFile3.log</em>.
+ </p>
+ <p>
+ File compression is also specified in the
+ <span class="option">FileNamePattern</span> option.
+ <em>MyLogFile%i.log.zip</em> will indicate to the
+ <code>FixedWindowRollingPolicy</code> that the archived file
+ must be compressed using the <em>zip</em> format. The <em>gz</em>
+ format is also supported.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">MaxIndex</span></b></td>
+ <td><code>int</code></td>
+ <td>
+ <p>
+ This option represents the maximum border of the window algorithm.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">MinIndex</span></b></td>
+ <td><code>int</code></td>
+ <td>
+ <p>
+ This option represents the minimum border of the window algorithm.
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ Given that this rollover algorithm requires as many file
+ renaming operations as the window size, large window sizes are
+ discouraged. The current implementation will automatically
+ reduce the window size to 12 when larger values are specified by
+ the user.
+ </p>
+
+ <p>
+ Here is an example of file handling by <code>FixedWindowRollingPolicy</code>.
+ We suppose that the <span class="option">MinIndex</span> is set to <em>1</em> and
+ <span class="option">MaxIndex</span> is set to <em>3</em>. The
+ <span class="option">FileNamePattern</span> option is set to <em>foo%i.log</em>, and
+ the <span class="option">FileNamePattern</span>
+ option is set to <em>foo.log</em>.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>
+ Steps
+ </th>
+ <th>
+ Active file name
+ </th>
+ <th>
+ Archived file names
+ </th>
+ <th>Description</th>
+ </tr>
+ <tr class="b">
+ <td>
+ 0
+ </td>
+ <td>
+ foo.log
+ </td>
+ <td>
+ -
+ </td>
+ <td>
+ No rollover has happened yet, logback logs
+ into the initial file.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>
+ 1
+ </td>
+ <td>
+ foo.log
+ </td>
+ <td>
+ foo1.log
+ </td>
+ <td>
+ First rollover. <em>foo.log</em> is renamed into <em>foo1.log</em> and
+ a new <em>foo.log</em> file is created and used for the output.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>
+ 2
+ </td>
+ <td>
+ foo.log
+ </td>
+ <td>
+ foo2.log, foo1.log
+ </td>
+ <td>
+ Second rollover. <em>foo.log</em> is renamed into <em>foo1.log</em> and
+ the old <em>foo1.log</em> is renamed into <em>foo2.log</em>.
+ Again, a new <em>foo.log</em> file is created and used for the output.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>
+ 3
+ </td>
+ <td>
+ foo.log
+ </td>
+ <td>
+ foo3.log, foo2.log, foo1.log
+ </td>
+ <td>
+ Third rollover. <em>foo.log</em> is renamed into <em>foo1.log</em> and
+ the old <em>foo1.log</em> is renamed into <em>foo2.log</em>. As well, the
+ old <em>foo2.log</em> is renamed into <em>foo3.log</em>.
+ A new <em>foo.log</em> file is created and used for the output.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>
+ 4
+ </td>
+ <td>
+ foo.log
+ </td>
+ <td>
+ foo3.log, foo2.log, foo1.log
+ </td>
+ <td>
+ From the fourth rollover, the old <em>foo3.log</em> file is deleted. The files
+ are all renamed with an increment to their index, and a new <em>foo.log</em>
+ file is created and used for the output.
+ From this moment on, there will always be 4 log files available, each being present
+ for the time of 3 rollovers and being deleted afterwards.
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ Here is a sample configuration to use <code>RollingFileAppender</code>
+ and <code>FixedWindowRollingPolicy</code>.
+ </p>
+
+<em>Example 4.4: Sample configuration of a <code>RollingFileAppender</code> using a
+<code>FixedWindowRollingPolicy</code> (logback-examples/src/main/java/chapter4/conf/logback-RollingFixedWindow.xml)</em>
+<div class="source"><pre><configuration>
+ <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <File>testFile.log</File>
+ <b><rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <FileNamePattern>testFile.%i.log.zip</FileNamePattern>
+ <MinIndex>1</MinIndex>
+ <MaxIndex>3</MaxIndex>
+ </rollingPolicy></b>
+
+ <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <MaxFileSize>5MB</MaxFileSize>
+ </triggeringPolicy>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration></pre></div>
+
+ <a name="TimeBasedRollingPolicy"></a>
+ <h4>TimeBasedRollingPolicy</h4>
+ <p>
+ <a href="../xref/ch/qos/logback/core/rolling/TimeBasedRollingPolicy.html">
+ <code>TimeBasedRollingPolicy</code></a> is both easy to configure and quite powerful.
+ It allows the rollover to be made based on time conditions. It is possible to specify
+ that the rollover must occur each day, or month, for example.
+ </p>
+ <p>
+ <code>TimeBasedRollingPolicy</code>'s only option is the
+ <span class="option">FileNamePattern</span>.
+ </p>
+
+ <p>
+ In order to use
+ <code>TimeBasedRollingPolicy</code>, the
+ <span class="option">FileNamePattern</span> option must be set. It basically
+ specifies the name of the rolled log files. The value
+ <span class="option">FileNamePattern</span> should consist of the name of the file,
+ plus a suitably placed <em>%d</em> conversion specifier.
+ The <em>%d</em> conversion specifier may contain a date and time pattern as
+ specified by the <code>java.text.SimpleDateFormat</code> class.
+ If the date and time pattern is omitted, then the default pattern
+ of <em>yyyy-MM-dd</em> is assumed. The following examples should
+ clarify the point.
+ </p>
+ <table class="bodyTable">
+ <tr class="a">
+ <th>
+ <span class="option">FileNamePattern</span>
+ </th>
+ <th>Roll-over schedule</th>
+ <th>Example</th>
+ </tr>
+ <tr class="b">
+ <td>
+ <em>/wombat/folder/foo.%d</em>
+ </td>
+ <td>
+ Daily rollover (at midnight). Due to the omission of the
+ optional time and date pattern for the <em>%d</em> token
+ specifier, the default pattern of <em>yyyy-MM-dd</em> is
+ assumed, which corresponds to daily rollover.
+ </td>
+ <td>
+ During November 23rd, 2006, logging output will go to
+ the file <em>/wombat/foo.2006-11-23</em>.
+ At midnight and for the rest of the 24th, logging
+ output will be directed to <em>/wombat/foo.2006-11-24</em>.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>
+ <em>/wombat/foo.%d{yyyy-MM}.log</em>
+ </td>
+ <td>Rollover at the beginning of each month.</td>
+ <td>
+ During the month of October 2006, logging output will go
+ to <em>/wombat/foo.2006-10.log</em>.
+ After midnight of October 31st and for the rest of
+ November, logging output will be directed to
+ <em>/wombat/foo.2006-11.log</em>.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>
+ <em>/wombat/foo.%d{yyyy-ww}.log</em>
+ </td>
+ <td>Rollover at the first day of each week. Note that the first
+ day of the week depends on the locale.</td>
+ <td>
+ During the 23rd week of 2006, the file <em>/wombat/foo.2006-23.log</em>
+ will contain the actual logging output.
+ Logging for the 24th week of 2006 will be output to
+ <em>/wombat/foo.2006-24.log</em>
+ until it is rolled over at the beginning of the next week.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>
+ <em>/wombat/foo.%d{yyyy-MM-dd-a}.log</em>
+ </td>
+ <td>Rollover at midnight and midday of each day.</td>
+ <td>
+ During the first 12 hours of November 3rd, 2006, the logging
+ will be output to <em>/wombat/foo.2006-11-03-AM.log</em>.
+ After noon, and until midnight, the logging will be output to
+ <em>/wombat/foo.2006-11-03-PM.log</em>.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>
+ <em>/wombat/foo.%d{yyyy-MM-dd_HH}.log</em>
+ </td>
+ <td>Rollover at the top of each hour.</td>
+ <td>
+ Between 11.00,001 and 11.59,999, on November 3rd, 2006, the logging
+ will be output to <em>/wombat/foo.2006-11-03_11.log</em>.
+ After that, and until 12.59,999, the logging will be output to
+ <em>/wombat/foo.2006-11-03_12.log</em>.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>
+ <em>/wombat/foo.%d{yyyy-MM-dd_HH-mm}.log</em>
+ </td>
+ <td>Rollover at the beggining of every minute.</td>
+ <td>
+ Between 11.32,001 and 11.32,999, on November 3rd, 2006, the logging
+ will be output to <em>/wombat/foo.2006-11-03_11-32.log</em>.
+ After that, and until 12.33,999, the logging will be output to
+ <em>/wombat/foo.2006-11_12-33.log</em>.
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ Any characters in the pattern outside the ranges <em>['a'..'z']</em> and <em>['A'..'Z']</em>
+ will be treated as quoted text. For instance, characters like <em>'.'</em>, <em>' '</em>,
+ <em>'#'</em> and <em>'@'</em> will appear in the resulting time text even when they are not
+ enclosed within single quotes. Nevertheless, we would recommend against
+ using the colon <em>":"</em> character anywhere within the
+ <span class="option">FileNamePattern</span> option.
+ The text before the colon is interpreted as the protocol specification of a
+ URL, which is most probably not what you intend. The slash <em>"/"</em> character, a
+ common date field separator, must also be avoided. It is taken as a file
+ separator causing the rollover operation to fail because the target file cannot
+ be created. Although less common, the backslash character <em>"\"</em> is equally troublesome.
+ </p>
+
+ <p>
+ Just like <code>FixedWindowRollingPolicy</code>, <code>TimeBasedRollingPolicy</code>
+ supports automatic file compression.
+ This feature is enabled if the value of the <span class="option">FileNamePattern</span> option
+ ends with <em>.gz</em> or <em>.zip</em>.
+ </p>
+ <table class="bodyTable">
+ <tr class="b">
+ <th><span class="option">FileNamePattern</span></th>
+ <th>Rollover schedule</th>
+ <th>Example</th>
+ </tr>
+ <tr class="a">
+ <td><em>/wombat/foo.%d.gz</em></td>
+ <td>Daily rollover (at midnight) with automatic GZIP compression of the
+ arcived files.</td>
+ <td>During November 23rd, 2004, logging output will go to
+ the file <em>/wombat/foo.2004-11-23</em>. However, at midnight that
+ file will be compressed to become <em>/wombat/foo.2004-11-23.gz</em>.
+ For the 24th of November, logging output will be directed to
+ <em>/wombat/folder/foo.2004-11-24</em> until its rolled over at the
+ beginning of the next day.
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ As we have seen, the <span class="option">FileNamePattern</span> serves two purposes. First,
+ by studying the pattern, logback computes the requested rollover periodicity. Second,
+ it computes each files' name based on the pattern. It is entirely possible for two different
+ file name patterns to specify the same periodicity.
+ The date patterns <em>yyyy-MM</em> and <em>yyyy at MM</em> both specify monthly
+ rollover periodicity, although the rolled files will carry different names.
+ </p>
+
+ <p>
+ Given the use of the <span class="option">FileNamePattern</span>, we see that the
+ <code>TimeBasedRollingPolicy</code> is responsible for the rollover as well as for
+ the triggering of said rollover. Therefore, <code>TimeBasedTriggeringPolicy</code>
+ implements both <code>RollingPolicy</code> and <code>TriggeringPolicy</code>
+ interfaces. A <code>RollingFileAppender</code> that uses
+ <code>TimeBasedRollingPolicy</code> can be started and used correctly even
+ if its configuration does not contain any reference to a <code>TriggeringPolicy</code>.
+ </p>
+
+ <p>
+ With <code>TimeBasedRollingPolicy</code>, it is possible to
+ decouple the location of the active log file and the archived log files
+ </p>
+ <p>
+ The <span class="option">File</span> option defines the log file
+ for the current period whereas <em>archived files</em> are those files
+ which have been rolled over in previous periods.
+ </p>
+ <p>
+ By setting the <span class="option">File</span> option you can
+ decouple the location of the active log file and the location
+ of the archived log files. The actual logging will be done in the
+ file specified by the <span class="option">File</span> option. This way,
+ the active file name will never change. By not setting the
+ <span class="option">File</span> option, logback uses the
+ <span class="option">FileNamePattern</span> to name the active file,
+ whose name will change each time a rollover occurs.
+ </p>
+
+ <p>
+ For various efficiency reasons, rollovers are not time-driven
+ but depend on the arrival of logging events. For example, on 8th of March 2002,
+ assuming the <span class="option">FileNamePattern</span> is set to
+ <em>yyyy-MM-dd</em> (daily rollover), the arrival of the first
+ event after midnight will trigger rollover. If there are no logging events
+ during, say 23 minutes and 47 seconds after midnight,
+ then rollover will occur at 00:23'47 AM on March 9th and not at 0:00 AM.
+ Thus, depending on the arrival rate of events, rollovers might be triggered
+ with some latency. However, regardless of the delay, the rollover algorithm
+ is known to be correct, in the sense that all logging events generated
+ during a certain period will be output in the correct file delimiting that period.
+ </p>
+
+ <p>Here is a sample configuration of a <code>RollingFileAppender</code> which
+ uses a <code>TimeBasedRollingPolicy</code>
+ </p>
+
+<em>Example 4.5: Sample configuration of a <code>RollingFileAppender</code> using a
+<code>TimeBasedRollingPolicy</code> (logback-examples/src/main/java/chapter4/conf/logback-RollingTimeBased.xml)</em>
+<div class="source"><pre><configuration>
+ <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <File>logFile.log</File>
+ <b><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>logFile.%d{yyyy-MM-dd}.log</FileNamePattern>
+ </rollingPolicy></b>
+
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration></pre></div>
+
+ <a name="TriggeringPolicy"></a>
+ <h3>Triggering policies</h3>
+
+ <p><a href="../xref/ch/qos/logback/core/rolling/TriggeringPolicy.html"><code>TriggeringPolicy</code></a>
+ implementations are responsible for instructing
+ the <code>RollingFileAppender</code> to rollover.</p>
+
+ <p>The <code>TriggeringPolicy</code> interface is pretty simple.</p>
+
+<div class="source"><pre>package ch.qos.logback.core.rolling;
+
+import java.io.File;
+import ch.qos.logback.core.spi.LifeCycle;
+
+public interface TriggeringPolicy extends LifeCycle {
+
+ <b>public boolean isTriggeringEvent(final File activeFile, final Object event);</b>
+}</pre></div>
+
+ <p>
+ The
+ <code>isTriggeringEvent()</code>
+ method takes the active file, and the currently processed
+ logging event. It's implementation decides, based on these
+ parameters, whether the rollover must occur or not, by
+ returning a boolean value.
+ </p>
+
+ <a name="SizeBasedTriggeringPolicy"></a>
+ <h4>SizeBasedTriggeringPolicy</h4>
+
+ <p>
+ <a href="../xref/ch/qos/logback/core/rolling/SizeBasedTriggeringPolicy.html">
+ <code>SizeBasedTriggeringPolicy</code></a>
+ looks at size of the file being currently written to. If it
+ grows larger than the specified size, the
+ <code>FileAppender</code> using the
+ <code>SizeBasedTriggeringPolicy</code>
+ will proceed to the rollover of the current file and log to
+ a new one.
+ </p>
+
+ <p>
+ This <code>TriggeringPolicy</code>
+ only accepts one parameter, that is the
+ <span class="option">MaxFileSize</span>
+ option. This option's default value is 10 MB.
+ </p>
+
+ <p>
+ The <span class="option">MaxFileSize</span>
+ option can be specified in a simple and easy way, by
+ specifying the unit that should be used. One can enter any
+ numeric value, with three possible units, namely <em>KB</em>,
+ <em>MB</em> and <em>GB</em>. Consequently, values like
+ <em>5MB</em>, <em>500KB</em> or <em>2GB</em> are all valid.
+ </p>
+ <p>
+ Here is a sample configuration with a <code>RollingFileAppender</code>
+ using a <code>SizeBasedTriggeringPolicy</code>.
+ </p>
+
+<em>Example 4.6: Sample configuration of a <code>RollingFileAppender</code> using a
+<code>SizeBasedTriggeringPolicy</code> (logback-examples/src/main/java/chapter4/conf/logback-RollingSizeBased.xml)</em>
+<div class="source"><pre><configuration>
+ <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <File>testFile.log</File>
+ <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <FileNamePattern>testFile.%i.log.zip</FileNamePattern>
+ <MinIndex>1</MinIndex>
+ <MaxIndex>3</MaxIndex>
+ </rollingPolicy>
+
+ <b><triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <MaxFileSize>5MB</MaxFileSize>
+ </triggeringPolicy></b>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ <code>TriggeringPolicy</code> implementations do not only serve with
+ <code>RollingFileAppender</code> objects. They can also be used to tell
+ <code>SMTPAppender</code>, which will be covered soon, when to send an email
+ containing the last logging events.
+ </p>
+
+ <p>
+ In that case, the <code>isTriggeringEvent()</code> method takes <em>null</em>
+ as its first parameter (of type <code>File</code>) and takes the logging event
+ as its second parameter. It is based on that last element that the decision is
+ made to send the email or not. By default, a <code>TriggeringPolicy</code> is
+ included with <code>SMTPAppender</code> that triggers the mail each time an event
+ with a <code>Level</code> of <em>ERROR</em> or more is issued.
+ </p>
+
+ <a name="Classic"></a>
+ <h2>Logback Classic</h2>
+
+
+ <p>While logging event are declared as <code>Object</code> in logback core,
+ they are instances of the <code>LoggingEvent</code> class in logback classic.</p>
+
+ <a name="SocketAppender"></a>
+ <h3>SocketAppender</h3>
+
+ <p>
+ The appenders covered this far were only able to log on local resources.
+ In contrast, the <a href="../xref/ch/qos/logback/classic/net/SocketAppender.html">
+ <code>SocketAppender</code></a> is designed to log to a
+ remote entity by transmitting serialized <code>LoggingEvent</code> objects over the wire.
+ Remote logging is non-intrusive as far as the logging event is concerned.
+ On the receiving end after de-serialization, the event can be logged as
+ if it were generated locally. Multiple <code>SocketAppender</code> instances
+ running of different machines can direct their logging output
+ to a central log server whose format is fixed.
+ <code>SocketAppender</code> does not admit an
+ associated layout because it sends serialized events to a remote server.
+ <code>SocketAppender</code> operates above the
+ <em>Transmission Control Protocol (TCP)</em>
+ layer which provides a reliable, sequenced, flow-controlled end-to-end octet stream.
+ Consequently, if the remote server is reachable, then log events
+ will eventually arrive there. Otherwise, if the remote server is down or
+ unreachable, the logging events will simply be dropped. If and when the server
+ comes back up, then event transmission will be resumed transparently.
+ This transparent reconnection is performed by a connector thread which
+ periodically attempts to connect to the server.
+ </p>
+
+ <p>
+ Logging events are automatically buffered by the native TCP implementation.
+ This means that if the link to server is slow but still faster than the
+ rate of event production by the client, the client will not be affected by
+ the slow network connection. However, if the network connection is slower
+ then the rate of event production, then the client can only progress at the
+ network rate. In particular, in the extreme case where the network link
+ to the server is down, the client will be eventually blocked.
+ Alternatively, if the network link is up, but the server is down,
+ the client will not be blocked, although the log events will be
+ lost due to server unavailability.
+ </p>
+
+ <p>
+ Even if a <code>SocketAppender</code> is no longer attached to any logger,
+ it will not be garbage collected in the presence of a connector thread.
+ A connector thread exists only if the connection to the server is down.
+ To avoid this garbage collection problem, you should close the <code>SocketAppender</code>
+ explicitly. Long lived applications which create/destroy many
+ <code>SocketAppender</code> instances should be aware of this
+ garbage collection problem. Most other applications can safely ignore it.
+ If the JVM hosting the <code>SocketAppender</code> exits before the
+ <code>SocketAppender</code> is closed, either explicitly or subsequent
+ to garbage collection, then there might be untransmitted data in the
+ pipe which may be lost. This is a common problem on Windows based systems.
+ To avoid lost data, it is usually sufficient to <code>close()</code> the
+ <code>SocketAppender</code> either explicitly or by calling the
+ <code>LoggerContext</code>'s <code>shutdownAndReset()</code> method before exiting the application.
+ </p>
+
+ <p>
+ The remote server is identified by the <span class="option">RemoteHost</span> and
+ <span class="option">Port</span> options.
+ <code>SocketAppender</code> options are listed in the following table.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">IncludeCallerData</span></b></td>
+ <td><code>boolean</code></td>
+ <td>
+ <p>
+ The <span class="option">IncludeCallerData</span> option takes a boolean value.
+ If true, the caller data will be available to the remote host.
+ By default no caller data is sent to the server.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">Port</span></b></td>
+ <td><code>int</code></td>
+ <td>
+ <p>
+ The port number of the remote server.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">ReconnectionDelay</span></b></td>
+ <td><code>int</code></td>
+ <td>
+ The <span class="option">ReconnectionDelay</span> option takes a
+ positive integer representing the number of milliseconds to wait between
+ each failed connection attempt to the server.
+ The default value of this option is 30'000 which corresponds to 30 seconds.
+ Setting this option to zero turns off reconnection capability.
+ Note that in case of successful connection to the server, there will be no
+ connector thread present.
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">RemoteHost</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ The host name of the server.
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ The standard logback distribution includes a simple log server application named
+ <code>ch.qos.logback.classic.net.SimpleSocketServer</code> that can service multiple
+ <code>SocketAppender</code> clients. It waits for logging events from
+ <code>SocketAppender</code> clients. After reception by
+ <code>SimpleSocketServer</code>, the events are logged according to local server policy.
+ The <code>SimpleSocketServer</code> application takes two parameters:
+ port and configFile; where port is the port to listen on and configFile is
+ configuration script in XML format.
+ </p>
+
+ <p>
+ Assuming you are in the <em>logback-examples/</em> directory,
+ start <code>SimpleSocketServer</code> with the following command:
+ </p>
+
+<div class="source"><pre>java ch.qos.logback.classic.net.SimpleSocketServer 6000 \
+ src/main/java/chapter4/socket/server1.xml
+</pre></div>
+
+ <p>
+ where 6000 is the port number to listen on and <em>server1.xml</em> is a
+ configuration script that adds a <code>ConsoleAppender</code> and a
+ <code>RollingFileAppender</code> to the root logger.
+ After you have started <code>SimpleSocketServer</code>, you can send it
+ log events from multiple clients using <code>SocketAppender</code>.
+ The examples associated with this manual include two such clients:
+ <code>chapter4.SocketClient1</code> and <code>chapter4.SocketClient2</code>
+ Both clients wait for the user to type a line of text on the console.
+ The text is encapsulated in a logging event of level debug and then sent
+ to the remote server. The two clients differ in the configuration of the
+ <code>SocketAppender</code>. <code>SocketClient1</code> configures the appender
+ programmatically while <code>SocketClient2</code> requires a configuration file.
+ </p>
+
+ <p>
+ Assuming <code>SimpleSocketServer</code> is running on the local host,
+ you connect to it with the following command:
+ </p>
+
+<div class="source"><pre>java chapter4.socket.SocketClient1 localhost 6000</pre></div>
+
+ <p>
+ Each line that you type should appear on the console of the
+ <code>SimpleSocketServer</code>
+ launched in the previous step. If you stop and restart the
+ <code>SimpleSocketServer</code>
+ the client will transparently reconnect to the new server
+ instance, although the events generated while disconnected
+ will be simply (and irrevocably) lost.
+ </p>
+
+ <p>
+ Unlike
+ <code>SocketClient1</code>, the sample application
+ <code>SocketClient2</code> does not configure logback by itself.
+ It requires a configuration file in XML format.
+ The configuration file <em>client1.xml</em>
+ shown below creates a <code>SocketAppender</code>
+ and attaches it to the root logger.
+ </p>
+
+ <em>Example 4.7: SocketAppender configuration (logback-examples/src/main/java/chapter4/socket/client1.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="SOCKET" class="ch.qos.logback.classic.net.SocketAppender">
+ <RemoteHost>${host}</RemoteHost>
+ <Port>${port}</Port>
+ <ReconnectionDelay>10000</ReconnectionDelay>
+ <IncludeCallerData>${includeCallerData}</IncludeCallerData>
+ </appender>
+
+ <root>
+ <level value ="debug"/>
+ <appender-ref ref="SOCKET" />
+ </root>
+
+</configuration></pre></div>
+
+
+ <p>
+ Note that in the above configuration scripts the values for the
+ <span class="option">RemoteHost</span>, <span class="option">Port</span> and
+ <span class="option">IncludeCallerData</span> options
+ are not given directly but as substituted variable keys. The values for the variables
+ can be specified as system properties:
+ </p>
+
+<div class="source"><pre>java -Dhost=localhost -Dport=6000 -DincludeCallerData=false \
+ chapter4.socket.SocketClient2 src/main/java/chapter4/socket/client1.xml
+</pre></div>
+
+ <p>
+ This command should give similar results to the previous
+ <code>SocketClient1</code>
+ example.
+ </p>
+
+ <p>
+ Allow us to repeat for emphasis that serialization of logging events is not
+ intrusive. A de-serialized event carries the same information as any other
+ logging event. It can be manipulated as if it were generated locally;
+ except that serialized logging events by default do not include caller
+ data. Here is an example to illustrate the point. First, start
+ <code>SimpleSocketServer</code> with the following command:
+ </p>
+
+<div class="source"><pre> java ch.qos.logback.classic.net.SimpleSocketServer 6000 \
+ src/main/java/chapter4/socket/server2.xml
+</pre></div>
+
+ <p>
+ The configuration file <em>server2.xml</em> creates a <code>ConsoleAppender</code>
+ whose layout outputs the callers file name and line number along with other
+ information. If you run <code>SocketClient2</code> with the configuration file
+ <em>client1.xml</em> as previously, you will notice that the output on the
+ server side will contain two question marks between parentheses instead of
+ the file name and the line number of the caller:
+ </p>
+
+<div class="source"><pre>2006-11-06 17:37:30,968 DEBUG [Thread-0] [?:?] chapter4.socket.SocketClient2 - Hi</pre></div>
+
+ <p>
+ The outcome can be easily changed by instructing the <code>SocketAppender</code>
+ to include caller data by setting the <span class="option">IncludeCallerData</span>
+ option to true. Using the following command will do the trick:
+ </p>
+
+<div class="source"><pre>java -Dhost=localhost -Dport=6000 -DincludeCallerData=true \
+ chapter4.socket.SocketClient2 src/main/java/chapter4/socket/client1.xml
+</pre></div>
+
+ <p>
+ As deserialized events can be handled in the same way as locally
+ generated events, they even can be sent to a second server for further treatment.
+ As an exercise, you may wish to setup two servers where the first server
+ tunnels the events it receives from its clients to a second server.
+ </p>
+
+ <a name="JMSAppenderBase"></a>
+ <h3>JMSAppenderBase</h3>
+
+ <p>
+ The <a href="../xref/ch/qos/logback/core/net/JMSAppenderBase.html">
+ <code>JMSAppenderBase</code></a> subclasses conceptually accomplishes
+ the same task as the <code>SocketAppender</code> but as the name
+ suggests it is based on the JMS API instead of TCP sockets.
+ JMS or the Java Message Service API
+ provides an abstraction for Message-Oriented Middleware (MOM) products.
+ One of the key architectural concepts in JMS is the decoupling of message
+ producers and message consumers. Senders do not have to wait for receivers
+ to handle messages and conversely the receiver consumes messages as they
+ become available; messages are said to be delivered asynchronously. Just as
+ importantly, consumers as well as producers can be added or removed at will
+ to a JMS channel. The set of the message producers and message consumers can
+ vary independently and transparently over time, with both sets oblivious
+ to each other.
+ </p>
+
+ <p>
+ The JMS specification provides for two types of messaging models,
+ publish-and-subscribe and point-to-point queuing. Logback supports the former
+ model with <code>JMSTopicAppender</code> and the latter with <code>JMSQueueAppender</code>
+ Both appenders extend the <code>JMSAppenderBase</code> class and
+ publish serialized events to a topic or queue specified by the user.
+ </p>
+
+ <p>
+ One or more <code>JMSTopicSink</code> or <code>JMSQueueSink</code> applications
+ can register to a JMS server and consume the serialized events.
+ The consumer of JMS appenders generated events need not be only <code>JMSTopicSink</code>
+ or <code>JMSQueueSink</code> applications. Any application or MessageDrivenBean
+ capable of subscribing to the appropriate topic or queue and consuming serialized
+ logging event messages would be suitable.
+ Additional consumers could be quickly built based on the <code>JMSTopicSink</code> or
+ <code>JMSQueueSink</code> model.
+ </p>
+
+ <p>
+ Here are <code>JMSAppenderBase</code>'s options:
+ </p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">InitialContextFactoryName</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ The class name of the initial JNDI context factory. There is no need
+ to set this option if you have a properly configured <em>jndi.properties</em>
+ file or if <code>JMSAppenderBase</code> subclass is running
+ within an application server.
+ </p>
+ <p>
+ If you set this option, you should
+ also set the <span class="option">ProviderURL</span> option.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">ProviderURL</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ This option specifies configuration information for the
+ JNDI service provider. The value of the property should contain a
+ URL string (e.g. <em>ldap://somehost:389</em>).
+ </p>
+ <p>
+ The <span class="option">ProviderURL</span> option is taken into
+ account only if the <span class="option">InitialContextFactoryName</span>
+ option is specified. It is ignored otherwise.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">URLPkgPrefixes</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ This option contains the list of package prefixes to
+ use when loading in URL context factories. The value of the
+ property should be a colon-separated list of package
+ prefixes for the class name of the URL context factory class.
+ </p>
+ <p>
+ For JBoss the value of this option should be:
+ org.jboss.naming:org.jnp.interfaces
+ This option is not needed under Weblogic.
+ </p>
+ <p>
+ This option is taken into account only if the
+ <span class="option">InitialContextFactoryName</span>
+ option is specified. It is ignored otherwise.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">SecurityPrincipalName</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ The security principal name to use when accessing the JNDI namespace.
+ This option is usually not required.
+ </p>
+ <p>
+ This option is taken into account only if the
+ <span class="option">InitialContextFactoryName</span>
+ option is specified. It is ignored otherwise.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td>
+ <b>
+ <span class="option">SecurityCredentials</span>
+ </b>
+ </td>
+ <td>
+ <code>String</code>
+ </td>
+ <td>
+ <p>
+ The security credentials to use when accessing the
+ JNDI namespace. This option is usually not required.
+ </p>
+ <p>
+ This option is taken into account only if the
+ <span class="option">
+ InitialContextFactoryName
+ </span>
+ option is specified. It is ignored otherwise.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td>
+ <b>
+ <span class="option">UserName</span>
+ </b>
+ </td>
+ <td>
+ <code>String</code>
+ </td>
+ <td>
+ <p>
+ The username to use when creating a topic or queue connection.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td>
+ <b>
+ <span class="option">Password</span>
+ </b>
+ </td>
+ <td>
+ <code>String</code>
+ </td>
+ <td>
+ <p>
+ The password to use when creating a topic or queue connection.
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ JMS topics, queues and connection factories are administered objects that are obtained
+ using the JNDI API. This in turn implies the necessity of retrieving a JNDI Context.
+ There are two common methods for obtaining a JNDI Context. If a file resource named
+ <em>jndi.properties</em> is available to the JNDI API, it will use the information
+ found therein to retrieve an initial JNDI context.
+ To obtain an initial context, one simply calls:
+ </p>
+
+<div class="source"><pre>InitialContext jndiContext = new InitialContext();</pre></div>
+
+ <p>
+ Calling the no-argument <code>InitialContext()</code> constructor will also work
+ from within Enterprise Java Beans (EJBs).
+ Indeed, it is part of the EJB contract for application servers to provide
+ each enterprise bean an environment naming context (ENC).
+ </p>
+
+ <p>
+ In the second approach, several predetermined properties are specified.
+ These properties are passed to the <code>InitialContext</code> constructor
+ to connect to the naming service provider.
+ For example, to connect to an
+ <a href="http://www.activemq.org/site/home.html"><code>ActiveMQ</code></a>
+ naming server one would write:
+ </p>
+
+<div class="source"><pre>Properties env = new Properties();
+env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
+env.put(Context.PROVIDER_URL, "tcp://<em>hostname</em>:61616");
+Context ctx = new InitialContext(env);</pre></div>
+
+ <p>
+ where <em>hostname</em> is the host where the ActiveMQ server is running.
+ </p>
+
+ <p>
+ Other JNDI providers will obviously require different values.
+ As mentioned previously, the initial JNDI context can be obtained by calling
+ the no-argument <code>InitialContext()</code> constructor from within EJBs.
+ Only clients running in a separate JVM need to be concerned about
+ the <em>jndi.properties</em> file or setting the different properties
+ before calling <code>InitialContext</code> constructor taking a
+ Properties (i.e. Hashtable) parameter.
+ </p>
+
+ <h4>Comments on JMS appenders</h4>
+
+ <p>
+ Transmitting a packet of information using JMS is certain to be substantially
+ slower then sending the same packet using raw TCP sockets. JMS vendors bragging
+ about the performance of their messaging platform tend to omit this simple fact.
+ Guaranteed store and forward messaging comes at a hefty price.
+ In return for increased cost, JMS messaging provides decoupling of
+ sender and receiver. As long as the JMS provider is reachable, messages
+ will eventually arrive at destination.
+ However, what if the JMS server is down or simply unreachable?
+ </p>
+
+ <p>
+ According to the JMS specification, producers can mark a message as either
+ persistent or non-persistent. The persistent delivery mode instructs the JMS provider
+ to log the message to stable storage as part of the client's send operation, allowing
+ the message to survive provider crashes. JMS appenders do not set the delivery
+ mode of messages it produces because according to the JMS specification,
+ the delivery mode is considered as an administered property.
+ </p>
+
+ <p>
+ Once a message reaches the JMS provider, the provider assumes the responsibility
+ of delivering it to its destination, relieving the client from this chore.
+ What if the JMS server is unreachable? The JMS API provides an
+ <code>ExceptionListener</code> interface to deal with this situation.
+ When the client runtime of the JMS provider detects a lost connection to the JMS server,
+ it calls the <code>onException()</code> method of the registered
+ <code>ExceptionListener</code>. Once notified of the problem, client code can attempt
+ to reestablish the connection. According to the section 4.3.8 of the JMS specification,
+ the provider should attempt to resolve connection problems prior to notifying the client.
+ The JMS appenders do not implement the <code>ExceptionListener</code> interface.
+ </p>
+
+ <a name="JMSTopicAppender"></a>
+ <h3>JMSTopicAppender</h3>
+
+ <p>
+ The <a href="../xref/ch/qos/logback/classic/net/JMSTopicAppender.html">
+ <code>JMSTopicAppender</code></a> acts as a message producer to a publish and subscribe
+ Topic.
+ </p>
+
+ <p>
+ Its most important method, <code>doAppend()</code> is listed below:
+ </p>
+
+<div class="source"><pre>public void append(LoggingEvent event) {
+ if (!isStarted()) {
+ return;
+ }
+
+ try {
+ ObjectMessage msg = topicSession.createObjectMessage();
+
+ msg.setObject(event);
+ topicPublisher.publish(msg);
+ successiveFailureCount = 0;
+ } catch (Exception e) {
+ successiveFailureCount++;
+ if (successiveFailureCount > SUCCESSIVE_FAILURE_LIMIT) {
+ stop();
+ }
+ addError("Could not publish message in JMSTopicAppender [" + name + "].", e);
+ }
+}</pre></div>
+
+ <p>
+ The <code>isStarted()</code> method allows the appender to check whether
+ prerequisite conditions for its proper functioning, in particular the
+ availability of a valid and open <code>TopicConnection</code> and a
+ <code>TopicSession</code>, are fulfilled. If that is not the case,
+ the append method returns without performing any work.
+ If the prerequisite conditions are fulfilled, then the method
+ proceeds to publish the logging event. This is done by obtaining a
+ <code>javax.jms.ObjectMessage</code> from the <code>TopicSession</code>
+ and then setting its payload to the logging event received as
+ the input parameter. Once the payload of the message is set, it is
+ published. The fact that <code>LoggingEvent</code> is serializable
+ has its importance, as only Serializable objects can be
+ transported within an <code>ObjectMessage</code>.
+ </p>
+
+ <p>
+ In summary, the <code>JMSTopicAppender</code> broadcasts messages consisting
+ of a serialized <code>LoggingEvent</code> payload over a user-specified
+ JMS topic. These events can be processed by a
+ <a href="../xref/ch/qos/logback/classic/net/JMSTopicSink.html">
+ <code>JMSTopicSink</code></a>
+ or a similar consumer. According to JMS specification, the provider
+ will asynchronously call the <code>onMessage()</code> of duly registered
+ and subscribed <code>javax.jms.MessageListener</code> objects.
+ The <code>onMessage()</code> method in <code>JMSTopicSink</code>
+ is implemented as follows:
+ </p>
+
+<div class="source"><pre>public void onMessage(javax.jms.Message message) {
+ LoggingEvent event;
+ try {
+ if (message instanceof ObjectMessage) {
+ ObjectMessage objectMessage = (ObjectMessage) message;
+ event = (LoggingEvent) objectMessage.getObject();
+ Logger log = (Logger) LoggerFactory.getLogger(event.getLoggerRemoteView().getName());
+ log.callAppenders(event);
+ } else {
+ logger.warn("Received message is of type " + message.getJMSType()
+ + ", was expecting ObjectMessage.");
+ }
+ } catch (JMSException jmse) {
+ logger.error("Exception thrown while processing incoming message.", jmse);
+ }
+}</pre></div>
+
+ <p>
+ The <code>onMessage()</code> method begins by retrieving the logging event's payload.
+ It then obtains a Logger with the same name as the logger name of the incoming event.
+ The event is then logged through this logger as if it were generated locally,
+ by calling its <code>callAppenders()</code> method. The <code>SocketNode</code> class used by
+ <code>SimpleSocketServer</code> handles incoming logging events essentially in the same way.
+ </p>
+
+ <p>
+ Some options are proper to <code>JMSTopicAppender</code>. They are
+ listed below.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">TopicConnectionFactoryBindingName</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ The name of the topic factory. There is no default value for this mandatory option.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">TopicBindingName</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ The name of the topic to use. There is no default value for this mandatory option.
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ <code>JMSTopicAppender</code> is rather straightforward to configure:
+ </p>
+
+ <em>Example 4.8: JMSTopicAppender configuration (logback-examples/src/main/java/chapter4/conf/logback-JMSTopic.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="Topic"
+ class="ch.qos.logback.classic.net.JMSTopicAppender">
+ <InitialContextFactoryName>
+ org.apache.activemq.jndi.ActiveMQInitialContextFactory
+ </InitialContextFactoryName>
+ <ProviderURL>tcp://localhost:61616</ProviderURL>
+ <TopicConnectionFactoryBindingName>
+ ConnectionFactory
+ </TopicConnectionFactoryBindingName>
+ <TopicBindingName>MyTopic</TopicBindingName>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="Topic" />
+ </root>
+</configuration></pre></div>
+
+ <a name="JMSQueueAppender"></a>
+ <h3>JMSQueueAppender</h3>
+
+ <p>
+ The <a href="../xref/ch/qos/logback/classic/net/JMSQueueAppender.html">
+ <code>JMSQueueAppender</code></a> acts as a message producer to a point-to-point
+ Queue.
+ </p>
+
+ <p>
+ It works in a very similar manner to the <code>JMSTopicAppender</code>.
+ </p>
+
+ <p>
+ Some options are proper to <code>JMSQueueAppender</code>. They are
+ listed below.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">QueueConnectionFactoryBindingName</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ The name of the queue factory. There is no default value for this mandatory option.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">QueueBindingName</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ The name of the queue to use. There is no default value for this mandatory option.
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ A typical <code>JMSQueueAppender</code> configuration file looks very
+ similar to that of a <code>JMSTopicAppender</code>.
+ </p>
+ <em>Example 4.9: JMSQueueAppender configuration (logback-examples/src/main/java/chapter4/conf/logback-JMSQueue.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="Queue"
+ class="ch.qos.logback.classic.net.JMSQueueAppender">
+ <InitialContextFactoryName>
+ org.apache.activemq.jndi.ActiveMQInitialContextFactory
+ </InitialContextFactoryName>
+ <ProviderURL>tcp://localhost:61616</ProviderURL>
+ <QueueConnectionFactoryBindingName>
+ ConnectionFactory
+ </QueueConnectionFactoryBindingName>
+ <QueueBindingName>MyQueue</QueueBindingName>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="Queue" />
+ </root>
+</configuration></pre></div>
+
+ <a name="SMTPAppender"></a>
+ <h3>SMTPAppender</h3>
+
+ <p>
+ The <a href="../xref/ch/qos/logback/classic/net/SMTPAppender.html"><code>SMTPAppender</code></a>
+ accumulates logging events in a fixed-size buffer and sends them in an email when a
+ user specified event occurs.
+ By default, the email is sent as the reception of an event
+ of level <em>ERROR</em> or higher.
+ </p>
+
+ <p>
+ The various options for <code>SMTPAppender</code> are summarized in the following table.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">SMTPHost</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ The host name of the SMTP server. This parameter is mandatory.
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">To</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ The email address of the recipient. Multiple recipients can
+ be specified by using several <To> elements.
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">From</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ The stated originator of the email messages sent by
+ <code>SMTPAppender</code>.
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">Subject</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>
+ The subject of the email. The String can contain a <code>Pattern</code>
+ that <code>PatternLayout</code> uses. In that case, the subject
+ is created just before the transmission of the email, with information
+ about the last logging event that was issued.
+ </p>
+ <p>
+ For example, setting <em>Log: %logger - %msg</em> as the
+ <span class="option">Subject</span> option will send an email with
+ the logger name and message string of the event that triggered the
+ email transmission.
+ </p>
+ <p>
+ By default, <code>SMTPAppender</code> will form a subject with
+ logger name and the message of the last logging event.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b><span class="option">BufferSize</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ The <span class="option">BufferSize</span> option takes a positive
+ integer representing the maximum number of logging events to collect in a
+ cyclic buffer. When the <span class="option">BufferSize</span> is reached,
+ oldest events are deleted as new events are added to the buffer.
+ The default size of the cyclic buffer is 512.
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b><span class="option">Evaluator</span></b></td>
+ <td><code>String</code></td>
+ <td>
+ <p>This option is declared by creating a new <code><EventEvaluator/></code>
+ element. The name of the class that the user wishes to use as the
+ <code>SMTPAppender</code>'s <code>Evaluator</code> can be given
+ by adding an attribute to the newly created element.
+ </p>
+ <p>
+ More details about the use of event evaluators with <code>SMTPAppender</code>
+ follow further down this document.
+ </p>
+ <p>In the absence of this option,
+ <code>SMTPAppender</code> is assigned a default event evaluator which triggers
+ email transmission as a response to any event of level <em>ERROR</em> or higher.
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ The SMTPAppender keeps only the last <span class="option">BufferSize</span> logging events
+ in its cyclic buffer, throwing away older events when its buffer becomes full.
+ The number of logging events delivered in any e-mail sent by <code>SMTPAppender</code>
+ is upper-bounded by <span class="option">BufferSize</span>. This keeps memory
+ requirements bounded while still delivering a reasonable amount of application context.
+ </p>
+
+ <p>
+ The <code>SMTPAppender</code> relies on the JavaMail API.
+ It has been tested with JavaMail API version 1.4.
+ The JavaMail API requires the JavaBeans Activation Framework package.
+ You can download the <a href="http://java.sun.com/products/javamail/">JavaMail API</a>
+ and the <a href="http://java.sun.com/beans/glasgow/jaf.html">Java-Beans Activation Framework</a>
+ from their respective websites.
+ Make sure to place these two jar files in the classpath before
+ trying the following examples.
+ </p>
+
+ <p>
+ A sample application called <code>chapter4.mail.EMail</code> takes two parameters.
+ The first parameter is an integer corresponding to the number of logging events
+ to generate. The second parameter is the logback configuration file in XML format.
+ The last logging event generated by chapter4.mail.Email application is always an
+ <em>ERROR</em> event which triggers the transmission of an email message.
+ </p>
+
+ <p>
+ Here is a sample configuration file you can supply to chapter4.mail.Email:
+ </p>
+
+<em>Example 4.10: A sample <code>SMTPAppender</code> configuration (logback-examples/src/main/java/chapter4/mail/mail1.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
+ <SMTPHost>ADDRESS-OF-YOUR-SMTP-HOST</SMTPHost>
+ <To>DESTINATION-EMAIL</To>
+ <From>SENDER-EMAIL</From>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%date %-5level %logger{35} - %message%n</Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value ="debug"/>
+ <appender-ref ref="EMAIL" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ Before trying out <code>chapter4.mail.Email</code> application with the above
+ configuration file, you must set the <span class="option">SMTPHost</span>,
+ <span class="option">To</span> and <span class="option">From</span> options
+ to values appropriate for your environment. Once you have set the proper values,
+ change directory to <em>logback-examples</em> and execute the following command:
+ </p>
+
+<div class="source"><pre>java chapter4.mail.EMail 300 src/main/java/chapter4/mail/mail.xml</pre></div>
+
+ <p>
+ The chosen recipient should see an email message containing 300 logging events
+ formatted by <code>PatternLayout</code>.
+ </p>
+
+ <p>
+ In another configuration file <em>mail2.xml</em>, the values for the
+ <span class="option">SMTPHost</span>, <span class="option">To</span>
+ and <span class="option">From</span> options are determined by variable
+ substitution. Here is the relevant part of <em>mail2.xml</em>.
+ </p>
+
+<div class="source"><pre>
+ <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
+ <SMTPHost>${smtpHost}</SMTPHost>
+ <To>${to}</To>
+ <From>${from}</From>
+ <layout class="ch.qos.logback.classic.html.HTMLLayout"/>
+ </appender>
+</pre></div>
+
+ <p>
+ You can supply the various values on the command line:
+ </p>
+
+<div class="source"><pre>java -Dfrom=source at xyz.com -Dto=recipient at xyz.com
+ -DsmtpHost=some_smtp_host src/main/java/chapter4.mail.EMail 10000 chapter4/mail/mail2.xml
+</pre></div>
+
+ <p>
+ Be sure to replace with the correct values appropriate for your environment.
+ </p>
+
+ <p>
+ Given that the default size of the cyclic buffer is 512,
+ the recipient should see an email message containing 512 events conveniently
+ formatted in an HTML table. Note that this run of the <code>chapter4.mail.Email</code>
+ application generated 10'000 events of which only the last 512 were included in the email.
+ </p>
+
+ <p>
+ By default, the <code>SMTPAppender</code> will initiate the transmission of an email
+ message as a response to an event of level <em>ERROR</em> or higher.
+ However, it is possible to override this default behavior by providing a custom
+ implementation of the <code>EventEvaluator</code> interface.
+ </p>
+
+ <p>
+ The <code>SMTPAppender</code> submits each incoming event to its evaluator
+ by calling <code>evaluate()</code> method in order to check whether
+ the event should trigger an email or just be placed in the cyclic buffer.
+ When the evaluator gives a positive answer to its evaluation, an email is sent.
+ The <code>SMTPAppender</code> contains one and only one evaluator object.
+ This object may possess its own state. For illustrative purposes,
+ the <code>CounterBasedEvaluator</code> class listed next, implements an
+ event evaluator whereby every 1024th event triggers an email message.
+ </p>
+
+<em>Example 4.11: A <code>EventEvaluator</code> implementation
+that evaluates to <code>true</code> every 1024th event (<a href="../xref/chapter4/mail/CounterBasedEvaluator.html">logback-examples/src/main/java/chapter4/mail/CounterBasedEvaluator.java</a>)</em>
+<div class="source"><pre>package chapter4.mail;
+
+import ch.qos.logback.core.boolex.EvaluationException;
+import ch.qos.logback.core.boolex.EventEvaluator;
+import ch.qos.logback.core.spi.ContextAwareBase;
+
+public class CounterBasedEvaluator extends ContextAwareBase implements EventEvaluator {
+
+ static int LIMIT = 1024;
+ int counter = 0;
+ String name;
+
+ <b>public boolean evaluate(Object event) throws NullPointerException,
+ EvaluationException {
+ counter++;
+
+ if (counter == LIMIT) {
+ counter = 0;
+
+ return true;
+ } else {
+ return false;
+ }
+ }</b>
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}</pre></div>
+
+ <p>
+ Note that this implementation extends <code>ContextAwareBase</code> and
+ implements <code>EventEvaluator</code>. This allows the user to concentrate
+ on the core functions of her <code>EventEvaluator</code> and let the base class
+ provide the common functionnality.
+ </p>
+
+ <p>
+ Setting the <span class="option">EventEvaluator</span> option of
+ <code>SMTPAppender</code> instructs it to use a custom evaluator.
+ The next configuration file attaches a <code>SMTPAppender</code> to the root logger.
+ This appender has a buffer size of 2048 and uses a <code>CounterBasedEvaluator</code> instance
+ as its event evaluator.
+ </p>
+
+<em>Example 4.12: <code>SMTPAppender</code> with custom
+<code>Evaluator</code> and buffer size (logback-examples/src/main/java/chapter4/mail/mail3.xml)</em>
+
+<div class="source"><pre><configuration>
+ <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
+ <b><Evaluator class="chapter4.mail.CounterBasedEvaluator" /></b>
+ <BufferSize>1050</BufferSize>
+ <SMTPHost>${smtpHost}</SMTPHost>
+ <To>${to}</To>
+ <From>${from}</From>
+ <layout class="ch.qos.logback.classic.html.HTMLLayout"/>
+ </appender>
+
+ <root>
+ <level value ="debug"/>
+ <appender-ref ref="EMAIL" />
+ </root>
+</configuration></pre></div>
+
+
+
+ <a name="DBAppender"></a>
+ <h3>DBAppender</h3>
+
+ <p>
+ The <a href="../xref/ch/qos/logback/classic/db/DBAppender.html"><code>DBAppender</code></a>
+ inserts loggin events into three database tables in a format
+ independent of the Java programming language.
+ </p>
+ <p>
+ These three tables are <em>logging_event</em>, <em>logging_event_property</em> and
+ <em>logging_event_exception</em>. They all must exist before <code>DBAppender</code>
+ can be used. Logback ships with SQL scripts that will create the tables.
+ They can be found in the found in the
+ <em>logback-classic/src/main/java/ch/qos/logback/classic/db/dialect</em> directory. There
+ is a specific script for each of the most popular database systems.
+ If the script for your particular type of database system is missing, it should be
+ quite easy to write one, taking example on the already existing scripts. If
+ you send them to us, we will gladly include missing scripts in future releases.
+ </p>
+
+ <p>
+ If your JDBC driver supports the
+ <code>getGeneratedKeys</code> method introduced in
+ JDBC 3.0 specification, then no more steps are required, excluding usual
+ configuration.
+ </p>
+ <p>
+ Otherwise, there must be an <code>SQLDialect</code> appropriate for your
+ database system. Currently, we have dialects for PostgreSQL,
+ MySQL, Oracle and MsSQL. As mentioned previously, an
+ <code>SQLDialect</code> is required only if the JDBC driver for your
+ database system does not support the <code>getGeneratedKeys</code>
+ method.
+ </p>
+
+ <p>
+ The table below summarizes the database types and their support of the
+ <code>getGeneratedKeys()</code> method.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>RDBMS</th>
+ <th>
+ supports
+ <br></br>
+ <code>getGeneratedKeys()</code>
+ method
+ </th>
+ <th>
+ specific
+ <br></br>
+ SQLDialect support
+ </th>
+ </tr>
+ <tr class="a">
+ <td>PostgreSQL</td>
+ <td>NO</td>
+ <td>present and used</td>
+ </tr>
+ <tr class="b">
+ <td>MySQL</td>
+ <td>YES</td>
+ <td>present, but not actually needed or used</td>
+ </tr>
+ <tr class="a">
+ <td>Oracle</td>
+ <td>YES</td>
+ <td>present, but not actually needed or used</td>
+ </tr>
+ <tr class="b">
+ <td>DB2</td>
+ <td>YES</td>
+ <td>not present, and not needed or used</td>
+ </tr>
+ <tr class="a">
+ <td>MsSQL</td>
+ <td>YES</td>
+ <td>not present, and not needed or used</td>
+ </tr>
+ <tr class="b">
+ <td>HSQL</td>
+ <td>NO</td>
+ <td>present and used</td>
+ </tr>
+ </table>
+
+ <p>
+ Experiments show that writing a single event
+ into the database takes approximately 10 milliseconds, on a
+ "standard" PC. If pooled connections are used, this figure
+ drops to around 1 milliseconds. Note that most JDBC drivers
+ already ship with connection pooling support.
+ </p>
+
+ <p>
+ Configuring logback to use <code>DBAppender</code> can be done
+ in several different ways, depending on the tools one has to
+ connect to the database, and the database itself. All manners of
+ configuring <code>DBAppender</code> are about setting its
+ <code>ConnectionSource</code> object, which we will cover in
+ a short moment.
+ </p>
+
+ <p>
+ Once logback is configured properly, the logging events are sent to
+ the specified database. As stated previously, there are three tables
+ used by logback to store logging event data.
+ </p>
+
+ <p>
+ The <em>logging_event</em> table contains the following fields:
+ </p>
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="b">
+ <td><b>timestmp</b></td>
+ <td><code>big int</code></td>
+ <td>The timestamp that was valid at the logging event's creation.</td>
+ </tr>
+ <tr class="a">
+ <td><b>formatted_message</b></td>
+ <td><code>text</code></td>
+ <td>The message that has been added to the logging event, after formatting with
+ <code>org.slf4j.impl.MessageFormatter</code>, in case object were passed
+ along with the message.</td>
+ </tr>
+ <tr class="b">
+ <td><b>logger_name</b></td>
+ <td><code>varchar</code></td>
+ <td>The name of the logger used to issue the logging request.</td>
+ </tr>
+ <tr class="a">
+ <td><b>level_string</b></td>
+ <td><code>varchar</code></td>
+ <td>The level of the logging event.</td>
+ </tr>
+ <tr class="b">
+ <td><b>reference_flag</b></td>
+ <td><code>smallint</code></td>
+ <td>
+ <p>
+ This field is used by logback to identify logging events that
+ have an exception or <code>MDC</code>property values associated.
+ </p>
+ <p>
+ It's value is computed by
+ <code>ch.qos.logback.classic.db.DBHelper</code>. A logging event that
+ contains <code>MDC</code> or <code>Context</code>
+ properties has a flag number of <em>1</em>. One
+ that contains an exception has a flag number of <em>2</em>. A logging
+ event that contains both elements has a flag number of <em>3</em>.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>caller_filename</b></td>
+ <td><code>varchar</code></td>
+ <td>The name of the file where the logging request was issued.</td>
+ </tr>
+ <tr class="b">
+ <td><b>caller_class</b></td>
+ <td><code>varchar</code></td>
+ <td>The class where the logging request was issued.</td>
+ </tr>
+ <tr class="a">
+ <td><b>caller_method</b></td>
+ <td><code>varchar</code></td>
+ <td>The name of the method where the logging request was issued.</td>
+ </tr>
+ <tr class="b">
+ <td><b>caller_line</b></td>
+ <td><code>char</code></td>
+ <td>The line number where the logging request was issued.</td>
+ </tr>
+ <tr class="a">
+ <td><b>event_id</b></td>
+ <td><code>int</code></td>
+ <td>The database id of the logging event.</td>
+ </tr>
+ </table>
+
+ <p>
+ The <em>logging_event_property</em> is used to store the keys and values
+ contained in the <code>MDC</code> or the <code>Context</code>.
+ It contains these fields:
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td><b>event_id</b></td>
+ <td><code>int</code></td>
+ <td>The database id of the logging event.</td>
+ </tr>
+ <tr class="b">
+ <td><b>mapped_key</b></td>
+ <td><code>varchar</code></td>
+ <td>The key of the <code>MDC</code> property</td>
+ </tr>
+ <tr class="a">
+ <td><b>mapped_value</b></td>
+ <td><code>text</code></td>
+ <td>The value of the <code>MDC</code> property</td>
+ </tr>
+ </table>
+
+ <p>
+ The <em>logging_event_exception</em> table contains the following fields:
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td><b>event_id</b></td>
+ <td><code>int</code></td>
+ <td>The database id of the logging event.</td>
+ </tr>
+ <tr class="b">
+ <td><b>i</b></td>
+ <td><code>smallint</code></td>
+ <td>The index of the line in the full stack trace.</td>
+ </tr>
+ <tr class="a">
+ <td><b>trace_line</b></td>
+ <td><code>varchar</code></td>
+ <td>The corresponding line</td>
+ </tr>
+ </table>
+
+ <p>
+ To give a more visual example of the work done by <code>DBAppender</code>, here
+ is a screenshot of a MySQL database with content provided by <code>DBAppender</code>.
+ </p>
+
+ <p>The <em>logging_event</em> table:</p>
+
+ <img src="images/chapter4/dbAppenderLE.gif" alt="Logging Event table"></img>
+
+ <p>The <em>logging_event_exception</em> table:</p>
+
+ <img src="images/chapter4/dbAppenderLEException.gif" alt="Logging Event Exception table"></img>
+
+ <p>The <em>logging_event_property</em> table:</p>
+
+ <img src="images/chapter4/dbAppenderLEProperty.gif" alt="Logging Event Property table"></img>
+
+
+ <h4>ConnectionSource</h4>
+
+ <p>
+ The <id>ConnectionSource</id> interface provides a pluggable means of
+ transparently obtaining JDBC Connections for logback classes that
+ require the use of a <code>java.sql.Connection</code>. There are currently
+ three implementations of <code>ConnectionSource</code>, namely
+ <code>DataSourceConnectionSource</code>, <code>DriverManagerConnectionSource</code>
+ and <code>JNDIConnectionSource</code>.
+ </p>
+
+ <p>
+ The first example that we will review is a configuration using
+ <code>DriverManagerConnectionSource</code> and a MySQL database.
+ The following configuration file is what one would need.
+ </p>
+
+<em>Example 4.13: <code>DBAppender</code> configuration (logback-examples/src/main/java/chapter4/db/append-toMySQL-with-driverManager.xml)</em>
+<div class="source"><pre><configuration>
+
+ <b><appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
+ <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
+ <driverClass>com.mysql.jdbc.Driver</driverClass>
+ <url>jdbc:mysql://host_name:3306/datebase_name</url>
+ <user>username</user>
+ <password>password</password>
+ </connectionSource>
+ </appender></b>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="DB" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ The correct driver must be declared. Here, the <code>com.mysql.jdbc.Driver</code>
+ class is used. The <span class="option">url</span> must begin with <em>jdbc:myslq://</em>.
+ </p>
+
+ <p>
+ The
+ <a href="../xref/ch/qos/logback/core/db/DriverManagerConnectionSource.html">
+ <code>DriverManagerConnectionSource</code></a> is an implementation of
+ <code>ConnectionSource</code> that obtains the connection in the
+ traditional JDBC manner based on the connection URL.
+ </p>
+ <p>
+ Note that this class will establish a new <code>Connection</code> for
+ each call to <code>getConnection()</code>. It is recommended
+ that you either use a JDBC driver that natively supports
+ connection pooling or that you create your own
+ implementation of <code>ConnectionSource</code> that taps into
+ whatever pooling mechanism you are already using. (If you
+ have access to a JNDI implementation that supports
+ <code>javax.sql.DataSource</code>, e.g. within a J2EE application
+ server, see <code>JNDIConnectionSource</code>).
+ </p>
+
+
+ <p>
+ Connecting to a database using a <code>DataSource</code> is rather similar.
+ The configuration now uses
+ <a href="../xref/ch/qos/logback/core/db/DataSourceConnectionSource.html">
+ <code>DataSourceConnectionSource</code></a>,
+ which is an implementation of <code>ConnectionSource</code> that obtains the
+ <code>Connection</code> in the recommended JDBC manner based on a
+ <code>javax.sql.DataSource</code>.
+ </p>
+
+<em>Example 4.14: <code>DBAppender</code> configuration (logback-examples/src/main/java/chapter4/db/append-with-datasource.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
+ <b><connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
+
+ <dataSource class="${dataSourceClass}">
+ </b><!-- Joran cannot substitute variables
+ that are not attribute values. Therefore, we cannot
+ declare the next parameter like the others.
+ -->
+ <b><param name="${url-key:-url}" value="${url_value}"/>
+ <serverName>${serverName}</serverName>
+ <databaseName>${databaseName}</databaseName>
+ </dataSource></b>
+
+ <user>${user}</user>
+ <password>${password}</password>
+ </connectionSource>
+ </appender>
+
+ <root>
+ <level value ="debug"/>
+ <appender-ref ref="DB" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ Not that in this configuration sample, we make heavy use of substitution variables.
+ They are sometimes handy when connection details have to be centralised in a
+ single configuration file and shared by logback and other frameworks.
+ </p>
+
+
+
+ <p>
+ The third implementation of <code>ConnectionSource</code> that is shipped with
+ logback is the <code>JNDIConnectionSource</code>.
+ </p>
+
+ <p>
+ The
+ <a href="../xref/ch/qos/logback/core/db/JNDIConnectionSource.html">
+ <code>JNDIConnectionSource</code></a>
+ is an implementation of <code>ConnectionSource</code> that
+ obtains a <code>javax.sql.DataSource</code> from a JNDI provider
+ and uses it to obtain a <code>java.sql.Connection</code>. It is
+ primarily designed to be used inside of J2EE application
+ servers or application server clients, assuming the
+ application server supports remote access of <code>javax.sql.DataSource</code>.
+ In this way one can take advantage of connection pooling and whatever other goodies the
+ application server provides.
+ </p>
+
+<div class="source"><pre><connectionSource class="ch.qos.logback.core.db.JNDIConnectionSource">
+ <param name="jndiLocation" value="jdbc/MySQLDS" />
+ <param name="username" value="myUser" />
+ <param name="password" value="myPassword" />
+</connectionSource></pre></div>
+
+ <p>
+ Note that this class will obtain an
+ <code>javax.naming.InitialContext</code>
+ using the no-argument constructor. This will usually work
+ when executing within a J2EE environment. When outside the
+ J2EE environment, make sure that you provide a
+ <em>jndi.properties</em>
+ file as described by your JNDI provider's documentation.
+ </p>
+
+ <h4>Connection pooling</h4>
+
+ <p>
+ Logging events can be created at a rather fast pace. To keep up
+ with the flow of events that must be inserted into a database,
+ it is recommanded to use connection pooling with
+ <code>DBAppender</code>.
+ </p>
+
+ <p>
+ Experiment shows that using connection pooling with <code>DBAppender</code>
+ gives a big performance boost. With the following
+ configuration file, logging events are sent to a MySQL database,
+ without any pooling.
+ </p>
+<em>Example 4.15: <code>DBAppender</code> configuration without pooling (logback-examples/src/main/java/chapter4/db/append-toMySQL-with-datasource.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
+ <connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
+ <dataSource class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
+ <serverName>${serverName}</serverName>
+ <port>${port$</port>
+ <databaseName>${dbName}</databaseName>
+ <user>${user}</user>
+ <password>${pass}</password>
+ </dataSource>
+ </connectionSource>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="DB" />
+ </root>
+</configuration</pre></div>
+
+ <p>
+ With this configuration file, sending 500 logging events to
+ a MySQL database takes a whopping 5 seconds, that is
+ 10 miliseconds per requests. This figure is
+ unacceptable when dealing with large applications.
+ </p>
+
+ <p>
+ A dedicated external library is necessary to use connection pooling
+ with <code>DBAppender</code>. The next example uses
+ <a href="http://sourceforge.net/projects/c3p0">c3p0</a>. To be able
+ to use c3p0, one must download it and place <em>c3p0-VERSION.jar</em>
+ in the classpath.
+ </p>
+
+<em>Example 4.16: <code>DBAppender</code> configuration with pooling (logback-examples/src/main/java/chapter4/db/append-toMySQL-with-datasource-and-pooling.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
+ <connectionSource
+ class="ch.qos.logback.core.db.DataSourceConnectionSource">
+ <b><dataSource
+ class="com.mchange.v2.c3p0.ComboPooledDataSource">
+ <driverClass>com.mysql.jdbc.Driver</driverClass>
+ <jdbcUrl>jdbc:mysql://${serverName}:${port}/${dbName}</jdbcUrl>
+ <user>${user}</user>
+ <password>${password}</password>
+ </dataSource></b>
+ </connectionSource>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="DB" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ With this new configuration, sending 500 logging requests to
+ the same MySQL database as previously used takes around 0.5 seconds,
+ for an average time of 1 milisecond per request.
+ The gain is a <em>10</em> factor.
+ </p>
+
+ <a name="SyslogAppender"></a>
+ <h3>SyslogAppender</h3>
+
+ <p>
+ The syslog protocol is a very simple protocol: a syslog sender sends a small
+ message to a syslog receiver.
+ The receiver is commonly called <em>syslog daemon</em> or <em>syslog server</em>.
+ Logback can send messages to a remote syslog daemon. This is achieved by using
+ <a href="../xref/ch/qos/logback/classic/net/SyslogAppender.html"><code>SyslogAppender</code></a>.
+ </p>
+
+ <p>
+ Here are its options:
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td>
+ <b>
+ <span class="option">SyslogHost</span>
+ </b>
+ </td>
+ <td>
+ <code>String</code>
+ </td>
+ <td>
+ The host name of the syslog server.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>
+ <b>
+ <span class="option">Port</span>
+ </b>
+ </td>
+ <td>
+ <code>String</code>
+ </td>
+ <td>
+ The port number on the syslog server to connect to. Normally, one would not want
+ to change the default value, that is <em>514</em>.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>
+ <b>
+ <span class="option">Facility</span>
+ </b>
+ </td>
+ <td>
+ <code>String</code>
+ </td>
+ <td>
+ <p>
+ The <span class="option">Facility</span> is meant to identify
+ the source of a message.
+ </p>
+ <p>
+ The <span class="option">Facility</span> option must be set one
+ of the strings <em>KERN, USER, MAIL, DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP,
+ CRON, AUTHPRIV, FTP, NTP, AUDIT, ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2,
+ LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7</em>. Case is not important.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td>
+ <b>
+ <span class="option">SuffixPattern</span>
+ </b>
+ </td>
+ <td>
+ <code>String</code>
+ </td>
+ <td>
+ <p>
+ The <span class="option">SuffixPattern</span> option specifies the format of the
+ non-standardized part the message sent to the syslog server. By default, its value
+ is <em>[%thread] %logger %msg %exception</em>. Any value that a <code>PatternLayout</code>
+ could use is a correct <span class="option">SuffixPattern</span>.
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ The syslog severity of a logging event is converted from the level of the logging event.
+ The <em>DEBUG</em> level is converted to <em>7</em>, <em>INFO</em> is converted to
+ <em>6</em>, <em>WARN</em> is converted to <em>4</em> and <em>ERROR</em> is converted
+ to <em>3</em>.
+ </p>
+
+ <p>
+ Since the format of a syslog request follows rather strict rules, there is no layout
+ to be used with <code>SyslogAppender</code>. However, the using the
+ <span class="option">SuffixPattern</span> option lets the user display whatever
+ information she wishes.
+ </p>
+
+ <p>
+ Here is a sample configuration using a <code>SyslogAppender</code>.
+ </p>
+
+<em>Example 4.17: <code>SyslogAppender</code> configuration (logback-examples/src/main/java/chapter4/conf/logback-syslog.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="SYSLOG"
+ class="ch.qos.logback.classic.net.SyslogAppender">
+ <SyslogHost>remote_home</SyslogHost>
+ <Facility>AUTH</Facility>
+ <SuffixPattern>%-4relative [%thread] %-5level - %msg</SuffixPattern>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ When testing this configuration, one should verify that the remote syslog daemon
+ accepts requests from an external source. Experience shows that syslog daemons
+ usually deny such requests by default.
+ </p>
+
+
+ <a name="Access"></a>
+ <h2>Logback Access</h2>
+
+ <p>
+ Most of the appenders found in logback classic can be used within
+ logback access. They function mostly in the same way as their logback
+ classic counterpart. In the next section, we will cover their use, but will
+ focuse on the differences with the classic appenders.
+ </p>
+
+ <a name="AccessSocketAppender"></a>
+ <h3>SocketAppender</h3>
+
+ <p>
+ The <a href="../xref/ch/qos/logback/access/net/SocketAppender.html">
+ <code>SocketAppender</code></a> is designed to log to a
+ remote entity by transmitting serialized <code>AccessEvent</code> objects over the wire.
+ Remote logging is non-intrusive as far as the access event is concerned.
+ On the receiving end after de-serialization, the event can be logged as
+ if it were generated locally.
+ </p>
+ <p>
+ The options of access' <code>SocketAppender</code> are the same as those available
+ for classic's <code>SocketAppender</code>.
+ </p>
+
+ <a name="AccessSMTPAppender"></a>
+ <h3>SMTPAppender</h3>
+
+ <p>
+ Access' <a href="../xref/ch/qos/logback/access/net/SMTPAppender.html">
+ <code>SMTPAppender</code></a> works in the same way as its Classic counterpart.
+ However, the <span class="option">evaluator</span> option is rather different.
+ By default, a <code>URLEvaluator</code> object
+ is used by <code>SMTPAppender</code>. This evaluator contains a list of URLs that are
+ checked agains the current request's URL. When one of the pages given to the
+ <code>URLEvaluator</code> is requested, <code>SMTPAppender</code> sends an email.
+ </p>
+
+ <p>
+ Here is a sample configuration of a <code>SMTPAppender</code> in the access environnement.
+ </p>
+<em>Example 4.18: <code>SMTPAppender</code> configuration (logback-examples/src/main/java/chapter4/conf/access/logback-smtp.xml)</em>
+<div class="source"><pre><appender name="SMTP"
+ class="ch.qos.logback.access.net.SMTPAppender">
+ <layout class="ch.qos.logback.access.html.HTMLLayout">
+ <Pattern>%h%l%u%t%r%s%b</Pattern>
+ </layout>
+
+ <b><Evaluator class="ch.qos.logback.access.net.URLEvaluator">
+ <URL>url1.jsp</URL>
+ <URL>directory/url2.html</URL>
+ </Evaluator></b>
+ <From>sender_email at host.com</From>
+ <SMTPHost>mail.domain.com</SMTPHost>
+ <To>recipient_email at host.com</To>
+</appender></pre></div>
+
+ <p>
+ This way of triggering the email lets user select pages that are important steps
+ in a specific process, for example.
+ When such a page is accessed, the email is sent with the pages
+ that were accessed previously, and any information the user wants to be included
+ in the email.
+ </p>
+
+
+
+ <a name="AccessDBAppender"></a>
+ <h3>DBAppender</h3>
+
+ <p>
+ <a href="../xref/ch/qos/logback/access/db/DBAppender.html"><code>DBAppender</code></a>
+ is used to insert the access events into a database.
+ </p>
+ <p>
+ Two tables are used by <code>DBAppender</code>: <em>access_event</em> and
+ <em>access_event_header</em>. They all must exist before <code>DBAppender</code>
+ can be used. Logback ships with SQL scripts that will create the tables.
+ They can be found in the found in the
+ <em>logback-access/src/main/java/ch/qos/logback/access/db/dialect</em> directory. There
+ is a specific script for each of the most popular database systems.
+ If the script for your particular type of database system is missing, it should be
+ quite easy to write one, taking example on the already existing scripts. If
+ you send them to us, we will gladly include missing scripts in future releases.
+ </p>
+
+ <p>The <em>access_event</em> table's fields are described below:</p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="b">
+ <td><b>timestmp</b></td>
+ <td><code>big int</code></td>
+ <td>The timestamp that was valid at the access event's creation.</td>
+ </tr>
+ <tr class="a">
+ <td><b>requestURI</b></td>
+ <td><code>varchar</code></td>
+ <td>The URI that was requested.</td>
+ </tr>
+ <tr class="b">
+ <td><b>requestURL</b></td>
+ <td><code>varchar</code></td>
+ <td>The URL that was requested. This is a string composed of the request method,
+ the request URI and the request protocol.
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>remoteHost</b></td>
+ <td><code>varchar</code></td>
+ <td>The name of the remote host.</td>
+ </tr>
+ <tr class="b">
+ <td><b>remoteUser</b></td>
+ <td><code>varchar</code></td>
+ <td>
+ The name of the remote user.
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>remoteAddr</b></td>
+ <td><code>varchar</code></td>
+ <td>The remote IP address.</td>
+ </tr>
+ <tr class="b">
+ <td><b>protocol</b></td>
+ <td><code>varchar</code></td>
+ <td>The request protocol, like <em>HTTP</em> or <em>HTTPS</em>.</td>
+ </tr>
+ <tr class="a">
+ <td><b>method</b></td>
+ <td><code>varchar</code></td>
+ <td>The request method, usually <em>GET</em> or <em>POST</em>.</td>
+ </tr>
+ <tr class="b">
+ <td><b>serverName</b></td>
+ <td><code>varchar</code></td>
+ <td>The name of the server that issued the request.</td>
+ </tr>
+ <tr class="a">
+ <td><b>event_id</b></td>
+ <td><code>int</code></td>
+ <td>The database id of the access event.</td>
+ </tr>
+ </table>
+
+ <p>
+ The <em>access_event_header</em> table contains the header of each
+ requests. The information is organised as shown below:
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td><b>event_id</b></td>
+ <td><code>int</code></td>
+ <td>The database id of the corresponding access event.</td>
+ </tr>
+ <tr class="b">
+ <td><b>header_key</b></td>
+ <td><code>varchar</code></td>
+ <td>The header name, for example <em>User-Agent</em>.</td>
+ </tr>
+ <tr class="a">
+ <td><b>header_value</b></td>
+ <td><code>varchar</code></td>
+ <td>The header value, for example <em>Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1) Gecko/20061010 Firefox/2.0</em></td>
+ </tr>
+ </table>
+
+ <p>
+ All options of classic's <code>DBAppender</code> are available
+ in access' <code>DBAppender</code>. The latter offers one more option,
+ described below.
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Option Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td>
+ <b>
+ <span class="option">insertHeaders</span>
+ </b>
+ </td>
+ <td>
+ <code>boolean</code>
+ </td>
+ <td>
+ Tells the <code>DBAppender</code> to populate the database with the header
+ information of all incoming requests.
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ Here is a sample configuration that uses <code>DBAppender</code>.
+ </p>
+<em>Example 4.19: DBAppender configuration (logback-examples/src/main/java/chapter4/conf/access/logback-DB.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="DB" class="ch.qos.logback.access.db.DBAppender">
+ <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
+ <driverClass>com.mysql.jdbc.Driver</driverClass>
+ <url>jdbc:mysql://localhost:3306/logbackdb</url>
+ <user>logback</user>
+ <password>logback</password>
+ </connectionSource>
+ <insertHeaders>true</insertHeaders>
+ </appender>
+
+ <appender-ref ref="DB" />
+</configuration></pre></div>
+
+
+ <a name="WriteYourOwnAppender"></a>
+ <h2>Writing your own Appender</h2>
+
+
+ <p>You can easily write your appender by sub-classing <code>AppenderBase</code>.
+ It handles support for filters, status among other functionality shared by most appenders.
+ The derived class only needs to implement one method, namely
+ <code>append(Object eventObject)</code>.
+ </p>
+
+ <p>The <code>CountingConsoleAppender</code>, which we list next, appends a limited
+ number of incoming events on the console. It shuts down after the limit is reached.
+ It uses a <code>Layout</code> to format the events and accepts a parameter,
+ thus a few more methods are needed.
+ </p>
+
+<em>Example 4.20: <code>CountingConsoleAppender</code> (logback-examples/src/main/java/chapter4/CountingConsoleAppender.java)</em>
+<div class="source"><pre>package chapter4;
+
+import ch.qos.logback.core.AppenderBase;
+import ch.qos.logback.core.Layout;
+
+
+public class CountingConsoleAppender extends AppenderBase<LoggingEvent> {
+ static int DEFAULT_LIMIT = 16;
+ int counter = 0;
+ int limit = DEFAULT_LIMIT;
+
+ private Layout<LoggingEvent> layout;
+
+ public CountingConsoleAppender() {
+ }
+
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
+
+ public int getLimit() {
+ return limit;
+ }
+
+ @Override
+ public void start() {
+ if (this.layout == null) {
+ addError("No layout set for the appender named ["+ name +"].");
+ return;
+ }
+
+ super.start();
+ }
+
+ public void append(LoggingEvent event) {
+
+ if (counter >= limit) {
+ return;
+ }
+
+ // output the events as formatted by our layout
+ System.out.print(this.layout.doLayout(event));
+
+ // prepare for next event
+ counter++;
+ }
+
+ public Layout<LoggingEvent> getLayout() {
+ return layout;
+ }
+
+ public void setLayout(Layout<LoggingEvent> layout) {
+ this.layout = layout;
+ }
+}</pre></div>
+
+ <p>
+ The <code>start()</code> method checks for the presence of a <code>Layout</code>.
+ In case none is found, the appender is not started.
+ </p>
+
+ <p>
+ This custom appender illustrates a two points:
+ </p>
+
+ <ul>
+ <li>
+ All options that follow the setter/getter JavaBeans conventions
+ are handled transparently. The <code>start()</code> method, that is
+ called automatically, has the responsability to check that the given
+ options are coherent.
+ </li>
+ <li>
+ The <code>AppenderBase.doAppend()</code> method invokes the append()
+ method of its derived classes where actual output operations occur.
+ It is in this method that appenders format events by invoking their layouts.
+ </li>
+ </ul>
+
+
+ The <code>CountingConsoleAppender</code> can be configured like any appender.
+ See sample file <em>logback-examples/src/main/java/chapter4/countingConsole.xml</em>
+ for an example.
+
+
+
+<script src="../templates/footer.js"></script>
+
+
+</div>
+
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/manual/architecture.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/manual/architecture.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,815 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Chapter 2: Architecture</title>
+<link rel="stylesheet" type="text/css" media="screen" href="../css/site.css" />
+</head>
+<body>
+<script src="../templates/header.js"></script>
+<div id="left">
+ <script src="../templates/left.js"></script>
+</div>
+<div id="right">
+ <script src="../templates/right.js"></script>
+</div>
+<div id="content"><br />
+ <h2>Chapter 2:
+ Architecture</h2>
+ <div class="author">Authors: Ceki Gülcü,
+ Sébastien Pennec </div>
+ <table class="bodyTable">
+ <tbody>
+ <tr class="a">
+ <td><a href="http://creativecommons.org/licenses/by-nc-sa/2.5/"><img alt="Creative Commons License" style="border-width: 0pt;" 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 href="http://creativecommons.org/licenses/by-nc-sa/2.5/">Creative
+ Commons
+ Attribution-NonCommercial-ShareAlike 2.5
+ License </a>. </p></td>
+ </tr>
+ </tbody>
+ </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>
+ <a name="LoggerContext"></a>
+ <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 {<br /> // Printing methods: public void debug(String message);<br /> public void info(String message); public void warn(String message); <br /> public void error(String message); public void fatal(String message); <br />}</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 class="bodyTable">
+ <tbody>
+ <tr class="b">
+ <th>Logger name </th>
+ <th> Assigned level </th>
+ <th> Effective level </th>
+ </tr>
+ <tr class="a">
+ <td>root</td>
+ <td>DEBUG</td>
+ <td>DEBUG</td>
+ </tr>
+ <tr class="b">
+ <td>X</td>
+ <td>none</td>
+ <td>DEBUG</td>
+ </tr>
+ <tr class="a">
+ <td>X.Y</td>
+ <td>none</td>
+ <td>DEBUG</td>
+ </tr>
+ <tr class="b">
+ <td>X.Y.Z</td>
+ <td>none</td>
+ <td>DEBUG</td>
+ </tr>
+ </tbody>
+ </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 class="bodyTable">
+ <tbody>
+ <tr class="a">
+ <th>Logger name </th>
+ <th> Assigned level </th>
+ <th> Effective level </th>
+ </tr>
+ <tr class="b">
+ <td>root</td>
+ <td>ERROR</td>
+ <td>ERROR</td>
+ </tr>
+ <tr class="a">
+ <td>X</td>
+ <td>INFO</td>
+ <td>INFO</td>
+ </tr>
+ <tr class="b">
+ <td>X.Y</td>
+ <td>DEBUG</td>
+ <td>DEBUG</td>
+ </tr>
+ <tr class="a">
+ <td>X.Y.Z</td>
+ <td>WARN</td>
+ <td>WARN</td>
+ </tr>
+ </tbody>
+ </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 class="bodyTable">
+ <tbody>
+ <tr class="b">
+ <th>Logger name </th>
+ <th> Assigned level </th>
+ <th> Effective level </th>
+ </tr>
+ <tr class="a">
+ <td>root</td>
+ <td>DEBUG</td>
+ <td>DEBUG</td>
+ </tr>
+ <tr class="b">
+ <td>X</td>
+ <td>INFO</td>
+ <td>INFO</td>
+ </tr>
+ <tr class="a">
+ <td>X.Y</td>
+ <td>none</td>
+ <td>INFO</td>
+ </tr>
+ <tr class="b">
+ <td>X.Y.Z</td>
+ <td>ERROR</td>
+ <td>ERROR</td>
+ </tr>
+ </tbody>
+ </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 class="bodyTable">
+ <tbody>
+ <tr class="a">
+ <th>Logger name </th>
+ <th> Assigned level </th>
+ <th> Effective level </th>
+ </tr>
+ <tr class="b">
+ <td>root</td>
+ <td>DEBUG</td>
+ <td>DEBUG</td>
+ </tr>
+ <tr class="a">
+ <td>X</td>
+ <td>INFO</td>
+ <td>INFO</td>
+ </tr>
+ <tr class="b">
+ <td>X.Y</td>
+ <td>none</td>
+ <td>INFO</td>
+ </tr>
+ <tr class="a">
+ <td>X.Y.Z</td>
+ <td>none</td>
+ <td>INFO</td>
+ </tr>
+ </tbody>
+ </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>
+ <a name="PrintintMethods"></a>
+ <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 class="bodyTable">
+ <tbody>
+ <tr class="b">
+ <th><span style=""><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 class="a">
+ <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 class="b">
+ <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 class="a">
+ <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 class="b">
+ <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>
+ </tbody>
+ </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. <br />Logger logger = LoggerFactory.getLogger("com.foo");<br />//set its Level to <span class="blue">INFO</span><br />logger.setLevel(Level. <span class="blue">INFO</span>);<br />Logger barlogger = LoggerFactory.getLogger("com.foo.Bar");<br />// This request is enabled, because <span class="green bold">WARN</span> >= <span class="blue">INFO</span><br />logger.<span class="green bold">warn</span>("Low fuel level.");<br />// This request is disabled, because <span class="green bold">DEBUG</span> < <span class="blue">INFO</span>. <br />logger.<span class="green bold">debug</span>("Starting search for nearest gas station.");<br />// The logger instance barlogger, named "com.foo.Bar", <br />// will inherit its level from the logger named <br />// "com.foo" Thus, the following request is enabled // because <span class="green bold">INFO</span> >= <span class="blue">INFO</span>.
<br />barlogger.<span class="green bold">info</span>("Located nearest gas station.");<br />// This request is disabled, because <span class="green bold">DEBUG</span> < <span class="blue">INFO</span>. <br />barlogger.<span class="green bold">debug</span>("Exiting gas station search");</pre>
+ </div>
+ <a name="RetrievingLoggers"></a>
+ <h3>Retrieving Loggers</h3>
+ <p>Calling the <code><a href="../apidocs/org/slf4j/LoggerFactory.html#getLogger%28java.lang.String%29">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"); <br />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>
+ <a name="AppendersAndLayouts"></a>
+ <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. </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%28ch.qos.logback.core.Appender%29">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">
+ <tbody>
+ <tr class="a">
+ <th>Logger Name</th>
+ <th>Attached Appenders</th>
+ <th>Additivity Flag</th>
+ <th>Output Targets</th>
+ <th>Comment</th>
+ </tr>
+ <tr class="b">
+ <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 class="a">
+ <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 class="b">
+ <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 class="a">
+ <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 class="b">
+ <td>security</td>
+ <td>A-sec</td>
+ <td><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 class="a">
+ <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>
+ </tbody>
+ </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>
+ <a name="ParametrizedLogging"></a>
+ <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()) { <br /> logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));<br />}</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(); <br />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+".");<br />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};<br />logger.debug("Value {} was inserted between {} and {}.", paramArray);</pre>
+ </div>
+ <a name="Configuration"></a>
+ <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>
+ <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>
+ <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 2.1: 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;<br />//Import SLF4J classes.<br />import org.slf4j.Logger;<br />import org.slf4j.LoggerFactory;<br />import ch.qos.logback.classic.LoggerContext;<br />import ch.qos.logback.classic.joran.JoranConfigurator;<br />import ch.qos.logback.core.util.StatusPrinter;<br /><br />public class MyAppWithConfigFile {<br /><br /> public static void main(String[] args) {<br /> Logger logger = LoggerFactory.getLogger(MyAppWithConfigFile.class);<br /> LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();<br /> JoranConfigurator configurator = new JoranConfigurator();<br /> configurator.setContext(lc);<br /> configurator.doConfigure(args[0]);<br /> logger.info("Entering application.");<br /> Bar bar = new Bar();<br /> bar.doIt();<br /> logger.info("Exiting application.");<br /> StatusPrinter.print(lc.getStatusManager());<br /> }<br />}</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 2.2: 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;<br />import org.slf4j.Logger;<br />import org.slf4j.LoggerFactory;<br /><br />class Bar {<br /> Logger logger = LoggerFactory.getLogger(Bar.class); public void doIt() {<br /> logger.debug("doing my job");<br /> }<br />}</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 2.3: 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" ?><br /><configuration><br /><br /> <appender name="STDOUT"<br /> class="ch.qos.logback.core.ConsoleAppender"><br /> <layout class="ch.qos.logback.classic.PatternLayout"><br /> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern><br /> </layout><br /> </appender><br /><br /> <root><br /> <level value="debug" /><br /> <appender-ref ref="STDOUT" /><br /> </root><br /><br /></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.<br />18:15:26.718 [main] DEBUG chapter2.Bar - doing my job<br />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 2.4: 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" ?><br /><configuration><br /><br /> <appender name="STDOUT"<br /> class="ch.qos.logback.core.ConsoleAppender"><br /> <layout class="ch.qos.logback.classic.PatternLayout"><br /> <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern><br /> </layout><br /> </appender><br /><br /> <appender name="FILE"<br /> class="ch.qos.logback.core.FileAppender"><br /> <layout class="ch.qos.logback.classic.PatternLayout"><br /> <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern><br /> </layout><br /> <File>sample-log.txt</File><br /> </appender><br /><br /> <root><br /> <level value="debug" /><br /> <appender-ref ref="STDOUT" /><br /> <appender-ref ref="FILE" /><br /> </root><br /><br /></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 2.5: 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" ?><br /><configuration><br /><br /> <appender name="STDOUT"<br /> class="ch.qos.logback.core.ConsoleAppender"><br /> <layout class="ch.qos.logback.classic.PatternLayout"><br /> <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern><br /> </layout><br /> </appender><br /> <appender name="FILE"<br /> class="ch.qos.logback.core.FileAppender"><br /> <layout class="ch.qos.logback.classic.PatternLayout"><br /> <pattern>%-4relative [%thread] %-5level %class - %msg%n</pattern><br /> </layout><br /> <File>sample-log.txt</File><br /> </appender><br /><b><br /></b> <b><logger name="chapter2"><br /></b> <b><level value="info" /><br /></b> <b></logger><br /></b><br /> <root><br /> <level value="debug" /><br /> <appender-ref ref="STDOUT" /><br /> <app
ender-ref ref="FILE" /><br /> </root><br /><br /></configuration><br />
+</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.<br />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>
+ <li>Logback first tries to find a file called <em>logback.xml</em> within the classpath.</li>
+ <li>If no such file is found, it checks for another file called <em>logback-test.xml</em>.</li>
+ <li>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.</li>
+ </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 the introduction. The output was generated due to this
+ feature. </p>
+ <a name="UnderTheHood"></a>
+ <h3>A peak under the hood</h3>
+ <p>After we have introduced the essential logback components, we
+ are
+ now ready to describe the steps that the logback framework takes when
+ the user invokes a logger's printing method. Let us now analyze the
+ steps logback takes when the user invokes the <code>info()</code> method of a logger named <em>com.wombat</em>. </p>
+ <h4>1. Get the filter chain decision</h4>
+ <p>Logback's <code>TurboFilter</code> chain is
+ called. These filters may
+ be used to prodvide a context-wide threshold, or to filter out certain
+ events based on basic logging informations such as <code>Marker</code>, <code>Level</code>, <code>Logger</code>,
+ message, or the <code>Throwable</code> that was provided in the logging request.
+ If the reply of the filter chain is <code>FilterReply.DENY</code>,
+ then the
+ logging request is dropped. If it is <code>FilterReply.NEUTRAL</code>,
+ then
+ the next step is processed. In case the reply is <code>FilterReply.ACCEPT</code>,
+ the next step is skipped and the logging request is directly processed
+ to step 3. </p>
+ <h4>2. Apply the Logger level filter</h4>
+ <p>Logback compares the effective level of the <em>com.wombat</em> logger
+ with the level of the request (in this example: <em>INFO</em>).
+ If the logging
+ request is disabled, then logback will drop the request without further
+ processing. </p>
+ <h4>3. Create a <code>LoggingEvent</code> object</h4>
+ <p>If the request passed the previous filter, or if the <code>TurboFilter</code> chain
+ gave a <code>FilterReply.ACCEPT</code> result, logback
+ will create a <code>ch.qos.logback.classic.LoggingEvent</code> object
+ containing all the relevant parameters of the request such as the
+ logger of the request, the request
+ level, the message, the exception that might have been passed along the
+ request,
+ the current time, the current thread, several information about the
+ class that issued the logging request and the <code>MDC</code> map. Note that some of these fields
+ are initialized lazily, that is only when they are actually needed. </p>
+ <h4>4. Invoking appenders</h4>
+ <p>After the creation of a <code>LoggingEvent</code> object, logback will proceed to invoke the <code>doAppend()</code> methods of all the applicable appenders, that is, the appenders
+ inherited from the logger context. </p>
+ <p> All appenders shipped with the logback distribution extend the <code>AppenderBase</code> abstract class that implements the <code>doAppend</code> method in a synchronized block ensuring thread-safety. The <code>doAppend()</code> method of <code>AppenderBase</code> also invokes custom filters attached to the appender, if any such
+ filters exist. Custom filters, which can be dynamically attached to any
+ appender, are presented Chapter 6. </p>
+ <h4>5. Formatting the <code>LoggingEvent</code></h4>
+ <p>It is responsibility of the invoked appender to format the
+ logging
+ event. However, most (but not all) appenders delegate the task of
+ formatting the logging event to their layout. Their layout formats the <code>LoggingEvent</code> instance and returns the result as a String. Note that some appenders,
+ such as the <code>SocketAppender</code>,
+ do not transform the logging event into a string but serialize it
+ instead. Consequently, they do not require nor have a layout. </p>
+ <h4>6. Sending out the <code>LoggingEvent</code></h4>
+ <p>After the logging event is fully formatted it is sent to its
+ destination by each appender. </p>
+ <p> Here is a sequence UML diagram to show how everything works. You might
+ want to click on the image to display its bigger version. </p>
+ <a href="underTheHood.html"><img src="images/chapter2/underTheHoodSequence2_small.gif" /></a> <a name="Performance"></a>
+ <h3>Performance</h3>
+ <p>One of the often-cited arguments against logging is its
+ computational
+ cost. This is a legitimate concern as even moderately sized
+ applications can generate thousands of log requests. Much effort is
+ spent measuring and tweaking logging performance.
+ Independently of these efforts, the user should still be aware of the
+ following performance issues. </p>
+ <h4>1. Logging performance when logging is turned off
+ entirely</h4>
+ <p>You can turn off logging entirely by setting the level of the
+ root logger
+ to <code>Level.OFF</code>,
+ the highest possible level. When logging is turned off entirely, the
+ cost of a log request consists of a method invocation plus an integer
+ comparison. On a 3.2Ghz Pentium D machine this cost is typically around
+ 20 nanoseconds. </p>
+ <p>However, any method invocation involves the "hidden" cost of
+ parameter construction. For example, for some logger <em>x</em> writing, </p>
+ <div class="source">
+ <pre>x.debug("Entry number: " + i + "is " + entry[i]);</pre>
+ </div>
+ <p> incurs the cost of constructing the message parameter, i.e. converting
+ both integer <code>i</code> and <code>entry[i]</code> to a string, and concatenating intermediate strings, regardless of
+ whether the message will be logged or not. </p>
+ <p>The cost of parameter construction can be quite high and
+ depends on the
+ size of the parameters involved. To avoid the cost of parameter
+ construction you can use logback's parametrized logging: </p>
+ <div class="source">
+ <pre>x.debug("Entry number: {} is {}", i, entry[i]);</pre>
+ </div>
+ <p> This will not incur the cost of parameter construction. Compared to the
+ previous call to the <code>debug()</code> method, this call will be faster by a very wide margin. The message
+ will be formatted only if the request is processed to the appenders. If
+ it is processed, the component that formats the message offers high
+ performance and does not impact negatively the overall process. It
+ respectively takes 2 and 4 microseconds to format a message with 1 and
+ 3 parameters. </p>
+ <p>Please notice that, despite the performance points
+ that we just
+ discussed, inserting logging statements in tight-loops or very
+ frequently invoked code is a lose-lose proposal
+ and will not result in high performance. They will slow down your
+ application even if logging is turned off or generate massive (and
+ hence useless) output if enabled. </p>
+ <h4>2. The performance of deciding whether to log or not to log
+ when logging is turned on.</h4>
+ <p>In logback, there is no need to walk the whole logger
+ hierarchy. A logger knows
+ its effective level (that is, its level, once level inheritance has
+ been
+ taken into consideration) when it is created. Should the level of a
+ parent logger
+ be changed, then all child loggers will be contacted and handle the
+ change. Thus, before
+ accepting or denying a request based on the effective level, the logger
+ does not need
+ to search its ancestors. </p>
+ <p> Given this situation, it takes the same time to decide whether to log
+ or not when logging
+ is turned on as it takes when logging is turned off. </p>
+ <h4>3. Actual logging (formatting and writing to the
+ output device)</h4>
+ <p>This is the cost of formatting the log output and sending it
+ to its
+ target destination. Here again, a serious effort was made to make
+ layouts (formatters) perform as quickly as possible. The same is true
+ for appenders. The typical cost of actually logging is about 9 to 12
+ microseconds when logging to a file on the local machine.
+ It goes up to 1 millisecond when logging to a database on a remote
+ server. </p>
+ <p>Although feature-rich, one of the foremost design
+ goals of logback
+ was speed of execution, a requirement which is second only to
+ reliability. Some logback components have been rewritten many times to
+ improve performance. </p>
+
+<script src="../templates/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/manual/contextSelector.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/manual/contextSelector.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,282 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Chapter 8: Context Selector</title>
+<link rel="stylesheet" type="text/css" media="screen" href="../css/site.css" />
+</head>
+<body>
+<script src="../templates/header.js"></script>
+<div id="left">
+ <script src="../templates/left.js"></script>
+</div>
+<div id="right">
+ <script src="../templates/right.js"></script>
+</div>
+<div id="content"><br />
+ <h2>Chapter 8: Context Selector</h2>
+ <div class="author">
+ Authors: Ceki Gülcü, Sébastien Pennec
+ </div>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <td>
+ <a 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"></img>
+ </a>
+ </td>
+ <td>
+ <p>Copyright © 2000-2006, QOS.ch</p>
+
+ <p>
+
+ This work is licensed under a
+ <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
+ Creative Commons
+ Attribution-NonCommercial-ShareAlike 2.5
+ License
+ </a>.
+
+ </p>
+ </td>
+ </tr>
+ </table>
+
+<h3>Introduction</h3>
+
+<p>
+When working with several Web applications, all running on one server, the
+multiplications of <code>LoggerContext</code> objects might reveal itself
+a tricky issue.
+</p>
+
+<p>
+Logback provides a simple yet powerful way of dealing with multiple
+contexts, without corruption of data, nor collusion between context
+instances.
+</p>
+
+<p>
+One thing we know is that JNDI environments are independant. Thus
+setting environment variables in each application will allow a given component
+to know which application it is dealing with at the moment. This is basically
+the mechanism that uses logback to provide easy access to the right
+<code>LoggerContext</code> instance.
+</p>
+
+<p>
+The component that manages the different contexts is a
+<a href="../xref/ch/qos/logback/classic/selector/ContextSelector.html">
+ContextSelector</a>
+implementation. The JNDI-specific implementation is called
+<a href="../xref/ch/qos/logback/classic/selector/ContextJNDISelector.html">
+ContextJNDISelector</a>.
+</p>
+
+<p>
+Each Web application provides two environment variables. One that specifies
+the application's <code>LoggerContext</code> name, and one that provides the
+path to the xml file that will be used to configure the context.
+</p>
+
+
+<h3>The server side</h3>
+
+<h4>Configuring Tomcat</h4>
+
+<p>
+First, place the logback jars (that is logback-classic-<em>VERSION</em>.jar,
+logback-core-<em>VERSION</em>.jar and slf4j-api-<em>VERSION</em>.jar) in the
+server's shared class directory. In Tomcat, this directory is
+<em>TOMCAT_HOME/common/lib/</em>.
+</p>
+
+<p>
+The next step is to let logback know that it will have to use JNDI to manage
+the context instances. This is done thanks to a System Property. When launching
+Tomcat, make sure that the <em>logback.ContextSelector</em> property is
+set with the <em>JNDI</em> value. This can be done by editing the
+<em>TOMCAT_HOME/bin/catalina.sh</em> or <em>TOMCAT_HOME/bin/catalina.bat</em>
+file, and adding the following line to the java options:
+</p>
+
+<div class="source"><pre>-Dlogback.ContextSelector=JNDI</pre></div>
+
+<h4>Configuring Jetty</h4>
+
+<p>
+Configuring Jetty requires first to enable the use of JNDI. This is not a big
+deal, since the Jetty distribution provides the configuration files needed to
+achieve this task. The only thing to do is launch Jetty with the following command:
+</p>
+
+<div class="source"><pre>java -jar start.jar etc/jetty.xml etc/jetty-plus.xml</pre></div>
+
+<p>
+Note that you will need to install your appplications in the
+<em>JETTY_HOME/webapps-plus</em> directory.
+</p>
+
+<p>In Jetty, the server shared class directory is <em>JETTY_HOME/lib/</em>.
+This is where you will need to place the logback jars
+(that is logback-classic-<em>VERSION</em>.jar,
+logback-core-<em>VERSION</em>.jar and slf4j-api-<em>VERSION</em>.jar).
+</p>
+
+<p>
+The next step is to let logback know that it will have to use JNDI to manage
+the context instances. This is done thanks to a System Property.
+In Jetty, adding an environment variable is done by adding the following
+xml element in the <em>JETTY_HOME/etc/jetty.xml</em> configuration file,
+nested in a <em>Configuration</em> element:
+</p>
+
+<div class="source"><pre><Call class="java.lang.System" name="setProperty">
+ <Arg>logback.ContextSelector</Arg>
+ <Arg>JNDI</Arg>
+</Call></pre></div>
+
+<p>
+Be aware that adding a <em>-Dlogback.ContextSelector=JNDI</em> to the java
+command when starting the server will not work. By doing this, the
+<code>LoggerFactory</code> instanciated by the server for its internal logging
+will try to use JNDI, when only the Web applications should attempt to retrieve
+their <code>LoggerContext</code> this way.
+</p>
+
+<h3>Configuring each Web application</h3>
+
+<p>
+While each Web application will need the logback jars to compile, they need not
+nor should be placed within the Web application's WAR file, except if you are
+using Jetty.
+</p>
+
+<p>This is due to <a href="http://docs.codehaus.org/display/JETTY/Classloading">
+Jetty's internal Classloading mechanism</a>.
+Consequently, the <em>logback-classic-VERSION.jar</em>
+and <em>slf4j-api-VERSION.jar</em> files should also be placed in the <em>WEB-INF/lib/</em>
+directory of your webapps when running Jetty.
+</p>
+
+<p>
+In each Web application's <em>web.xml</em> file, two JNDI environment entries
+are needed. The first one specifies the desired name of the application's
+<code>LoggerContext</code>. It takes the following form:
+</p>
+
+<div class="source"><pre><env-entry>
+ <description>JNDI logging context for this app</description>
+ <env-entry-name>logback/context-name</env-entry-name>
+ <env-entry-type>java.lang.String</env-entry-type>
+ <env-entry-value>ContextApp-A</env-entry-value>
+</env-entry></pre></div>
+
+<p>
+The second JNDI entry will lead logback to the application's own xml configuration
+file. It can be declared as shown below:
+</p>
+
+<div class="source"><pre><env-entry>
+ <description>URL for configuring logback context</description>
+ <env-entry-name>logback/configuration-resource</env-entry-name>
+ <env-entry-type>java.lang.String</env-entry-type>
+ <env-entry-value>logback-app-A.xml</env-entry-value>
+</env-entry></pre></div>
+
+<p>
+Specifying only the name of the file will lead logback to search for it in
+the Web application's <em>WEB-INF/classes/</em> directory.
+</p>
+
+<p>
+When the Web application is recycled or shutdown, it is very often
+useful to recycle the associated <code>LoggerContext</code>. This can
+be done by installing a <code>ServletContextListener</code> which will
+detach the context from the <code>ContextSelector</code> and shut it down.
+</p>
+
+<p>
+The <a href="../xref/ch/qos/logback/classic/selector/servlet/ContextDetachingSCL.html">
+<code>ContextDetachingSCL</code></a> class which
+ships with logback does exactly that. To use it, add the following
+lines to your Web application's <em>web.xml</em> file.
+</p>
+
+<div class="source"><pre><listener>
+ <listener-class>ch.qos.logback.classic.selector.servlet.ContextDetachingSCL</listener-class>
+</listener</pre></div>
+
+
+<p>
+Using the <code>ContextJNDISelector</code> might slow down your
+application, because of the JNDI call that is issued each time
+a <code>LoggerContext</code> is required. To prevent the cost
+of this call, logback ships with a <code>LoggerContextFilter</code>
+component. This filter is a <code>javax.servlet.Filter</code> implementation
+that gets the environment-specific <code>LoggerContext</code> and sets it
+in a <code>ThreadLocal</code> variable. Each time
+the <code>ContextSelector</code> will be called to provide the
+Web application's own <code>LoggerContext</code>, it will first check
+if the <code>ThreadLocal</code> variable is set. If it is, then the call
+to the JNDI environment will not be issued. The <code>LoggerContextFilter</code>
+class increases the performances by a wide margin.
+</p>
+
+<p>
+Like all servlet filters, the
+<a href="../xref/ch/qos/logback/classic/selector/servlet/LoggerContextFilter.html">
+<code>LoggerContextFilter</code></a> can act
+before and after the Web application's process. This allows the filter
+to set the <code>ThreadLocal</code> variable at the beginning of the process
+and to remove it once the Web application has finished processing the request.
+This behaviour permits the thread to be recycled for use by another Web
+application and still provide the correct <code>LoggerContext</code>.
+</p>
+
+<p>The <code>LoggerContextFilter</code> can be used by adding the following
+lines to your Web application's <em>web.xml</em> file.
+</p>
+
+<div class="source"><pre><filter>
+ <filter-name>LoggerContextFilter</filter-name>
+ <filter-class>ch.qos.logback.classic.selector.servlet.LoggerContextFilter</filter-class>
+</filter>
+<filter-mapping>
+ <filter-name>LoggerContextFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping></pre></div>
+
+<h4>Some recommandations</h4>
+
+<p>
+To avoid confusion, it is prudent to name each Web application
+in the <em>web.xml</em> file, as in:
+</p>
+
+<div class="source"><pre><display-name>Name_Of_My_WebApp</display-name></pre></div>
+
+<p>
+We recommend that you name logback configuration resources uniquely. In
+particualar, avoid naming the logback configuration resource as
+<em>logback.xml</em> for a non-default logger context.
+</p>
+
+<p>
+While trying to configure the Web application logback would search for
+the resource <em>logback.xml</em> using the thread context classloader. Thus,
+it would first attempt to locate <em>logback.xml</em> file using the
+classloader specific to the Web application. However, if the file
+<em>logback.xml</em> did not exist there (if you forgot to put a custom one in
+<em>WEB-INF/classes</em>), and if the file <em>logback.xml</em> existed higher up in the
+classloader tree, we could end up in a situation where the logger
+context for your Web application would be configured using the same
+file as that used to configure the default context. Such
+involuntary sharing of the same configuration by multiple repositories
+will result in corrupt log output.
+</p>
+<script src="../templates/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/manual/filters.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/manual/filters.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,770 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Chapter 6: Filters</title>
+<link rel="stylesheet" type="text/css" media="screen" href="../css/site.css" />
+</head>
+<body>
+<script src="../templates/header.js"></script>
+<div id="left">
+ <script src="../templates/left.js"></script>
+</div>
+<div id="right">
+ <script src="../templates/right.js"></script>
+</div>
+<div id="content"> <h2>Chapter 6: Filter chains</h2>
+ <div class="author">
+ Authors: Ceki Gülcü, Sébastien Pennec
+ </div>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <td>
+ <a 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"></img>
+ </a>
+ </td>
+ <td>
+ <p>Copyright © 2000-2006, QOS.ch</p>
+
+ <p>
+
+ This work is licensed under a
+ <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
+ Creative Commons
+ Attribution-NonCommercial-ShareAlike 2.5
+ License
+ </a>.
+
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ As we have seen, logback has several built-in ways for filtering log requests,
+ including the context-wide filter, logger-level selection rule and appender filters.
+ These provide high performance filtering for the most commonly encountered
+ cases. These filters are largely inspired from Linux ipchains or
+ iptables as they are called in more recent Linux kernels.
+ Logback filters are based on ternary logic allowing them to be assembled or chained
+ together to compose an arbitrarily complex filtering policy.
+ </p>
+
+ <div class="highlight">
+ <p>
+ In order to run the examples in this chapter, 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>
+
+ <p>
+ There are two main types of filters, namely <code>Filter</code> and
+ <code>TurboFilter</code>.
+ </p>
+
+ <h2>Logback Classic</h2>
+
+ <a name="Filter"></a>
+ <p><code>Filter</code> objects all implement the
+ <a href="../xref/ch/qos/logback/core/filter/Filter.html"><code>Filter</code></a>
+ abscract class. The <code>decide(Object event)</code> method is passed a
+ newly created <code>LoggingEvent</code> object.
+ </p>
+
+ <h3>Filter chains</h3>
+ <p>
+ This abstract class assumes that filters be organized in a linear chain.
+ Its member field next points to the next filter in the chain, or
+ <code>null</code> if there are no further filters in the chain.
+ Figure 6.1 depicts a sample filter chain consisting of three filters.
+ </p>
+
+ <img src="images/chapter6/filterChain.gif" alt="A sample filter chain"></img>
+
+ <p>
+ Filters are based on ternary logic. The <code>decide(Object event)</code>
+ method of each filter is called in sequence. This method returns one of the
+ enumerations <code>FilterReply.DENY</code>, <code>FilterReply.NEUTRAL</code> or
+ <code>FilterReply.ACCEPT</code>. If the returned value is <code>FilterReply.DENY</code>,
+ then the log event is dropped immediately without consulting the
+ remaining filters. If the value returned is <code>FilterReply.NEUTRAL</code>,
+ then the next filter in the chain is consulted. If there are no further filters
+ to consult, then the logging event is processed normally.
+ If the returned value is <code>FilterReply.ACCEPT</code>, then the logging
+ event is processed immediately skipping the remaining filters.
+ </p>
+
+ <p>
+ In logback-classic, <code>Filter</code> objects can only be added to <code>Appender</code>
+ instances. By adding filters to an appender you can filter events by various
+ criteria, such as the contents of the log message, the contents of the MDC,
+ the time of day or any other part of the logging event.
+ </p>
+
+ <h3>Implementing your own Filter</h3>
+
+ <p>
+ Creating your own filter is not difficult. All you have to do is extend the <code>Filter</code>
+ abstract class. The only method that you will have to implement is the <code>decide()</code>
+ method, allowing you to contentrate only on the behaviour of your filter.
+ </p>
+
+ <p>
+ The next class is all it takes to implement one's own filter. All it does is accept
+ logging events who's message contains the String <em>sample</em>. The filter will give a
+ neutral response to any logging event who's message does not contain this String.
+ </p>
+
+<em>Example 6.1: Basic custom filter (<a href="../xref/chapter6/SampleFilter.html">logback-examples/src/main/java/chapter6/SampleFilter.java</a>)</em>
+<div class="source"><pre>package chapter6;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.filter.Filter;
+import ch.qos.logback.core.spi.FilterReply;
+
+public class SampleFilter extends Filter {
+
+ @Override
+ public FilterReply decide(Object eventObject) {
+ LoggingEvent event = (LoggingEvent)eventObject;
+
+ if (event.getMessage().contains("sample")) {
+ return FilterReply.ACCEPT;
+ } else {
+ return FilterReply.NEUTRAL;
+ }
+ }
+}</pre></div>
+
+ <p>
+ What is shown above might be the simplest filter. Like any filter, it
+ can be attached to any appender using the <Filter> element, as
+ shown below:
+ </p>
+
+<em>Example 6.2: SampleFilter configuration (logback-examples/src/main/java/chapter6/SampleFilterConfig.xml)</em>
+<div class="source"><pre><configuration>
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <b><Filter class="chapter6.SampleFilter" /></b>
+
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <pattern>
+ %-4relative [%thread] %-5level %logger - %msg%n
+ </pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ Thanks to Joran, logback's powerful configuration framework, adding
+ an option to such a filter is very easy. Just add the corresponding
+ getter and setter methods in the class, and you can specify the
+ option's value in an xml element, nested within the <em>filter</em> element.
+ </p>
+
+ <p>
+ In case you want to implement a filter that provides different behaviour
+ depending on the result of its test (say, a filter that would accept or deny
+ an event depending on the content of its message), you can extend the
+ <a href="../xref/ch/qos/logback/core/filter/AbstractMatcherFilter.html">
+ <code>AbstractMatcherFilter</code></a> class. It will provide your filter with
+ two attribute: <em>OnMatch</em> and <em>OnMismatch</em>, that can be configured
+ like any other option.
+ </p>
+
+ <h3>Logback Filters</h3>
+
+ <p>
+ As the moment, there are two filters that ship with logback.
+ <a href="../xref/ch/qos/logback/classic/LevelFilter.html">
+ <code>LevelFilter</code></a> provides event filtering based on a <code>Level</code> value.
+ It the event's level is equal to the configured level, the filter accepts of denies
+ the event, depending on its configuration. It allows you to choose the
+ behaviour of logback for a precise given level. Here is a sample configuration that
+ uses <code>LevelFilter</code>.
+ </p>
+
+<em>Example 6.3: Sample LevelFilter configuration (logback-examples/src/main/java/chapter6/LevelFilterConfig.xml)</em>
+<div class="source"><pre><configuration>
+ <appender name="CONSOLE"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <b><filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <level>INFO</level>
+ <onMatch>ACCEPT</onMatch>
+ <onMismatch>DENY</onMismatch>
+ </filter></b>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <pattern>
+ %-4relative [%thread] %-5level %logger{30} - %msg%n
+ </pattern>
+ </layout>
+ </appender>
+ <root>
+ <level value="DEBUG" />
+ <appender-ref ref="CONSOLE" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ The second filter that ships with logback is
+ <a href="../xref/ch/qos/logback/classic/ThresholdFilter.html">
+ <code>ThresholdFilter</code></a>.
+ It is also based on level value, but acts as a threshold to deny any request
+ whose level is not equal or greater to the configured level. A sample
+ use of the <code>ThresholdFilter</code> is shown below.
+ </p>
+
+<em>Example 6.4: Sample ThresholdFilter configuration (logback-examples/src/main/java/chapter6/ThresholdFilterConfig.xml)</em>
+<div class="source"><pre><configuration>
+ <appender name="CONSOLE"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <b><filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+ <level>INFO</level>
+ </filter></b>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <pattern>
+ %-4relative [%thread] %-5level %logger{30} - %msg%n
+ </pattern>
+ </layout>
+ </appender>
+ <root>
+ <level value="DEBUG" />
+ <appender-ref ref="CONSOLE" />
+ </root>
+</configuration></pre></div>
+
+ <h3>Evaluator Filters</h3>
+
+ <p>
+ A special category of filters ships with logback. The
+ <a href="../xref/ch/qos/logback/core/filter/EvaluatorFilter.html">
+ <code>EvaluatorFilter</code></a> objects use an
+ <a href="../xref/ch/qos/logback/core/boolex/EventEvaluator.html">
+ <code>EventEvaluator</code></a>
+ to decide wether to accept or deny the request. This allows unprecedented
+ flexibility in the way that you can affect the logging event's filtering.
+ </p>
+
+ <p>
+ Creating a customized filter that makes use of <code>EventEvaluator</code> objects
+ works the same way as seen previously, except that one must extend the
+ <code>EvaluatorFilter</code> class, instead of the <code>Filter</code>
+ or <code>AbstractMatcherFilter</code> classes.
+ </p>
+
+ <a name="EventEvaluator"></a>
+ <h3>Event Evaluators</h3>
+
+ <p>
+ Events evaluators allow the user to enter java expressions, using
+ components of a logging event, and to check each logging event
+ against the compiled expression.
+ </p>
+
+ <p>
+ Let's see a sample configuration.
+ </p>
+
+<em>Example 6.5: Basic event evaluator usage (logback-examples/src/main/java/chapter6/basicEventEvaluator.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <b><filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+ <evaluator name="myEval">
+ <expression>message.contains("billing")</expression>
+ </evaluator>
+ <OnMismatch>NEUTRAL</OnMismatch>
+ <OnMatch>DENY</OnMatch>
+ </filter></b>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <pattern>
+ %-4relative [%thread] %-5level %logger - %msg%n
+ </pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="INFO" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ The bold part in the previous configuration adds an <code>EvaluatorFilter</code>
+ to a <code>ConsoleAppender</code>. An <code>EventEvaluator</code> is then given to
+ the filter. The <em>expression</em> element contains a recognizable java expression.
+ Notice that the <em>message</em> variable is defined implicitly. Logback provides
+ access to the internal components of a logging event and lets the user build her
+ expression at will.
+ </p>
+
+ <p>
+ The implicit variables available to the <code>EventEvaluator</code> are described below:
+ </p>
+
+ <table class="bodyTable">
+ <tr class="b">
+ <th>Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr class="a">
+ <td>event
+ </td>
+ <td><code>LoggingEvent</code></td>
+ <td>The logging event associated with the logging request.
+ All of the following variables are also available from the event. For example,
+ <code>event.getMessage()</code> returns the same String value as the <em>message</em>
+ variable.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>message
+ </td>
+ <td><code>String</code></td>
+ <td>The message created with the logging request.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>logger
+ </td>
+ <td><code>LoggerRemoteView</code></td>
+ <td>This object can be treated like a usual logger. In case the logging event
+ is serialized and sent to a remote machine, the usual logger object is
+ dropped and replaced by a <code>LoggerRemoteView</code> object, which
+ performs much better when serialized.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>level
+ </td>
+ <td><code>int</code></td>
+ <td>The int value corresponding to the level. To help create easily
+ expressions involving levels, the default value <em>DEBUG</em>,
+ <em>INFO</em>, <em>WARN</em> and <em>ERROR</em> are also available. Thus,
+ using <em>level > INFO</em> is a correct expression.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>timeStamp
+ </td>
+ <td><code>long</code></td>
+ <td>The timestamp corresponding to the logging event's creation.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>marker
+ </td>
+ <td><code>Marker</code></td>
+ <td>The <code>Marker</code> object associated with the logging request.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>mdc
+ </td>
+ <td><code>Map</code></td>
+ <td>A map containing all the MDC values at the time of the
+ creation of the logging event. A value can be access by using the
+ following expression: <em>mdc.get("myKey")</em>.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>throwable
+ </td>
+ <td><code>Throwable</code></td>
+ <td>The exception that was passed to the logger when it
+ was requested.
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ The behaviour of the filter is also defined by its <span class="option">OnMatch</span>
+ and <span class="option">OnMismatch</span> options. The configuration specifies thanks
+ to these elements the replies that the <code>EvaluatorFilter</code> must give once its
+ expression has been evaluated. The example above returns the value <code>FilterReply.ACCEPT</code>
+ when the message of the logging event contains the String <em>important</em>.
+ If <em>important</em> is not contained in the message, then the filter lets the next filter
+ evaluate this logging event.
+ </p>
+
+ <p>
+ Let us see an example of <code>EvaluatorFilter</code>. The <code>FilterEvents</code>
+ class issues ten logging requests, numbered from 0 to 9.
+ </p>
+
+ <p>
+ First, let us run the <code>FilterEvents</code> class with a configuration that does
+ not contain any filters. This can be done by issuing the following command:
+ </p>
+
+<div class="source"><pre>
+java chapter6.FilterEvents src/main/java/chapter6/basicConfiguration.xml
+</pre></div>
+
+ <p>
+ All requests will be displayed, as shown below:
+ </p>
+
+<div class="source"><pre>0 [main] INFO chapter6.FilterEvents - logging statement 0
+0 [main] INFO chapter6.FilterEvents - logging statement 1
+0 [main] INFO chapter6.FilterEvents - logging statement 2
+0 [main] DEBUG chapter6.FilterEvents - logging statement 3
+0 [main] INFO chapter6.FilterEvents - logging statement 4
+0 [main] INFO chapter6.FilterEvents - logging statement 5
+0 [main] ERROR chapter6.FilterEvents - <b>billing statement 6</b>
+0 [main] INFO chapter6.FilterEvents - logging statement 7
+0 [main] INFO chapter6.FilterEvents - logging statement 8
+0 [main] INFO chapter6.FilterEvents - logging statement 9</pre></div>
+
+ <p>
+ Suppose that we want to get rid of the billing information. We
+ can use an <code>EvaluatorFilter</code> configured as follows:
+ </p>
+
+<div class="source"><pre><configuration>
+ ...
+ <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+ <evaluator name="myEval">
+ <expression>message.contains("billing")</expression>
+ </evaluator>
+ <OnMismatch>NEUTRAL</OnMismatch>
+ <OnMatch>DENY</OnMatch>
+ </filter>
+ ...
+</configuration></pre></div>
+
+ <p>
+ This filter will deny any logging event whose message
+ contains the String <em>billing</em>. If we run the <code>FilterEvents</code>
+ class again, we obtain the following output:
+ </p>
+
+<div class="source"><pre>0 [main] INFO chapter6.FilterEvents - logging statement 0
+0 [main] INFO chapter6.FilterEvents - logging statement 1
+0 [main] INFO chapter6.FilterEvents - logging statement 2
+0 [main] DEBUG chapter6.FilterEvents - logging statement 3
+0 [main] INFO chapter6.FilterEvents - logging statement 4
+0 [main] INFO chapter6.FilterEvents - logging statement 5
+0 [main] INFO chapter6.FilterEvents - logging statement 7
+0 [main] INFO chapter6.FilterEvents - logging statement 8
+0 [main] INFO chapter6.FilterEvents - logging statement 9</pre></div>
+
+
+ <a name="TurboFilter"></a>
+ <h3>TurboFilters</h3>
+
+ <p>
+ <code>TurboFilter</code> objects all extend the
+ <a href="../xref/ch/qos/logback/classic/turbo/TurboFilter.html">
+ <code>TurboFilter</code></a> abstract class. Like the usual filters, they
+ use ternary logic to return their evaluation of the logging event.
+ </p>
+
+ <p>
+ Overall, they work much like the previously mentionned filters. However,
+ there are two main differences between <code>Filter</code> and
+ <code>TurboFilter</code> objects.
+ </p>
+
+ <p>
+ <code>TurboFilter</code> objects are tied to the logging context. Hence, they
+ are called not only when a given appender is used, but each and every time a logging
+ request is issued. Their scope is wider than appender-attached filters.
+ </p>
+
+ <p>
+ More importantly, they are called before the <code>LoggingEvent</code> object creation.
+ Their decision is made based on some of the logging event's components. They require
+ no logging event instanciation, nor any other treatement to provide their
+ filtering functionnalities. They are much more performant than the usual
+ <code>Filter</code> objects.
+ </p>
+
+ <h3>Implementing your own TurboFilter</h3>
+
+ <p>
+ To create your own <code>TurboFilter</code> component, just extend the
+ <code>TurboFilter</code> abstract class. As previously, when implementing
+ a custumized filter object, developing a custom <code>TurboFilter</code> only
+ ask that one implement the <code>decide()</code> method. In the next example, we
+ create a slightly more complex filter:
+ </p>
+
+<em>Example 6.6: Basic custom <code>TurboFilter</code> (<a href="../xref/chapter6/SampleTurboFilter.html">logback-examples/src/main/java/chapter6/SampleTurboFilter.java</a>)</em>
+<div class="source"><pre>package chapter6;
+
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.turbo.TurboFilter;
+import ch.qos.logback.core.spi.FilterReply;
+
+public class SampleTurboFilter extends TurboFilter {
+
+ String marker;
+ Marker markerToAccept;
+
+ @Override
+ public FilterReply decide(Marker marker, Logger logger, Level level,
+ String format, Object[] params, Throwable t) {
+
+ if (!isStarted()) {
+ return FilterReply.NEUTRAL;
+ }
+
+ if ((markerToAccept.equals(marker))) {
+ return FilterReply.ACCEPT;
+ } else {
+ return FilterReply.NEUTRAL;
+ }
+ }
+
+ public String getMarker() {
+ return marker;
+ }
+
+ public void setMarker(String markerStr) {
+ this.marker = markerStr;
+ }
+
+ @Override
+ public void start() {
+ if (marker != null && marker.trim().length() > 0) {
+ markerToAccept = MarkerFactory.getMarker(marker);
+ super.start();
+ }
+ }
+}
+</pre></div>
+
+ <p>
+ The <code>TurboFilter</code> above accepts events that contain a specific marker.
+ If said marker is not found, then the filter passes the responsability to
+ the next filter in the chain.
+ </p>
+
+ <p>
+ To allow more flexibility, the marker that will be tested can be specified
+ in the configuration file. Hence the getter and setter methods. We also implemented
+ the <code>start()</code> method, to check that the option has been specified during the
+ configuration process.
+ </p>
+
+ <p>
+ Here is a sample configuration that makes use of the newly created <code>TurboFilter</code>.
+ </p>
+
+<em>Example 6.7: Basic custom <code>TurboFilter</code> configuration (logback-examples/src/main/java/chapter6/sampleTurboFilterConfig.xml)</em>
+<div class="source"><pre><configuration>
+ <b><turboFilter class="chapter6.SampleTurboFilter">
+ <Marker>sample</Marker>
+ </turboFilter></b>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <pattern>
+ %-4relative [%thread] %-5level %logger - %msg%n
+ </pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ Logback classic ships with several <code>TurboFilter</code> classes ready for use.
+ The
+ <a href="../xref/ch/qos/logback/classic/turbo/MDCFilter.html"><code>MDCFilter</code></a>
+ check the presence of a given value in the MDC. On the other hand,
+ <a href="../xref/ch/qos/logback/classic/turbo/MarkerFilter.html"><code>MarkerFilter</code></a>
+ checks for the presence of a specific marker associated with the logging request.
+ </p>
+
+ <p>
+ Here is a sample configuration, using both <code>MDCFilter</code> and
+ <code>MarkerFilter</code>.
+ </p>
+
+<em>Example 6.8: <code>MDCFilter</code> and <code>MarkerFilter</code>
+configuration (logback-examples/src/main/java/chapter6/turboFilters.xml)</em>
+<div class="source"><pre><configuration>
+
+ <turboFilter class="ch.qos.logback.classic.turbo.MDCFilter">
+ <MDCKey>username</MDCKey>
+ <Value>sebastien</Value>
+ <OnMatch>ACCEPT</OnMatch>
+ </turboFilter>
+
+ <turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
+ <Marker>billing</Marker>
+ <OnMatch>DENY</OnMatch>
+ </turboFilter>
+
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%date [%thread] %-5level %logger - %msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="info"/>
+ <appender-ref ref="console" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ You can see this configuration in action by issuing the following command:
+ </p>
+
+<div class="source"><pre>
+java chapter6.FilterEvents src/main/java/chapter6/turboFilters.xml
+</pre></div>
+
+ <p>
+ As we've seen previously, the <code>FilterEvents</code> class creates 10 logging requests,
+ each with its number from 0 to 9. All of the requests are of level <em>INFO</em>,
+ just like the configured overall level, except for two requests.
+ The 3rd request, is a <em>DEBUG</em> level corresponding to the key <em>username</em>.
+ This obviously satisfies the first <code>TurboFilter</code> declared in the previous
+ configuration file. The 6th request, a <em>ERROR</em> level request,
+ which is issued along with the <em>billing</em> marker, matches
+ the second <code>TurboFilter</code>.
+ </p>
+
+ <p>
+ Here is the output of the previous command:
+ </p>
+
+<div class="source"><pre>
+2006-12-04 15:17:22,859 [main] INFO chapter6.FilterEvents - logging statement 0
+2006-12-04 15:17:22,875 [main] INFO chapter6.FilterEvents - logging statement 1
+2006-12-04 15:17:22,875 [main] INFO chapter6.FilterEvents - logging statement 2
+2006-12-04 15:17:22,875 [main] DEBUG chapter6.FilterEvents - logging statement 3
+2006-12-04 15:17:22,875 [main] INFO chapter6.FilterEvents - logging statement 4
+2006-12-04 15:17:22,875 [main] INFO chapter6.FilterEvents - logging statement 5
+2006-12-04 15:17:22,875 [main] INFO chapter6.FilterEvents - logging statement 7
+2006-12-04 15:17:22,875 [main] INFO chapter6.FilterEvents - logging statement 8
+2006-12-04 15:17:22,875 [main] INFO chapter6.FilterEvents - logging statement 9
+</pre></div>
+
+
+ <p>
+ One can see that the 3rd request, who should not be displayed if we
+ only followed the overall <em>INFO</em> level, appears anyway, because
+ it matched the first <code>TurboFilter</code> requirements and was accepted.
+ </p>
+
+ <p>
+ On the other hand, the 6th request, that is a <em>ERROR</em> level request
+ should have been displayed. But it satisfied the second <code>TurboFilter</code>
+ whose <span class="option">OnMatch</span> option is set to <em>DENY</em>.
+ Thus, the 6th request was not displayed.
+ </p>
+
+
+ <h2>Logback Access</h2>
+
+ <p>
+ Logback access benefits from most of the possibilities available
+ to the classic module. <code>Filter</code> objects are available and work
+ in the same way as their classic counterpart. They handle access' implementation
+ of logging events: <code>AccessEvent</code>.
+ Thus, a customized filter
+ for logback access is follows strictly the same rules than one for the
+ classic module, except for the event implemenation recieved as a parameter.
+ On the other hand,
+ <code>TurboFilter</code> objects are not available to the access module.
+ </p>
+
+ <h3>Filters</h3>
+
+ <p>
+ <code>EvaluatorFilter</code> objects, with their expressions, are available to
+ the access module. However, the variables that one can use to build an expression
+ are different. Only the <code>AccessEvent</code> object can be used, by inserting the
+ <em>event</em> variable in the expression. Although less wide than its classic
+ counterpart, the access evaluation filter is just as powerfull. All the
+ request and response components are reachable from the <em>event</em> variable.
+ </p>
+
+ <p>
+ Here is a sample configuration that will ensure that any 404 error will be displayed:
+ </p>
+
+<em>Example 6.9: Access Evaluator (logback-examples/src/main/java/chapter6/accessEventEvaluator.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <b><filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+ <evaluator name="myEval">
+ <expression>event.getStatusCode() == 404</expression>
+ </evaluator>
+ <OnMismatch>NEUTRAL</OnMismatch>
+ <OnMatch>ACCEPT</OnMatch>
+ </filter></b>
+ <layout class="ch.qos.logback.access.PatternLayout">
+ <pattern>
+ %h %l %u %t %r %s %b
+ </pattern>
+ </layout>
+ </appender>
+
+ <appender-ref ref="STDOUT" />
+</configuration></pre></div>
+
+ <p>
+ We might imagine a slightly more complex use of filters to ensure the display of 404 errors, but
+ to prevent polluting the output with endless accesses to CSS files. Here is what such a configuration
+ would look like:
+ </p>
+
+<em>Example 6.10: Access Evaluator (logback-examples/src/main/java/chapter6/accessEventEvaluator2.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <b><filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+ <evaluator name="Eval404">
+ <expression>event.getStatusCode() == 404</expression>
+ </evaluator>
+ <OnMismatch>NEUTRAL</OnMismatch>
+ <OnMatch>ACCEPT</OnMatch>
+ </filter>
+ <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+ <evaluator name="EvalCSS">
+ <expression>event.getRequestURI().contains("css")</expression>
+ </evaluator>
+ <OnMismatch>NEUTRAL</OnMismatch>
+ <OnMatch>DENY</OnMatch>
+ </filter></b>
+ <layout class="ch.qos.logback.access.PatternLayout">
+ <pattern>
+ %h %l %u %t %r %s %b
+ </pattern>
+ </layout>
+ </appender>
+
+ <appender-ref ref="STDOUT" />
+</configuration></pre></div>
+<script src="../templates/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/manual/index.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/manual/index.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,101 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Logback Manual</title>
+<link rel="stylesheet" type="text/css" media="screen" href="../css/site.css" />
+</head>
+<body>
+<script src="../templates/header.js"></script>
+<div id="left">
+ <script src="../templates/left.js"></script>
+</div>
+<div id="right">
+ <script src="../templates/right.js"></script>
+</div>
+<div id="content"> <h2>The logback manual</h2>
+
+ <p>The complete logback manual documents the latest version of
+ logback framework. In over 100 pages and dozens of concrete
+ examples, it covers both basic and advanced logback features:
+ </p>
+
+ <div>
+ <ul>
+ <li>the overall logback architecture</li>
+ <li>discussion of best logback practices and anti-patterns</li>
+ <li>logback configuration scripts in XML format</li>
+ <li>appenders</li>
+ <li>layouts</li>
+ <li>filter chains</li>
+ <li>logback diagnostic contexts</li>
+ <li>logback default initialization</li>
+ <li>logback in Servlet Containers</li>
+ </ul>
+ </div>
+
+
+ <div class="highlight">
+ <p>
+ If you wish to print chapters in this document, we recommend
+ that you do so using <a href="http://www.getfirefox.com">Firefox 2</a>, with <em>Adapt to
+ page size</em> enabled, or <a href="http://www.opera.com">Opera</a>.
+ </p>
+ <p>
+ To run the examples provided in this book, you might have
+ to run the provided script to setup your classpath. The scripts
+ can be found in the logback distributions, inside the <em>logback-examples</em>
+ directory.
+ </p>
+ </div>
+
+ <p>The logback manual describes the logback API in considerable
+ detail, including its features and design rationale. Authored by
+ Ceki Gülcü and Sébastien Pennec, the main
+ contributors to the logback project, the logback manual is
+ intended for developers already familiar with the Java language
+ but new to logback, as much as for experienced logback users. With
+ the aid of introductory material and many examples, new users
+ should quickly come up to speed.
+ </p>
+
+ <div>
+ <p>Without further ado, here are the contents of the manual:</p>
+
+ <ul>
+ <li>
+ <a href="introduction.html"><b>Chapter 1: Introduction to logback</b></a>
+ </li>
+ <li>
+ <a href="architecture.html"><b>Chapter 2: Architecture</b></a>
+ </li>
+ <li>
+ <a href="joran.html"><b>Chapter 3: Logback configuration with Joran</b></a>
+ </li>
+
+ <li>
+ <a href="appenders.html"><b>Chapter 4: Appenders</b></a>
+ </li>
+
+ <li>
+ <a href="layouts.html"><b>Chapter 5: Layouts</b></a>
+ </li>
+
+ <li>
+ <a href="filters.html"><b>Chapter 6: Filter chains</b></a>
+ </li>
+
+ <li>
+ <a href="mdc.html"><b>Chapter 7: Diagnostic Context</b></a>
+ </li>
+
+ <li>
+ <a href="contextSelector.html"><b>Chapter 8: Context Selector</b></a>
+ </li>
+
+ </ul>
+ </div>
+<script src="../templates/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/manual/introduction.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/manual/introduction.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,262 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Chapter 1: Introduction</title>
+<link rel="stylesheet" type="text/css" media="screen" href="../css/site.css" />
+</head>
+<body>
+<script src="../templates/header.js"></script>
+<div id="left">
+ <script src="../templates/left.js"></script>
+</div>
+<div id="right">
+ <script src="../templates/right.js"></script>
+</div>
+<div id="content">
+ <h2>Introduction</h2>
+ <div class="author">
+ Authors: Ceki Gülcü, Sébastien Pennec
+ </div>
+
+
+ <table class="bodyTable">
+ <tr class="a">
+ <td>
+ <a 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"></img>
+ </a>
+ </td>
+ <td>
+ <p>Copyright © 2000-2006, QOS.ch</p>
+
+ <p>
+
+ This work is licensed under a
+ <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
+ Creative Commons
+ Attribution-NonCommercial-ShareAlike 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 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>
+
+ <a name="Requirements"></a>
+ <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 at 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 type="1">
+
+ <p>Configure the logback environment. You can do so in several
+ more or less sophisticated ways. More on this later.</p>
+
+ <p>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.</p>
+
+ <p>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.</p>
+ </ol>
+
+ <a name="BuildingLogback"></a>
+ <h3>Building logback</h3>
+
+<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>
+<script src="../templates/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/manual/joran.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/manual/joran.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,1407 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Chapter3: Logback configuration</title>
+<link rel="stylesheet" type="text/css" media="screen" href="../css/site.css" />
+</head>
+<body>
+<script src="../templates/header.js"></script>
+<div id="left">
+ <script src="../templates/left.js"></script>
+</div>
+<div id="right">
+ <script src="../templates/right.js"></script>
+</div>
+<div id="content">
+
+ <h2>Chapter 3: Logback configuration with Joran</h2>
+ <div class="author">
+ Authors: Ceki Gülcü, Sébastien Pennec
+ </div>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <td>
+ <a 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"></img>
+ </a>
+ </td>
+ <td>
+ <p>Copyright © 2000-2006, QOS.ch</p>
+
+ <p>
+
+ This work is licensed under a
+ <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
+ Creative Commons
+ Attribution-NonCommercial-ShareAlike 2.5
+ License
+ </a>
+ .
+
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <div class="highlight">
+ <p>
+ In order to run the examples in this chapter, 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>
+
+<p>Joran stands for a cold north-west wind which, every now and then,
+blows force-fully on Lake Leman, a.k.a lake Geneva. Located right in
+the middle of Europe, the Leman happens to be the continent's largest
+sweet water reserve.
+</p>
+
+<p>
+ This document begins with an explanation of how to use it within
+ logback to configure precisely a logging strategy. Then,
+ <a href="#Joran">a second part</a> gives a generic explanation of
+ how the configuration framework in logback works, and how to use
+ it in your own applications.
+</p>
+
+<h2>Configuration in logback</h2>
+
+<p>
+Logback can be configured both programmatically and with an xml configuration
+file. Here are the steps that logback follows to try to configure itself:
+</p>
+
+<ul>
+ <p>Logback 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>
+
+<h3>Automatically configuring logback</h3>
+
+<p>
+The simplest way to configure logback is by letting logback use its
+<code>BasicConfigurator.configureDefaultContext()</code> method. Let us give a taste of how
+this is done with the help of an imaginary application called <code>MyApp1</code>.
+</p>
+
+<em>Example 3.1: Simple example of <code>BasicConfigurator</code> usage
+<a href="../xref/chapter3/MyApp1.html">(logback-examples/src/main/java/chapter3/MyApp1.java)</a></em>
+<div class="source"><pre>package chapter3;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MyApp1 {
+ final static Logger logger = LoggerFactory.getLogger(MyApp1.class);
+
+ public static void main(String[] args) {
+ logger.info("Entering application.");
+
+ Foo foo = new Foo();
+ foo.doIt();
+ logger.info("Exiting application.");
+ }
+}</pre></div>
+
+<p>
+There is no invokation of the <code>BasicConfigurator</code> here, since logback
+automatically calls it when no configuration files are found. It creates a rather
+simple logback setup. This call is hardwired to add a <code>ConsoleAppender</code> to
+the root logger. The output is formatting using a <code>PatternLayout</code> set to the
+pattern <em>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</em>. Note that
+by default the root logger is assigned to the <code>DEBUG</code> level.
+</p>
+
+<p>
+The output of the command <em>java chapter3.MyApp1</em> should be similar to:
+</p>
+
+<div class="source"><pre>16:06:09.031 [main] INFO chapter3.MyApp1 - Entering application.
+16:06:09.046 [main] DEBUG chapter3.Foo - Did it again!
+16:06:09.046 [main] INFO chapter3.MyApp1 - Exiting application.</pre></div>
+
+<p>
+If you are unable to run this command, then make sure that you have set
+your classpath correctly. The scripts provided in the
+<em>logback-examples/</em> directory will help you setting it up.
+</p>
+
+<p>
+As a side note, let us mention that in logback child loggers link only
+to their existing ancestors. In particular, the logger named <em>chapter3.Foo</em>
+is linked directly with the root logger, thereby circumventing the unused
+<em>chapter3</em> logger. This noticeably improves the performance
+of hierarchy walks and also slightly reduces logback's memory footprint
+</p>
+
+<p>
+The <code>MyApp1</code> class uses logback by calling the org.slf4j.LoggerFactory and
+org.slf4j.Logger classes, retrieve the loggers it wishes to use, and log away.
+For example, the only dependence of the <code>Foo</code> class on logback is the
+org.slf4j.LoggerFactory and org.slf4j.Logger import.
+Except code that configures logback (if such code exists) user code does not need to
+depend on logback. Given that SLF4J permits the use of any implementation under its
+abstraction layer, it is rather easy to migrate large bodies of code from an implementation
+to another. Logback also ships with a module called <em>log4j-bridge</em> that intercepts
+log4j calls and redirects them to the corresponding logback components. Thank to that module,
+one can migrate an entire application using log4j to logback just by replacing jars. More
+information about the <em>log4j-bridge</em> module in its
+<a href="../bridge.html">specific documentation page</a>.
+</p>
+
+<h3>The same using <code>JoranConfigurator</code></h3>
+
+<p>
+The previous example outputs logging information always in the same fixed manner.
+Fortunately, it is easy to modify <code>MyApp1</code> so that the log output can
+be controlled at runtime. Here is a slightly modified version called <code>MyApp2</code>.
+</p>
+
+<em>Example 3.2: Simple example of <code>BasicConfigurator</code> usage <a href="../xref/chapter3/MyApp2.html">(logback-examples/src/main/java/chapter3/MyApp2.java)</a></em>
+<div class="source"><pre>package chapter3;
+
+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;
+
+public class MyApp2 {
+ final static Logger logger = LoggerFactory.getLogger(MyApp2.class);
+
+ public static void main(String[] args) {
+ LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+
+ try {
+ <b>JoranConfigurator configurator = new JoranConfigurator();
+ configurator.setContext(lc);
+ lc.shutdownAndReset();
+ configurator.doConfigure(args[0]);</b>
+ } catch (JoranException je) {
+ je.printStackTrace();
+ }
+
+ logger.info("Entering application.");
+
+ Foo foo = new Foo();
+ foo.doIt();
+ logger.info("Exiting application.");
+ }
+}</pre></div>
+
+<p>
+<code>MyApp2</code> fetches the <code>LoggerContext</code>, creates a new
+<code>JoranConfigurator</code>, gives it the context and finally asks that
+the configurator parses a configuration file. A basic configuration file, that
+creates the same components as the default configuration would create, is
+listed below:
+</p>
+
+<em>Example 3.3: Basic configuration file (logback-examples/src/main/java/chapter3/sample0.xml)</em>
+<div class="source"><pre><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>
+Assuming the current directory is <em>logback-examples</em>, try running the
+<code>MyApp2</code> class by issuing the following command:
+</p>
+
+<div class="source"><pre>java chapter3.MyApp2 src/main/java/chapter3/sample0.xml</pre></div>
+
+<p>
+The ouput of this command is very similar to the output of the previous example, except
+that <code>MyApp2</code> retrieves a logger called <em>chapter3.MyApp2</em> instead of
+<code>chapter3.MyApp1</code>. The output will reflect the difference.
+</p>
+
+<div class="source"><pre>16:09:00.593 [main] INFO chapter3.MyApp2 - Entering application.
+16:09:00.593 [main] DEBUG chapter3.Foo - Did it again!
+16:09:00.593 [main] INFO chapter3.MyApp2 - Exiting application.</pre></div>
+
+<p>
+It is often very useful to define the logback debug configuration property in order
+to instruct logback to output internal configuration messages on the console. To achieve
+this, one only needs to add an attribute to the main <em>configuration</em> element in the
+configuration file, as shown above:
+</p>
+
+<em>Example 3.4: Basic configuration file using debug mode (logback-examples/src/main/java/chapter3/sample1.xml)</em>
+<div class="source"><pre><configuration debug="true">
+
+ <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>
+This should cause logback to print internal configuration messages in
+addition to the actual logs. Relaunching the <code>MyApp2</code> application with this
+new configuration file will ouput the following lines:
+</p>
+
+<div class="source"><pre>|-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch. \
+qos.logback.core.ConsoleAppender]
+|-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
+|-INFO in ch.qos.logback.core.joran.action.AppenderAction - Popping appender named [STDOUT] from the \
+object stack
+|-INFO in ch.qos.logback.classic.joran.action.LevelAction - root level set to DEBUG
+|-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to \
+Logger[root]
+|-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
+16:18:23.687 [main] INFO chapter3.MyApp2 - Entering application.
+16:18:23.687 [main] DEBUG chapter3.Foo - Did it again!
+16:18:23.687 [main] INFO chapter3.MyApp2 - Exiting application.</pre></div>
+
+<p>
+At the end of this output, one will immediately recognize the lines that were printed
+before. But right above stand the printing of logback's <code>Status</code> objects.
+<code>Status</code> objects are logback's powerful error reporting mechanism. They provide
+easy and precise access to logback's internal state.
+</p>
+
+<h3>XML Syntax</h3>
+
+<h4>Configuring Loggers</h4>
+
+<p>
+Loggers are configured using <em>logger</em> elements. A <em>logger</em> element takes exactly
+one mandatory name atttribute and an optional additivity attribute, which takes values
+<em>true</em> or <em>false</em>. The <em>logger</em> element admits at most one <em>level</em>
+element which is discussed next. It may also contain zero or more <em>appender-ref</em> elements;
+each appender thus referenced is added to the named logger. It is important to keep mind that
+each named logger that is declared with a <em>logger</em> element first has all its
+appenders removed and only then are the referenced appenders attached to it.
+In particular, if there are no appender references, then the named logger will
+lose all its appenders.
+</p>
+
+<p>
+The <em>level</em> element is used to set logger levels. It admits two attributes
+<em>value</em> and <em>class</em>. The value attribute can be one of the strings <em>DEBUG</em>,
+<em>INFO</em>, <em>WARN</em> <em>ERROR</em>, <em>ALL</em> or <em>OFF</em>.
+The special case-insensitive value <em>INHERITED</em>, or its synonym <em>NULL</em>,
+will force the level of the logger to be inherited from higher up in the hierarchy.
+Note that the level of the root logger cannot be inherited.
+If you set the level of a logger and later decide that it should inherit
+its level, then you need to specify <em>INHERITED</em> or its synonym <em>NULL</em>
+as the level value. The class attribute allows you to specify a custom
+level where the value of the attribute is the fully qualified name of a
+custom level class. You may alternatively use the <em>level#classname</em> syntax within
+the value attribute. The <em>level</em> element has no children.
+</p>
+
+<p>
+The <em>root</em> element configures the root logger. It does not admit
+any attributes because the additivity flag does not apply to the root logger.
+Moreover, since the root logger cannot be named, it does not admit a name
+attribute either. The <em>root</em> element admits at most one <em>level</em>
+element and zero or more <em>appender-ref</em> elements.
+Similar to the <em>logger</em> element, declaring a <em>root</em> element
+will have the effect of first closing and then detaching all its current
+appenders and only subsequently will referenced appenders, if any, will be added.
+In particular, if it has no appender references, then the root logger
+will lose all its appenders.
+</p>
+
+<p>
+Setting the level of a logger is as simple as declaring it and setting
+its level, as the next example illustrates. Suppose we are no longer interested
+in seeing any <code>DEBUG</code> level logs from any component
+belonging to the chapter3 package. The following configuration file shows how to achieve that.
+</p>
+
+<em>Example 3.5: Setting the level of a logger (logback-examples/src/main/java/chapter3/sample2.xml)</em>
+<div class="source"><pre><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>
+
+ <b><logger name="chapter3">
+ <level value="INFO" />
+ </logger></b>
+
+ <root>
+ <!-- The following level element is not necessary since the -->
+ <!-- level of the root level is set to DEBUG by default. -->
+ <level value="DEBUG" />
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration></pre></div>
+
+<p>
+This new configuration will yield the following output, when used with the
+same <code>chapter3.MyApp2</code> class.
+</p>
+
+<div class="source"><pre>17:34:07.578 [main] INFO chapter3.MyApp2 - Entering application.
+17:34:07.578 [main] INFO chapter3.MyApp2 - Exiting application.</pre></div>
+
+<p>
+Obviously, you can configure the levels of as many loggers as you wish.
+In the next configuration file we set the level of the <em>chapter3</em> logger to
+<code>INFO</code> but at the same time set the level of the <em>chapter3.Foo</em> logger
+to <code>DEBUG</code>.
+</p>
+
+<em>Example 3.6: Setting the level of multiple loggers (logback-examples/src/main/java/chapter3/sample3.xml)</em>
+<div class="source"><pre><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>
+
+ <b><logger name="chapter3">
+ <level value="INFO" />
+ </logger>
+
+ <logger name="chapter3.Foo">
+ <level value="DEBUG" />
+ </logger></b>
+
+ <root>
+ <!-- The following level element is not necessary since the -->
+ <!-- level of the root level is set to DEBUG by default. -->
+ <level value="DEBUG" />
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration></pre></div>
+
+<p>
+Running <code>MyApp2</code> with this configuration file will result in the
+following output on the console:
+</p>
+
+<div class="source"><pre>17:39:27.593 [main] INFO chapter3.MyApp2 - Entering application.
+17:39:27.593 [main] DEBUG chapter3.Foo - Did it again!
+17:39:27.593 [main] INFO chapter3.MyApp2 - Exiting application.</pre></div>
+
+<p>
+After <code>JoranConfigurator</code> configures logback using the <em>sample3.xml</em>
+file, the logger settings, more specifically their levels, are summarized in the following table.
+</p>
+
+<table class="bodyTable">
+ <tr class="b">
+ <th>Logger name</th>
+ <th>Assigned Level</th>
+ <th>Effective Level</th>
+ </tr>
+ <tr class="a">
+ <td>root</td>
+ <td><code>DEBUG</code></td>
+ <td><code>DEBUG</code></td>
+ </tr>
+ <tr class="b">
+ <td>chapter3</td>
+ <td><code>INFO</code></td>
+ <td><code>INFO</code></td>
+ </tr>
+ <tr class="a">
+ <td>chapter3.MyApp2</td>
+ <td><code>null</code></td>
+ <td><code>INFO</code></td>
+ </tr>
+ <tr class="b">
+ <td>chapter3.Foo</td>
+ <td><code>DEBUG</code></td>
+ <td><code>DEBUG</code></td>
+ </tr>
+</table>
+
+<p>
+It follows that the two logging statements of level <code>INFO</code> in the <code>MyApp2</code>
+class are enabled while the <code>debug</code> statement in <code>Foo.doIt()</code> method
+will also print without hindrance. Note that the level of the root logger is always
+set to a non-null value, which is <code>DEBUG</code> by default.
+One rather important point to remember is that the logger-level filter depends
+on the effective level of the logger being invoked, not the level of the logger
+where the appenders are attached. The configuration file <em>sample4.xml</em> is a case in point:
+</p>
+<em>Example 3.7: Logger level sample (logback-examples/src/main/java/chapter3/sample4.xml)</em>
+<div class="source"><pre><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>
+
+ <b><logger name="chapter3">
+ <level value="INFO" />
+ </logger></b>
+
+ <root>
+ <b><level value="OFF" /></b>
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration></pre></div>
+
+<p>
+The following table lists the loggers and their level setting after applying the
+<em>sample4.xml</em> configuration file.
+</p>
+
+<table class="bodyTable">
+ <tr class="a">
+ <th>Logger name</th>
+ <th>Assigned Level</th>
+ <th>Effective Level</th>
+ </tr>
+ <tr class="b">
+ <td>root</td>
+ <td><code>OFF</code></td>
+ <td><code>OFF</code></td>
+ </tr>
+ <tr class="a">
+ <td>chapter3</td>
+ <td><code>INFO</code></td>
+ <td><code>INFO</code></td>
+ </tr>
+ <tr class="b">
+ <td>chapter3.MyApp2</td>
+ <td><code>null</code></td>
+ <td><code>INFO</code></td>
+ </tr>
+ <tr class="a">
+ <td>chapter3.Foo</td>
+ <td><code>null</code></td>
+ <td><code>INFO</code></td>
+ </tr>
+</table>
+
+<p>
+The ConsoleAppender named <em>STDOUT</em>, the only configured appender in
+<em>sample4.xml</em>, is attached to the root logger whose level is set to
+<code>OFF</code>. However, running MyApp2 with configuration script
+<em>sample4.xml</em> will output:
+</p>
+
+<div class="source"><pre>17:52:23.609 [main] INFO chapter3.MyApp2 - Entering application.
+17:52:23.609 [main] INFO chapter3.MyApp2 - Exiting application.</pre></div>
+
+<p>
+Thus, the level of the root logger has no apparent effect because the loggers in
+<code>chapter3.MyApp2</code> and <code>chapter3.Foo</code> classes, namely
+<em>chapter3.MyApp2</em> and <em>chapter3.Foo</em>, inherit their level from the
+<em>chapter3</em> logger which has its level set to <code>INFO</code>.
+As noted previously, the <em>chapter3</em> logger exists by virtue of its
+declaration in the configuration file - even if the Java source code does not
+directly refer to it.
+</p>
+
+<h4>Configuring Appenders</h4>
+
+<p>
+Appenders are configured using <em>appender</em> elements. These elements admit
+two attributes <em>name</em> and <em>class</em> both of which are mandatory.
+The <em>name</em> attribute specifies the name of the appender whereas
+the <em>class</em> attribute specifies the fully qualified name of the class
+of which the named appender will be an instance.
+The <em>appender</em> may contain zero or one <em>layout</em> elements and
+zero or more <em>filter</em> elements. Appart from these two basic elements,
+<em>appender</em> elements may contain any element that corresponds to a setter
+method of the appender class, to configure the appender's options.
+</p>
+
+<p>
+The <em>layout</em> element takes a mandatory class attribute specifying
+the fully qualified name of the class of which the associated layout
+should be an instance. Like the <em>appender</em> element, it may contain
+other elements, referring to setter methods, to configure its options.
+</p>
+
+<p>
+Logging to multiple appenders is as easy as defining the various appenders
+and referencing them in a logger, as the next configuration file illustrates:
+</p>
+
+<em>Example 3.8: Multiple loggers (logback-examples/src/main/java/chapter3/multiple.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="<b>FILE</b>"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>myApp.log</file>
+
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>
+ myApp-%d{yyyy-MM-dd-HH-mm-ss}.log
+ </FileNamePattern>
+ </rollingPolicy>
+
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>
+ %date %level [%thread] %logger{10} [%file : %line] %msg%n
+ </Pattern>
+ </layout>
+ </appender>
+
+ <appender name="<b>STDOUT</b>"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>
+ %msg%n
+ </Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <b><appender-ref ref="FILE" />
+ <appender-ref ref="STDOUT" /></b>
+ </root>
+</configuration></pre></div>
+
+<p>
+This configuration scripts defines two appenders called <em>FILE</em> and <em>STDOUT</em>.
+The <em>FILE</em> appender logs to a file called <em>myApp.log</em>. The layout for this appender
+is a <code>PatternLayout</code> that outputs the date, level, thread name, logger name,
+file name and line number where the log request is located,
+the message and line separator character(s).
+The second appender called <code>STDOUT</code> outputs to the console.
+The layout for this appender outputs only the message string followed by a line separator.
+</p>
+
+<p>
+The appenders are attached to the root logger by referencing
+them by name within an <em>appender-ref</em> element. Note that each appender
+has its own layout. Layouts are usually not designed to be shared by multiple
+appenders. XML configuration files do not provide any syntactical
+means for sharing layouts.
+</p>
+
+<p>
+By default, <b>appenders are cumulative</b>: a logger will log to the appenders
+attached to itself (if any) as well as all the appenders attached to its ancestors.
+Thus, attaching the same appender to multiple loggers will cause
+logging output to be duplicated.
+</p>
+
+<em>Example 3.9: Duplicate appender (logback-examples/src/main/java/chapter3/duplicate.xml)</em>
+<div class="source"><pre><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>
+
+ <logger name="chapter3">
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+<p>
+Running <code>MyApp2</code> with <em>duplicate.xml</em> will yield the following output:
+</p>
+
+<div class="source"><pre>14:25:36.343 [main] INFO chapter3.MyApp2 - Entering application.
+14:25:36.343 [main] INFO chapter3.MyApp2 - Entering application.
+14:25:36.359 [main] DEBUG chapter3.Foo - Did it again!
+14:25:36.359 [main] DEBUG chapter3.Foo - Did it again!
+14:25:36.359 [main] INFO chapter3.MyApp2 - Exiting application.
+14:25:36.359 [main] INFO chapter3.MyApp2 - Exiting application.</pre></div>
+
+<p>
+Notice the duplicated output. The appender named <em>STDOUT</em> is attached to
+two loggers, to root and to <em>chapter3</em>. Since the root logger is the
+ancestor of all loggers and <em>chapter3</em> is the parent of <em>chapter3.MyApp2</em>
+and <em>chapter3.Foo</em>, logging request made with these two loggers
+will be output twice, once because <em>STDOUT</em> is attached to <em>chapter3</em>
+and once because it is attached to <em>root</em>.
+</p>
+
+<p>
+Appender additivity is not intended as a trap for new users.
+It is a quite convenient logback feature. For instance, you can configure
+logging such that log messages appear on the console (for all loggers in the system)
+while messages only from some specific set of loggers flow into a specific appender.
+</p>
+
+<em>Example 3.10: Multiple appender (logback-examples/src/main/java/chapter3/restricted.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="FILE"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>myApp.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>
+ myApp-%d{yyyy-MM-dd-HH-mm-ss}.log
+ </FileNamePattern>
+ </rollingPolicy>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>
+ %date %level [%thread] %logger{10} [%file : %line] %msg%n
+ </Pattern>
+ </layout>
+ </appender>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <logger name="chapter3">
+ <appender-ref ref="FILE" />
+ </logger>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+<p>
+In this example, the console appender will log all the messages (for all loggers in the system)
+whereas only logs under the <em>chapter3</em> tree go into the <em>myApp.log</em> file.
+</p>
+
+<h4>Overriding the default cumulative behaviour</h4>
+
+<p>
+In case the default cumulative behavior turns out to be unsuitable for
+one's needs, one can override it by setting the additivity flag to false.
+Thus, a branch in your logger tree may direct output to a set of appenders
+different than those of the rest of the tree.
+</p>
+
+<em>Example 3.11: Additivity flag (logback-examples/src/main/java/chapter3/additivityFlag.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="FILE"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>foo.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>
+ foo-%d{yyyy-MM-dd-HH-mm-ss}.log
+ </FileNamePattern>
+ </rollingPolicy>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>
+ %date %level [%thread] %logger{10} [%file : %line] %msg%n
+ </Pattern>
+ </layout>
+ </appender>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <logger name="chapter3.Foo" <b>additivity="false"</b>>
+ <appender-ref ref="FILE" />
+ </logger>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+<p>
+This example, the appender named <em>FILE</em> is attached to the <em>chapter3.Foo</em>
+logger. Moreover, the <em>chapter3.Foo</em> logger has its additivity flag set to false
+such that its logging output will be sent to the appender named <em>FILE</em> but
+not to any appender attached higher in the hierarchy. Other loggers remain
+oblivious to the additivity setting of the <em>chapter3.Foo</em> logger.
+Running the <code>MyApp2</code> application with the <em>additivityFlag.xml</em>
+configuration file will output results on the console from the <em>chapter3.MyApp2</em>
+logger.
+However, output from the <em>chapter3.Foo</em> logger will appear in the <em>foo.log</em> file
+and only in that file.
+</p>
+
+<h4>Variable substitution</h4>
+
+<p>
+All option <em>values</em> admit variable substitution. The syntax of variable
+substitution is similar to that of Unix shells. The string between an
+opening <em>${</em> and closing <em>}</em> is interpreted as a key.
+The value of the substituted variable can be defined as a system property
+in the configuration file itself or in a separate file linked to the
+configuration file. The value of the key
+is first searched in configuration file or linked properties file,
+and if not found there, it is then searched in system properties.
+The corresponding value replaces <em>${aKey}</em> sequence. For example,
+if <em>java.home</em> system property is set to <em>/home/xyz</em>,
+then every occurrence of the sequence <em>c:\Program Files\Java\jdk1.5.0_10\jre</em> will be
+interpreted as <em>/home/xyz</em>.
+</p>
+
+<p>
+The first example shows a declared property at the beginning of the
+configuration file. It is then used further down the file to specify
+the place to create the output file.
+</p>
+
+<em>Example 3.12: Simple Variable substitution (logback-examples/src/main/java/chapter3/variableSubstitution1.xml)</em>
+<div class="source"><pre><configuration>
+
+ <b><substitutionProperty name="user.home.dir" value="/Users/seb" /></b>
+
+ <appender name="FILE"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <b><file>${user.home.dir}/myApp.log</file></b>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>
+ myApp-%d{yyyy-MM-dd-HH}.log
+ </FileNamePattern>
+ </rollingPolicy>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>
+ %date %level [%thread] %logger{10} [%file : %line] %msg%n
+ </Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration></pre></div>
+
+
+<p>
+The next example shows the use of a System property to achieve the same result. The
+property is not declared anywhere, thus logback will look for it in the System properties.
+</p>
+
+<em>Example 3.13: System Variable substitution (logback-examples/src/main/java/chapter3/variableSubstitution2.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="FILE"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <b><file>${user.home.dir}/myApp.log</file></b>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>
+ myApp-%d{yyyy-MM-dd-HH}.log
+ </FileNamePattern>
+ </rollingPolicy>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>
+ %date %level [%thread] %logger{10} [%file : %line] %msg%n
+ </Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration></pre></div>
+
+<p>
+When many variables are used, it is often more convenient to create
+a separate file that will contain all the variables. Here is how one can
+do such a setup.
+</p>
+
+<em>Example 3.14: Variable substitution using a separate file (logback-examples/src/main/java/chapter3/variableSubstitution3.xml)</em>
+<div class="source"><pre><configuration>
+
+ <substitutionProperty file="variables1.properties" />
+
+ <appender name="FILE"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <b><file>${user.home.dir}/myApp.log</file></b>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>
+ myApp-%d{yyyy-MM-dd-HH}.log
+ </FileNamePattern>
+ </rollingPolicy>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>
+ %date %level [%thread] %logger{10} [%file : %line] %msg%n
+ </Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration></pre></div>
+
+<p>
+This configuration file contains a link to another file called <em>variables.properties</em>.
+The variables contained in that other file will be read and will thus be available to the
+logback configuration file. Here is what the <em>variable.properties</em> file looks like.
+</p>
+
+<em>Example 3.15: Variable file (logback-examples/src/main/java/chapter3/variables1.properties)</em>
+<div class="source"><pre>user.home.dir=/Users/seb</pre></div>
+
+<p>
+Nothing more is needed to declare the variable.
+</p>
+
+<p>
+Recursive subsitution is also available. If the user wants to use variables to
+specify not only the destination directory but also the file name, here is what she
+would write in her <em>variables.properties</em> file.
+</p>
+
+
+<em>Example 3.16: Recursive use of variables (logback-examples/src/main/java/chapter3/variables2.properties)</em>
+<div class="source"><pre>user.home.dir=/Users/seb
+fileName=myApp.log
+destination=${user.home.dir}/${fileName}</pre></div>
+
+<p>
+In the configuration file, only the last variable, <em>${destination}</em> will
+be used, as shown below:
+</p>
+
+<em>Example 3.17: Variable substitution using a separate file (logback-examples/src/main/java/chapter3/variableSubstitution4.xml)</em>
+<div class="source"><pre><configuration>
+
+ <substitutionProperty file="variables1.properties" />
+
+ <appender name="FILE"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <b><file>${destination}</file></b>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <FileNamePattern>
+ myApp-%d{yyyy-MM-dd-HH}.log
+ </FileNamePattern>
+ </rollingPolicy>
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>
+ %date %level [%thread] %logger{10} [%file : %line] %msg%n
+ </Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration></pre></div>
+
+
+<a name="Joran"></a>
+<h2>Using Joran in your own application</h2>
+
+<p>As we've seen, logback relies on Joran, a
+mature, flexible and powerful configuration framework. Many of the
+capabilities offered by logback modules are possible with the help of Joran.
+</p>
+
+<p>Joran is actually a generic configuration system which can be used
+independently of logging. To emphaises this point, we should mention
+that the logback-core module does not have a notion of loggers. In
+that sprit, many of the examples related to this tutorial, have
+nothing to do with loggers, appenders or layouts.
+</p>
+
+<p>The examples for this chapter can be found under
+<em>LOGBACK_HOME/logback-examples/src/main/java/chapter3</em>.
+</p>
+
+<p>To install joran, simply <a href="download.html">download</a>
+logback and add <em>logback-core-VERSION.jar</em> to your classpath.</p>
+
+<h2>Historical perspective</h2>
+
+<p>One of the most powerful features of the Java language is
+reflection. Reflection makes it possible to configure software systems
+declaratively. For example, many important properties of an EJB are
+configured with the <em>ejb.xml</em> file. While EJBs are written in Java, many
+of their properties are specified within the <em>ejb.xml</em> file. Similarly,
+logback settings can be specified in a configuration file, expressed
+in XML format.
+</p>
+
+<p>In log4j, logback's predecessor, <code>DOMConfigurator</code> that
+shipped with log4j version 1.2.x can parse configuration files written
+in XML. The <code>DOMConfigurator</code> was written in a way that
+forced to tweak it each time the structure of the configuration file
+changed. The modified code had to be recompiled and redeployed. Just
+as importantly, the code of the DOMConfigurator consists of loops
+dealing with children elements containing many interspersed if/else
+statements. One could not help but notice that that particular code
+reeked of redundancy. The <a href="http://jakarta.apache.org/commons/digester/">digester
+project</a> has shown that it is possible to parse XML files using
+pattern matching rules. At parse time, digester will apply the rules
+that match previously stated patterns. Rule classes are usually quite
+small and specialized. Consequently, they are relatively easy to
+understand and to maintain.
+</p>
+
+<p>Joran is heavily inspired by the commons-digester project but uses
+a slightly different terminology. In commons-digester, a rule can be
+seen as consisting of a pattern and a rule, as shown by the
+<code>Digester.addRule(String pattern, Rule rule)</code> method. We
+find it unnecessarily confusing to have a rule to consist of itself,
+not recursively but with a different meaning. In Joran, a rule
+consists of a pattern and an action. An action is invoked when a match
+occurs for the corresponding pattern. This relation between patterns
+and actions lies at the core of Joran. Quite remarkably, one can deal
+with quite complex requirements by using simple patterns, or more
+precisely with exact matches and wildcard matches. For example, the
+pattern <em>a/b</em> will match a <code><b></code> element nested within
+an <code><a></code> element but not a <code><c></code> element,
+even if nested within a <code><b></code> element. It is also
+possible to match a particular XML element, regardless of its nesting
+level, by using the <em>*</em> wildcard character. For example, the pattern
+<em>*/a</em> will match an <code><a></code> element at any nesting
+position within the document. Other types of patterns, for example
+<em>a/*</em>, are not currently supported by Joran.
+</p>
+
+<h2>SAX or DOM?</h2>
+
+<p>Due to the event-based architecture of the SAX API, a tool based on
+SAX cannot easily deal with forward references, that is, references to
+elements which are defined later than the current element being
+processed. Elements with cyclical references are equally
+problematic. More generally, the DOM API allows the user to perform
+searches on all the elements and make forward jumps.
+</p>
+
+<p>This extra flexibility initially led us to choose the DOM API as
+the underlying parsing API for Joran. After some experimentation, it
+quickly became clear that dealing with jumps to distant elements while
+parsing the DOM tree did not make sense when the interpretation rules
+were expressed in the form of patterns and actions. <em>Joran only
+needs to be given the elements in the XML document in a sequential,
+depth-first order.</em>
+</p>
+
+<p>Joran was first implemented in DOM. However, the author migrated to
+SAX in order to benefit form the location information provided to the
+user, that is, to an <code>org.w3.sax.ContentHandler</code>. With the
+help of location information, it becomes possible to display essential
+error reports to the user which include exact line and column. This
+extra information turns out to be handy in hunting down problems.
+</p>
+
+
+<h2>Actions</h2>
+
+<p>Actions extend the
+<code>ch.qos.logback.core.joran.action.Action</code> class which
+consists of the following abstract methods.
+</p>
+
+
+<div class="source"><pre>package ch.qos.logback.core.joran.action;
+
+import org.xml.sax.Attributes;
+import ch.qos.logback.core.joran.spi.ExecutionContext;
+
+public abstract class Action {
+
+
+ /**
+ * Called when the parser first encounters an element.
+ */
+ public abstract void begin(ExecutionContext ec,
+ String name,
+ Attributes attributes);
+
+ /**
+ * Called when the parser encounters the element end. At
+ * this stage, we can assume that child elements, if any,
+ * have been processed.
+ */
+ public abstract void end(ExecutionContext ec, String name);
+}</pre></div>
+
+<p>Thus, every action must implement the begin and end methods.</p>
+
+
+<h2>Execution context</h2>
+
+<p>To allow various actions to collaborate, the invocation of begin
+and end methods include an execution context as the first
+parameter. The execution context includes an object stack, an object
+map, an error list and a reference to the Joran interpreter invoking
+the action. Please see the
+<code>ch.qos.logback.core.joran.spi.ExecutionContext</code> class for
+the exact list of fields contained in the execution context.
+</p>
+
+<p>Actions can collaborate together by fetching, pushing or popping
+objects from the common object stack, or by putting and fetching keyed
+objects on the common object map. Actions can report any error
+conditions by adding error items on the execution context's
+<code>StatusManager</code>.
+</p>
+
+<a name="helloWorld"></a>
+<h3>A hello world example</h3>
+
+<p>The <em>logback-examples/src/main/java/chapter3/helloWorld/</em> directory includes a
+trivial action and Joran interpreter setup which just displays <em>Hello
+World</em> when a <hello-world> element is encountered in an XML file.
+It also includes the basic steps which are
+necessary to set up and invoke a Joran interpreter.
+</p>
+<p>
+The <em>hello.xml</em> file contains only one element, without any
+other nested elements. The <a href="../xref/chapter3/helloWorld/HelloWorldAction.html">
+<code>HelloWorldAction</code></a> class is
+a trivial implementation: it only prints "Hello World" in the console when
+it's <code>begin()</code> method is called.
+</p>
+<p>
+<a href="../xref/chapter3/helloWorld/HelloWorld.html"><code>HelloWorld</code></a>
+is a class that sets up the Joran interpreter,
+with the minimal steps necessary:
+</p>
+
+<ul>
+ <p>It creates a <code>RuleStore</code> and a <code>Context</code></p>
+ <p>It adds the <em>hello-world</em> pattern, with it's corresponding action</p>
+ <p>It creates a Joran interpreter, and passes the <code>RuleStore</code></p>
+ <p>It creates a SAX parser and parses the given file, specifying the newly created
+ Joran interpreter as the <code>ContentHandler</code></p>
+</ul>
+
+<p>
+It's last step is to print the content of the <code>Context</code>.
+Since Joran uses logback's powerfull <code>Status</code> objects for
+error reporting, one can have a good feedback on what happened during
+the parsing.
+</p>
+
+<p>
+In this example, the parsing is rather simple. The <em>hello-world</em> element
+will activate <code>HelloWorldAction</code>'s <code>begin()</code> and
+<code>end()</code> methods.
+In the first method, a simple call to <code>System.out.println()</code>
+will be issued, displaying <em>Hello World</em> in the console.
+</p>
+
+<a name="calculator"></a>
+<h3>Collaborating actions</h3>
+<p>
+The <em>logback-examples/src/main/java/joran/calculator/</em> directory includes several actions
+which collaborate together through the common object stack in order
+to accomplish simple computations.
+</p>
+<p>
+The <em>calculator1.xml</em> file contains a <code>computation</code> element,
+with a nested <code>literal</code> element.
+</p>
+<p>
+In the <a href="../xref/chapter3/calculator/Calculator1.html">
+<code>Calculator1</code></a> class, we declare various patterns and actions,
+that will collaborate and calculate a result based on the xml file. The simple
+<em>calculator1.xml</em> file only creates a computation and declares a literal
+value. The resulting parsing is pretty simple:
+</p>
+<ul>
+ <p>The <a href="../xref/chapter3/calculator/ComputationAction1.html">
+ <code>ComputationAction1</code></a> class' <code>begin()</code> method
+ is called</p>
+ <p>The <a href="../xref/chapter3/calculator/LiteralAction.html">
+ <code>LiteralAction</code></a> class' <code>begin()</code> and <code>end()</code>
+ methods are called</p>
+ <p>The <a href="../xref/chapter3/calculator/ComputationAction1.html">
+ <code>ComputationAction1</code></a> class' <code>end()</code> method
+ is called</p>
+</ul>
+<p>
+What is interesting here is the way that the Actions collaborate.
+The <code>LiteralAction</code> reads a literal value and pushes it in the
+object stack maintained by the <code>ExecutionContext</code>. Once done,
+any other action can pop the value to read or modify it. Here, the
+<code>end()</code> method of the <code>ComputationAction1</code> class pops
+the value from the stack and prints it.
+</p>
+<p>The <em>calculator2.xml</em> file is a bit more complex, but much more interesting.</p>
+<p>It contains the following elements:</p>
+
+<em>Example 3.18: Calculator configuration file (logback-examples/src/main/java/chapter3/calculator/calculator2.xml)</em>
+<div class="source"><pre><computation name="toto">
+ <literal value="7"/>
+ <literal value="3"/>
+ <add/>
+ <literal value="3"/>
+ <multiply/>
+</computation></pre></div>
+<p>
+Here, there are obviously more actions that will be part of the computation.
+</p>
+<p>When called, the <a href="../xref/chapter3/calculator/AddAction.html">
+<code>AddAction</code></a> class will remove the two integers at
+the bottom of the stack, add them and push the resulting integer at the
+top of the stack, for further use.</p>
+<p>Later in the computation, the <a href="../xref/chapter3/calculator/MultiplyAction.html">
+<code>MultiplyAction</code></a> class will be called.
+It will take the last two integers from the stack, multiply them and
+push the result in the stack.</p>
+<p>We have here two examples of action whose <code>begin()</code> method behaves in
+a certain, predictable way, but whose <code>end()</code> methods are empty.</p>
+
+<p>Finally, a <em>calculator3.xml</em> is also provided, to demonstrate the possibility
+elements that contain instances of the same element. Here's the content of
+<em>calculator3.xml</em>:</p>
+
+<em>Example 3.19: Calculator configuration file (logback-examples/src/main/java/chapter3/calculator/calculator3.xml)</em>
+<div class="source"><pre><computation name="toto">
+ <computation>
+ <literal value="7"/>
+ <literal value="3"/>
+ <add/>
+ </computation>
+
+ <literal value="3"/>
+ <multiply/>
+</computation></pre></div>
+
+<p>Much like the use of parentheses in an algebrical equation, the presence of
+a <code>computation</code> element nested in another is managed by the
+<a href="../xref/chapter3/calculator/ComputationAction2.html">
+<code>ComputationAction2</code></a> class using an internal stack. The well-formedness
+of XML will guarantee that a value saved by one <code>begin()</code> will be consumed
+only by the matching <code>end()</code> method.</p>
+
+<a name="newRule"></a>
+<h3>New-rule action</h3>
+<p>Joran includes an action which allows the Joran interpreter to lean
+new rules on the fly while interpreting the XML file containing the
+new rules. See the <em>logback-examples/src/main/java/joran/newRule/</em>
+directory for sample code.
+</p>
+<p>In this package, the <a href="../xref/chapter3/newRule/NewRuleCalculator.html">
+<code>NewRuleCalculator</code></a> class contains
+the same setup as we have seen so far, but for one line:</p>
+
+<div class="source"><pre>ruleStore.addRule(new Pattern("/computation/new-rule"), new NewRuleAction());</pre></div>
+
+<p>By adding this line, we ask Joran to allow new rules to be learnt
+at parsing time. It works pretty much like the other rules: it has a
+<code>begin()</code> and <code>end()</code> method, and is called each time
+the parser finds a <em>new-rule</em> element.</p>
+
+<p>When called, the <code>begin()</code> method looks for a <em>pattern</em>
+and a <em>actionClass</em> attribute. The action class is then instanciated
+and added to the <code>RuleStore</code>, along with its corresponding pattern.</p>
+
+<p>Here is how new rules can be declared in an xml file:</p>
+
+<div class="source"><pre><new-rule pattern="*/computation/literal" actionClass="chapter3.calculator.LiteralAction"/></pre></div>
+
+<p>Using new rule declarations, the preceding example, involving the calculation, could be
+expressed this way:</p>
+
+<em>Example 3.20: Configuration file using new rules on the fly (logback-examples/src/main/java/chapter3/newrule/new-rule.xml)</em>
+<div class="source"><pre><computation name="toto">
+ <new-rule pattern="*/computation/literal"
+ actionClass="chapter3.calculator.LiteralAction"/>
+ <new-rule pattern="*/computation/add"
+ actionClass="chapter3.calculator.AddAction"/>
+ <new-rule pattern="*/computation/multiply"
+ actionClass="chapter3.calculator.MultiplyAction"/>
+
+ <computation>
+ <literal value="7"/>
+ <literal value="3"/>
+ <add/>
+ </computation>
+
+ <literal value="3"/>
+ <multiply/>
+</computation></pre></div>
+
+<a name="implicit"></a>
+<h3>Implicit actions </h3>
+<p>The rules defined thus far are called explicit rules because they
+require an explicit pattern, hence fixing the tag name of the elements
+for which they apply.
+</p>
+
+<p>In highly extensible systems, the number and type of components to
+handle are innumerable so that it would become very tedious or even
+impossible to list all the applicable patterns by name.
+</p>
+
+<p>At the same time, even in highly extensible systems one can observe
+well-defined patterns linking the various parts together. Implicit
+rules come in very handy when processing components composed of
+sub-components unknown ahead of time. For example, Apache Ant is
+capable of handling tasks which contain tags unknown at compile time
+by looking at methods whose names start with <em>add</em>, as in
+<code>addFile</code>, or <code>addClassPath</code>.
+When Ant encounters an embedded tag within a task, it
+simply instantiates an object that matches the signature of the task
+class' add method and attaches the resulting object to the parent.
+</p>
+
+<p>Joran includes similar capability in the form of implicit
+actions. Joran keeps a list of implicit actions which can be applied
+if no explicit pattern matches the current XML element. However,
+applying an implicit action may not be always appropriate. Before
+executing the implicit action, Joran asks an implicit action whether
+it is appropriate in the current context. Only if the action replies
+affirmatively does Joran interpreter invoke the (implicit)
+action. This extra step makes it possible to support multiple implicit
+actions or obviously none, if no implicit action is appropriate for a
+given situation.
+</p>
+
+<p>For example, the <a href="../xref/ch/qos/logback/core/joran/action/NestedComponentIA.html">
+<code>NestedComponentIA</code></a> extending
+<a href="../xref/ch/qos/logback/core/joran/action/ImplicitAction.html">
+<code>ImplicitAction</code></a> , will
+instantiate the class specified in a nested component and attach it
+to the parent component by using setter method of the parent
+component and the nested element's name. Under certain circumstances,
+a nested action needs to be applied to an element say <a> and also
+to another element <b> nested within <a>. The current
+implementation of <code>NestedComponentIA</code> is capable of
+handling multiply nested elements requiring intervention by the same
+implicit action.
+</p>
+
+<p>Both <code>ImplicitAction</code> and <code>NestedComponentIA</code> are located in the
+<code>ch.qos.logback.core.joran.action</code> package.
+</p>
+
+<p>Refer to the <em>logback-examples/src/main/java/joran/implicit</em>
+directory for an example of an implicit action.
+</p>
+
+<p>In that directory, you will find two actions classes, one xml file and one
+class containing the setup of Joran.</p>
+
+<p>The <a href="../xref/chapter3/implicit/NOPAction.html">
+<code>NOPAction</code></a> class does nothing. It is used to set
+the context of the <em>foo</em> element, using this line:</p>
+
+<div class="source"><pre>ruleStore.addRule(new Pattern("*/foo"), new NOPAction());</pre></div>
+
+<p>After that, the implicit action, namely
+<a href="../xref/chapter3/implicit/PrintMeImplicitAction.html">
+<code>PrintMeImplicitAction</code></a>,
+is added to the <code>RuleStore</code>. This is done by simply adding a new
+instance of the action to the <code>Joran interpreter</code></p>
+
+<div class="source"><pre>ji.addImplicitAction(new PrintMeImplicitAction());</pre></div>
+
+<p>When called, the <code>isApplicable()</code> method of <code>PrintMeImplicitAction</code>
+checks the value of the <em>printme</em> attribute. If the value is <code>true</code>,
+the implicit action is applicable: its <code>begin()</code> method will be called.</p>
+
+<p>The <em>implicit1.xml</em> file contains the following lines:</p>
+
+<em>Example 3.21: Usage of implicit rules (logback-examples/src/main/java/chapter3/implicit/implicit1.xml)</em>
+<div class="source"><pre><foo>
+
+ <xyz printme="true">
+ <abc printme="true"/>
+ </xyz>
+
+ <xyz/>
+
+ <foo printme="true"/>
+
+</foo></pre></div>
+
+<p>As one can see, the first element will be printed, since it has a <em>printme</em>
+attribute, which bears the value <code>true</code>.</p>
+
+<p>The second element will not be printed, because no <em>printme</em> attibute is present.</p>
+
+<p>The last element will not be printed, although the required attribute is present.
+This is because implicit rules are called only if no explicit rules are defined. Since
+we added a <code>NOPAction</code> with the <em>*/foo</em> pattern, it will be used instead
+of the <code>PrintMeImplicitAction</code>.</p>
+
+<p>Running the example yields the following output:</p>
+
+<div class="source"><pre>Element <xyz> asked to be printed.
+Element <abc> asked to be printed.
+ERROR in ch.qos.logback.core.joran.spi.ExecutionContext at 1c5c1 - no applicable action \
+for <xyz>, current pattern is [/foo/xyz]</pre></div>
+
+<p>The last line was printed because of a call to <code>StatusPrinter</code> at the end
+of the main class.</p>
+
+<h3>Non goals</h3>
+
+<p>The Joran API is not intended to be used to parse documents with
+thousands of elements.
+</p>
+
+<script src="../templates/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/manual/layouts.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/manual/layouts.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,1753 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Chapter 5: Layouts</title>
+<link rel="stylesheet" type="text/css" media="screen" href="../css/site.css" />
+</head>
+<body>
+<script src="../templates/header.js"></script>
+<div id="left">
+ <script src="../templates/left.js"></script>
+</div>
+<div id="right">
+ <script src="../templates/right.js"></script>
+</div>
+<div id="content"> <h2>Chapter 5: Layouts</h2>
+ <div class="author">
+ Authors: Ceki Gülcü, Sébastien Pennec
+ </div>
+
+
+ <table class="bodyTable">
+ <tr class="a">
+ <td>
+ <a 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"></img>
+ </a>
+ </td>
+ <td>
+ <p>Copyright © 2000-2006, QOS.ch</p>
+
+ <p>
+
+ This work is licensed under a
+ <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
+ Creative Commons
+ Attribution-NonCommercial-ShareAlike 2.5
+ License
+ </a>
+ .
+
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <div class="highlight">
+ <p>
+ In order to run the examples in this chapter, 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>
+
+ <h2>What is a layout</h2>
+ <p>
+ While appenders are responsible for writing logging output
+ to an appender dependent device, layouts are responsible for
+ the format of the output. In case you were wondering,
+ layouts have nothing to do with large estates in Florida.
+ The
+ <code>format()</code>
+ method in the
+ <a href="../xref/ch/qos/logback/core/Layout.html"><code>Layout</code></a>
+ interface takes an object that represents
+ an event (of any type) and returns a String. A synopsis of the
+ <code>Layout</code> interface is shown below.
+ </p>
+ <div class="source"><pre>public interface Layout<E> extends ContextAware, LifeCycle {
+
+ String doLayout(E event);
+ String getHeader();
+ String getFooter();
+ String getContentType();
+}</pre></div>
+ <p>
+ This interface is rather simple and yet is sufficent for
+ many formatting needs. The Texan developer from Texas,
+ who you might know from Joseph Heller's <em>Catch-22</em>,
+ might exclaim:
+ it just takes two methods to implement a layout!!?
+ </p>
+
+ <h2>Logback classic</h2>
+
+ <p>
+ Logback classic only processes events of type
+ <a href="../xref/ch/qos/logback/classic/spi/LoggingEvent.html">
+ <code>ch.qos.logback.classic.spi.LoggingEvent</code></a>.
+ </p>
+
+ <h3>Writing your own Layout</h3>
+ <p>
+ Let us implement a simple and functional layout for the
+ classic module which prints the time elapsed since the start
+ of the application, the level of the logging event, the
+ caller thread between brackets, its logger name, a dash followed
+ by the event message and a new line.
+ </p>
+ <p>Sample output might look like:</p>
+ <div class="source">10489 DEBUG [main] com.marsupial.Pouch - Hello world.</div>
+
+ <p>Here is a possible implementation, authored by the Texan developer:</p>
+ <em>Example 5.0: Sample implementation of a Layout
+ <a href="../xref/chapter5/MySampleLayout.html">
+ (logback-examples/src/main/java/chapter5/MySampleLayout.java)</a></em>
+ <div class="source"><pre>package chapter5;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.LayoutBase;
+
+public class MySampleLayout extends LayoutBase<LoggingEvent> {
+
+ public String doLayout(LoggingEvent event) {
+ StringBuffer sbuf = new StringBuffer(128);
+ sbuf.append(event.getTimeStamp() - LoggingEvent.getStartTime());
+ sbuf.append(" ");
+ sbuf.append(event.getLevel());
+ sbuf.append(" [");
+ sbuf.append(event.getThreadName());
+ sbuf.append("] ");
+ sbuf.append(event.getLoggerRemoteView().getName());
+ sbuf.append(" - ");
+ sbuf.append(event.getFormattedMessage());
+ sbuf.append(LINE_SEP);
+ return sbuf.toString();
+ }
+}</pre></div>
+
+ <p>
+ Note that
+ <code>MySampleLayout</code>
+ extends <a href="../xref/ch/qos/logback/core/LayoutBase.html">
+ <code>LayoutBase</code></a>.
+ This class manages trivial components of a <code>Layout</code>
+ such as started or stopped status, header, footer and
+ content type access or logging context awareness. It allows
+ the developer to concentrate on the formatting she expects
+ from her <code>Layout</code>. Note that the <code>LayoutBase</code>
+ class is generic. By extending it, we precise the type that it will
+ have to handle, by adding <em><LoggingEvent></em> after its declaration.
+ </p>
+
+ <p>The marginally more interesting <code>doLayout(LoggingEvent event)</code>
+ method begins by instantiating a StringBuffer. It proceeds by adding various
+ fields of the event parameter. The Texan from Texas was careful to print
+ the formatted form of the message and not its object form.
+ This allows for logging requests which are passed object arrays to
+ build the message in its proper form.
+ </p>
+ <p>
+ In the above listing of the <code>Layout</code> class,
+ we had omitted the class static <code>LINE_SEP</code>
+ field which is simply assigned the value returned by
+ <code>System.getProperty("line.separator")</code>
+ method. After adding system dependent line separator
+ character(s), the format method returns the string buffer as
+ a String.
+ </p>
+ <p>
+ The <code>doLayout</code> method ignores any eventual exceptions contained
+ in the event. In a real world layout implementation, you would probably not want
+ to silently ignore exceptions.
+ </p>
+
+ <p>Custom layouts are configured as any other layout, as shown below:</p>
+
+ <em>Example 5.0: Configuration of MySampleLayout
+ (logback-examples/src/main/java/chapter5/sampleLayoutConfig.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <b><layout class="chapter5.MySampleLayout" /></b>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+ <p>The sample application <a href="../xref/chapter5/SampleLogging.html">
+ <code>chapter5.SampleLogging</code></a> configures logback with the
+ configuration script supplied as parameter and then logs a debug message,
+ followed by an error message. </p>
+
+ <p>
+ To run this example execute the command
+ <em>java chapter5.SampleLogging src/main/java/chapter5/sampleLayoutConfig.xml</em>
+ once in the <em>logback-examples</em> directory. This will produce the following
+ output:
+ </p>
+
+<div class="source"><pre>0 DEBUG [main] chapter5.SampleLogging - Everything's going well
+0 ERROR [main] chapter5.SampleLogging - ... not quite</pre></div>
+
+ <p>That was simple enough.
+ The skeptic Pyrrho of Elea, who insists that nothing is certain except
+ perhaps uncertainty itself, which is by no means certain either,
+ might ask: how about a layout with options?
+ The reader shall find a slightly modified version of our
+ custom layout in <code>MySampleLayout2.java</code>. She will discover that adding an option
+ to a layout is as simple as declaring a setter method for the option.
+ </p>
+ <p>
+ The
+ <a href="../xref/chapter5/MySampleLayout2.html"><code>MySampleLayout2</code>
+ </a>
+ class contains two attributes. The first one is a prefix that
+ can be added to the output. The second attribute is used to
+ choose wether to display the name of the thread from which
+ the logging request was sent.
+ </p>
+ <p>Here is the implementation of this class:</p>
+<div class="source"><pre>package chapter5;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.LayoutBase;
+
+public class MySampleLayout2 extends LayoutBase<LoggingEvent> {
+
+ String prefix = null;
+ boolean printThreadName = true;
+
+ <b>public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public void setPrintThreadName(boolean printThreadName) {
+ this.printThreadName = printThreadName;
+ }</b>
+
+ public String doLayout(LoggingEvent event) {
+ StringBuffer sbuf = new StringBuffer(128);
+ <b>if (prefix != null) {
+ sbuf.append(prefix + ": ");
+ }</b>
+ sbuf.append(event.getTimeStamp() - LoggingEvent.getStartTime());
+ sbuf.append(" ");
+ sbuf.append(event.getLevel());
+ <b>if (printThreadName) {
+ sbuf.append(" [");
+ sbuf.append(event.getThreadName());
+ sbuf.append("] ");
+ } else {
+ sbuf.append(" ");
+ }</b>
+ sbuf.append(event.getLoggerRemoteView().getName());
+ sbuf.append(" - ");
+ sbuf.append(event.getFormattedMessage());
+ sbuf.append(LINE_SEP);
+ return sbuf.toString();
+ }
+}</pre></div>
+
+ <p>Appart from the actual use of the two attributes, in the <code>doLayout</code> method,
+ the two setter methods are the only addition to the original class. Yet, it is sufficient
+ to allow the user to configure these attributes, as shown in the configuration file below:</p>
+
+<div class="source"><pre><configuration>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="chapter5.MySampleLayout2">
+ <b><prefix>MyPrefix</prefix>
+ <printThreadName>false</printThreadName></b>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ Note that the <code>PrintThreadName</code> attribute is a boolean
+ and not a <code>String</code>. It can be configured anyway by writing <em>true</em>
+ of <em>false</em> in the configuration file.
+ </p>
+
+
+ <a name="PatternLayout"></a>
+ <h3>PatternLayout</h3>
+
+ <p>
+ Logback classic ships with a flexible layout called
+ <a href="../xref/ch/qos/logback/classic/PatternLayout.html">
+ <code>PatternLayout</code></a>.
+ As all classic layouts, <code>PatternLayout</code>
+ takes a logging event and returns a String. However, the
+ returned String can be customized at will by tweaking its
+ conversion pattern.
+ </p>
+ <p>
+ The conversion pattern of
+ <code>PatternLayout</code>
+ is closely related to the conversion pattern of the
+ <code>printf()</code>
+ function in the C programming language. A conversion pattern
+ is composed of literal text and format control expressions
+ called conversion specifiers. You are free to insert any
+ literal text within the conversion pattern. Each conversion
+ specifier starts with a percent sign (%) and is followed by
+ optional format modifiers, a conversion word and optional
+ parameters between braces. The
+ conversion word controls the type of data to use, e.g.
+ logger name, level, date, thread name. The format modifiers
+ control such things as field width, padding, and left or
+ right justification. The following is a simple example.
+ </p>
+ <em>
+ Example 5.1: Sample usage of a PatternLayout
+ <a href="../xref/chapter5/PatternSample.html">
+ (logback-examples/src/main/java/chapter5/PatternSample.java)</a>
+ </em>
+ <div class="source"><pre>package chapter5;
+
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.PatternLayout;
+import ch.qos.logback.core.ConsoleAppender;
+
+public class PatternSample {
+
+ static public void main(String[] args) throws Exception {
+ Logger rootLogger = (Logger)LoggerFactory.getLogger("root");
+
+ <b>PatternLayout layout = new PatternLayout();
+ layout.setPattern("%-5level [%thread]: %message%n");
+ layout.start();</b>
+
+ ConsoleAppender<LoggingEvent> appender = new ConsoleAppender<LoggingEvent>();
+ appender.setContext(rootLogger.getLoggerContext());
+ appender.setLayout(layout); appender.start();
+
+ rootLogger.addAppender(appender);
+
+ rootLogger.debug("Message 1");
+ rootLogger.warn("Message 2");
+ }
+}</pre></div>
+
+ <p>
+ The conversion pattern is set to be <b>"%-5level [%thread]:
+ %message%n"</b>. Running PatternSample will yield the following
+ output on the console.
+ </p>
+ <div class="source"><pre>DEBUG [main]: Message 1
+WARN [main]: Message 2</pre></div>
+ <p>
+ Note that in the conversion pattern <b>"%-5level [%thread]:
+ %message%n"</b> there is no explicit separator between literal
+ text and conversion specifiers. When parsing a conversion
+ pattern,
+ <code>PatternLayout</code>
+ is capable of differentiating between literal text (space
+ characters, the brackets, colon character) and conversion
+ specifiers. In the example above, the conversion specifier
+ %-5level means the level of the logging event should be left
+ justified to a width of five characters. Format specifiers
+ will be explained in a short moment.
+ </p>
+ <p>
+ Note that usual brackets chars <em>(</em>
+ and <em>)</em> need to be escaped to be parsed correctly. These
+ brackets can be used by adding two backslashes before the bracket
+ like in <em>\\)</em> and <em>\\)</em>.
+ </p>
+ <p>
+ As mentionned previously, certain conversion specifiers can include
+ optional parameters which are declared
+ between braces following the conversion word. A sample conversion
+ specifier with options could be <em>%logger{10}</em>.
+ </p>
+
+ <p>The recognized conversions words along with their options are
+ described below. When multiple conversion words are listed on the left
+ column, they should be considered as aliases.
+ </p>
+
+ <table class="bodyTable">
+ <th>Conversion Word</th>
+ <th>Effect</th>
+
+ <tr class="b">
+ <td>
+ <b>c</b>{<em>length</em>} <br></br>
+ <b>l</b>{<em>length</em>} <br></br>
+ <b>lo</b>{<em>length</em>} <br></br>
+ <b>logger</b>{<em>length</em>} <br></br>
+ </td>
+
+ <td>
+ <p>
+ Used to output the name of the logger at the
+ source of the logging event.
+ </p>
+ <p>
+ The logger name conversion word can take an
+ integer as a first option. The
+ converter's abbreviation algorithm will shorten the logger name
+ without significant loss of meaning.
+ </p>
+
+ <p>The next table should clarify the matter.</p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Conversion Pattern</th>
+ <th>Logger name</th>
+ <th>Result</th>
+ </tr>
+ <tr class="b">
+ <td>%logger</td>
+ <td>mainPackage.sub.sample.Bar</td>
+ <td>mainPackage.sub.sample.Bar</td>
+ </tr>
+ <tr class="a">
+ <td>%logger{10}</td>
+ <td>mainPackage.sub.sample.Bar</td>
+ <td>m.s.s.Bar</td>
+ </tr>
+
+ <tr class="b">
+ <td>%logger{15}</td>
+ <td>mainPackage.sub.sample.Bar</td>
+ <td>m.s.sample.Bar</td>
+ </tr>
+
+ <tr class="a">
+ <td>%logger{16}</td>
+ <td>mainPackage.sub.sample.Bar</td>
+ <td>m.sub.sample.Bar</td>
+ </tr>
+
+ <tr class="b">
+ <td>%logger{26}</td>
+ <td>mainPackage.sub.sample.Bar</td>
+ <td>mainPackage.sub.sample.Bar</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr class="a">
+ <td>
+ <b>C</b>{<em>length</em>} <br></br>
+ <b>class</b>{<em>length</em>} <br></br>
+ </td>
+
+ <td>
+ <p>
+ Used to output the fully qualified class name of
+ the caller issuing the logging request.
+ </p>
+ <p>
+ Just like the <em>%logger</em> conversion word above, this
+ word can take an interger as it's first option
+ and use its abbreviation algorithm to
+ shorten the class name.
+ </p>
+ <p>
+ By default the class name is output in full.
+ </p>
+ <p>
+ Generating the caller class information is not particularly fast.
+ Thus, it's use should be avoided unless
+ execution speed is not an issue.
+ </p>
+ </td>
+ </tr>
+
+ <tr class="b">
+ <td>
+ <b>d</b>{<em>pattern</em>} <br></br>
+ <b>date</b>{<em>pattern</em>} <br></br>
+ </td>
+ <td>
+ <p>Used to output the date of the logging event.
+ The date conversion word may be followed by an option
+ enclosed between braces.</p>
+ <p>The option admits the same syntax as the time pattern
+ string of the <code>java.text.SimpleDateFormat</code>.</p>
+ <p>A shortcut to the ISO8601 format is available by
+ specifying the String <em>"ISO8601"</em> in the braces. If no option is set,
+ the converter uses <em>"ISO8601"</em> as the default value.</p>
+ <p>Here are some sample option values. They assume
+ that the actual date is Friday 20th of October, 2006 and that
+ the author finished his meal a short while ago.</p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Conversion Pattern</th>
+ <th>Result</th>
+ </tr>
+ <tr class="b">
+ <td>%date</td>
+ <td>2006-10-20 14:46:49,812</td>
+ </tr>
+ <tr class="a">
+ <td>%date{ISO8601}</td>
+ <td>2006-10-20 14:46:49,812</td>
+ </tr>
+ <tr class="b">
+ <td>%date{HH:mm:ss.SSS}</td>
+ <td>14:46:49.812</td>
+ </tr>
+ <tr class="a">
+ <td>%date{dd MMM yyyy ;HH:mm:ss.SSS}</td>
+ <td>20 oct. 2006;14:46:49.812 </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr class="b">
+ <td>
+ <b>F / file</b>
+ </td>
+
+ <td>
+ <p>
+ Used to output the file name where the logging
+ request was issued.
+ </p>
+ <p>
+ Generating the file information is not particularly fast.
+ Thus, it's use should be avoided unless
+ execution speed is not an issue.
+ </p>
+ </td>
+ </tr>
+
+ <tr class="a">
+ <td>
+ <b>caller{depth}</b>
+ <b>caller{depth, evaluator-1, ... evaluator-n}</b>
+ </td>
+
+ <td>
+ <p>
+ Used to output location information of the
+ caller which generated the logging event.
+ </p>
+ <p>
+ The location information depends on the JVM
+ implementation but usually consists of the fully
+ qualified name of the calling method followed by
+ the caller's source the file name and line
+ number between parentheses.
+ </p>
+ <p>
+ A integer can be added to the
+ <em>caller</em>
+ conversion specifier's options to configure the depth of
+ the information to be displayed.
+ </p>
+ <p>For example, <b>%caller{2}</b> would display the following excerpt:</p>
+
+<div class="source"><pre>0 [main] DEBUG - logging statement
+Caller+0 at mainPackage.sub.sample.Bar.sampleMethodName(Bar.java:22)
+Caller+1 at mainPackage.sub.sample.Bar.createLoggingRequest(Bar.java:17)</pre></div>
+ <p>And <b>%caller{3}</b> would display this other excerpt:</p>
+<div class="source"><pre>16 [main] DEBUG - logging statement
+Caller+0 at mainPackage.sub.sample.Bar.sampleMethodName(Bar.java:22)
+Caller+1 at mainPackage.sub.sample.Bar.createLoggingRequest(Bar.java:17)
+Caller+2 at mainPackage.ConfigTester.main(ConfigTester.java:38)</pre></div>
+
+ <p>
+ This conversion word can also use evaluators to test logging events
+ against a given criteria before creating the output. For example,
+ using <b>%caller{3, CALLER_DISPLAY_EVAL}</b> will display three lines
+ of stacktrace, only if the evaluator called <em>CALLER_DISPLAY_EVAL</em>
+ returns a <b>positive</b> answer.
+ </p>
+ <p>Evaluators are described
+ further down this document.
+ </p>
+ </td>
+ </tr>
+
+ <tr class="b">
+ <td>
+ <b>L / line</b>
+ </td>
+
+ <td>
+ <p>
+ Used to output the line number from where the
+ logging request was issued.
+ </p>
+ <p>
+ Generating the line number information is not particularly fast.
+ Thus, it's use should be avoided unless
+ execution speed is not an issue.
+ </p>
+ </td>
+ </tr>
+
+
+ <tr class="a">
+ <td>
+ <b>m / msg / message</b>
+ </td>
+ <td>
+ Used to output the application supplied message
+ associated with the logging event.
+ </td>
+ </tr>
+
+ <tr class="b">
+ <td>
+ <b>M / method</b>
+ </td>
+
+ <td>
+ <p>
+ Used to output the method name where the logging
+ request was issued.
+ </p>
+ <p>
+ Generating the method name is not particularly fast.
+ Thus, it's use should be avoided unless
+ execution speed is not an issue.
+ </p>
+ </td>
+ </tr>
+
+ <tr class="a">
+ <td>
+ <b>n</b>
+ </td>
+
+ <td>
+ <p>
+ Outputs the platform dependent line separator
+ character or characters.
+ </p>
+ <p>
+ This conversion word offers practically the
+ same performance as using non-portable line
+ separator strings such as "\n", or "\r\n". Thus,
+ it is the preferred way of specifying a line
+ separator.
+ </p>
+ </td>
+
+ </tr>
+
+ <tr class="b">
+ <td>
+ <b>p / le / level</b>
+ </td>
+ <td>Used to output the level of the logging event.</td>
+ </tr>
+
+ <tr class="a">
+
+ <td>
+ <b>r / relative</b>
+ </td>
+
+ <td>
+ Used to output the number of milliseconds elapsed
+ since the start of the application until the
+ creation of the logging event.
+ </td>
+ </tr>
+
+
+ <tr class="b">
+ <td>
+ <b>t / thread</b>
+ </td>
+
+ <td>
+ Used to output the name of the thread that generated
+ the logging event.
+ </td>
+
+ </tr>
+
+ <tr class="a">
+ <td>
+ <b>X</b>{<em>key</em>} <br></br>
+ <b>mdc</b>{<em>key</em>} <br></br>
+ </td>
+
+ <td>
+
+ <p>
+ Used to output the MDC (mapped diagnostic
+ context) associated with the thread that
+ generated the logging event.
+ </p>
+ <p>
+ If
+ <b>mdc</b>
+ conversion word is followed by a key
+ between braces, as in <b>%mdc{clientNumber}</b>,
+ then the value in the MDC corresponding
+ to the key will be output.
+ </p>
+ <p>
+ If no option is given, then
+ the entire content of the MDC will be output in the format
+ "key1=val1, key2=val2".
+ </p>
+
+ <p>
+ See
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/classic/MDC.html">
+ MDC
+ </a>
+ class for more details.
+ </p>
+
+ </td>
+ </tr>
+ <tr class="b">
+ <td>
+ <b>ex</b>{<em>length</em>} <br></br>
+ <b>throwable</b>{<em>length</em>} <br></br>
+ <b>ex{length, evaluator-1, ..., evaluator-n}</b>
+ <b>throwable{length, evaluator-1, ..., evaluator-n}</b>
+ </td>
+
+ <td>
+ <p>
+ Used to output the stack trace of the exception associated
+ with the logging event, if any. By default the full stack trace
+ will be output.
+ </p>
+ <p>The <em>throwable</em> conversion word can followed by one of
+ the following options:
+ </p>
+ <ul>
+ <p><em>short</em>: prints the first line of the stack trace</p>
+ <p><em>full</em>: prints the full stack trace</p>
+ <p>Any integer: prints the given number of lines of the stack trace</p>
+ </ul>
+
+ <p>Here are some examples:</p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <th>Conversion Pattern</th>
+ <th>Result</th>
+ </tr>
+ <tr class="b">
+ <td>%ex</td>
+ <td><pre>mainPackage.foo.bar.TestException: Houston we have a problem
+ at mainPackage.foo.bar.TestThrower.fire(TestThrower.java:22)
+ at mainPackage.foo.bar.TestThrower.readyToLaunch(TestThrower.java:17)
+ at mainPackage.ExceptionLauncher.main(ExceptionLauncher.java:38)</pre></td>
+ </tr>
+ <tr class="a">
+ <td>%ex{short}</td>
+ <td><pre>mainPackage.foo.bar.TestException: Houston we have a problem
+ at mainPackage.foo.bar.TestThrower.fire(TestThrower.java:22)</pre></td>
+ </tr>
+ <tr class="b">
+ <td>%ex{full}</td>
+ <td><pre>mainPackage.foo.bar.TestException: Houston we have a problem
+ at mainPackage.foo.bar.TestThrower.fire(TestThrower.java:22)
+ at mainPackage.foo.bar.TestThrower.readyToLaunch(TestThrower.java:17)
+ at mainPackage.ExceptionLauncher.main(ExceptionLauncher.java:38)</pre></td>
+ </tr>
+ <tr class="a">
+ <td>%ex{2}</td>
+ <td><pre>mainPackage.foo.bar.TestException: Houston we have a problem
+ at mainPackage.foo.bar.TestThrower.fire(TestThrower.java:22)
+ at mainPackage.foo.bar.TestThrower.readyToLaunch(TestThrower.java:17)</pre></td>
+ </tr>
+ </table>
+
+ <p>
+ This conversion word can also use evaluators to test logging events
+ against a given criteria before creating the output. For example,
+ using <b>%ex{full, EX_DISPLAY_EVAL}</b> will display the full
+ stacktrace of the exception, only if the evaluator called <em>EX_DISPLAY_EVAL</em>
+ returns a <b>negative</b> answer. Evaluators are described
+ further down this document.
+ </p>
+ </td>
+ </tr>
+
+ <tr class="b">
+ <td>
+ <b>marker</b>
+ </td>
+
+ <td>
+ <p>
+ Used to output the marker associated with the logger request.
+ </p>
+ <p>
+ If there is a single marker available, its name is displayed.
+ In case the marker has children markers, the converter displays
+ the parent's and children's names as shown below.
+ </p>
+ <p>
+ <em>parentName [ child1, child2 ]</em>
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+
+ <td>
+ <b>%</b>
+ </td>
+
+ <td>The sequence %% outputs a single percent sign.</td>
+ </tr>
+
+ </table>
+ <p>
+ By default the relevant information is output as is.
+ However, with the aid of format modifiers it is possible to
+ change the minimum field width, the maximum field width and
+ justification.
+ </p>
+ <p>
+ The optional format modifier is placed between the percent
+ sign and the conversion character or word.
+ </p>
+ <p>
+ The first optional format modifier is the
+ <em>left justification flag</em>
+ which is just the minus (-) character. Then comes the
+ optional
+ <em>minimum field width</em>
+ modifier. This is a decimal constant that represents the
+ minimum number of characters to output. If the data item
+ contains fewer characters, it is padded on either the left
+ or the right until the minimum width is reached. The default
+ is to pad on the left (right justify) but you can specify
+ right padding with the left justification flag. The padding
+ character is space. If the data item is larger than the
+ minimum field width, the field is expanded to accommodate
+ the data. The value is never truncated.
+ </p>
+ <p>
+ This behavior can be changed using the
+ <em>maximum field width</em>
+ modifier which is designated by a period followed by a
+ decimal constant. If the data item is longer than the
+ maximum field, then the extra characters are removed from
+ the <em>beginning</em>
+ of the data item. For example, if the
+ maximum field width is eight and the data item is ten
+ characters long, then the first two characters of the data
+ item are dropped. This behavior deviates from the printf
+ function in C where truncation is done from the end.
+ </p>
+ <p>
+ Truncation from the end is possible by appending a minus
+ character right after the period. In that case, if the
+ maximum field width is eight and the data item is ten
+ characters long, then the last two characters of the data
+ item are dropped.
+ </p>
+ <p>
+ Below are various format modifier examples for the logger
+ conversion specifier.
+ </p>
+
+ <table class="bodyTable">
+ <th>Format modifier</th>
+ <th>Left justify</th>
+ <th>Minimum width</th>
+ <th>Maximum width</th>
+ <th>Comment</th>
+
+ <tr class="b">
+ <td>%20logger</td>
+ <td>false</td>
+ <td>20</td>
+ <td>none</td>
+ <td>
+ Left pad with spaces if the category name is less
+ than 20 characters long.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>%-20logger</td>
+ <td>true</td>
+ <td>20</td>
+ <td>none</td>
+ <td>
+ Right pad with spaces if the logger name is less
+ than 20 characters long.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>%.30logger</td>
+ <td>NA</td>
+ <td>none</td>
+ <td>30</td>
+ <td>
+ Truncate from the beginning if the logger name is
+ longer than 30 characters.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>%20.30logger</td>
+ <td>false</td>
+ <td>20</td>
+ <td>30</td>
+ <td>
+ Left pad with spaces if the logger name is shorter
+ than 20 characters. However, if logger name is
+ longer than 30 characters, then truncate from the
+ beginning.
+ </td>
+ </tr>
+ <tr class="b">
+ <td>%-20.30logger</td>
+ <td>true</td>
+ <td>20</td>
+ <td>30</td>
+ <td>
+ Right pad with spaces if the logger name is shorter
+ than 20 characters. However, if logger name is
+ longer than 30 characters, then truncate from the
+ <em>beginning</em>.
+ </td>
+ </tr>
+ <tr class="a">
+ <td>%.-30logger</td>
+ <td>NA</td>
+ <td>none</td>
+ <td>30</td>
+ <td>
+ Truncate from the <em>end</em> if the logger name is
+ longer than 30 characters.
+ </td>
+ </tr>
+ </table>
+
+ <p>Here are some examples of the format modifier truncation:</p>
+
+
+ <table class="bodyTable">
+ <th>Format modifier</th>
+ <th>Logger name</th>
+ <th>Result</th>
+ <tr class="b">
+ <td>[%-20.20logger]</td>
+ <td>main.Name</td>
+ <td><pre>[main.Name ]</pre></td>
+ </tr>
+ <tr class="a">
+ <td>[%20.-20logger]</td>
+ <td>main.Name</td>
+ <td><pre>[ main.Name]</pre></td>
+ </tr>
+ <tr class="b">
+ <td>[%-10.10logger]</td>
+ <td>main.foo.foo.bar.Name</td>
+ <td><pre>[o.bar.Name]</pre></td>
+ </tr>
+ <tr class="a">
+ <td>[%10.-10logger]</td>
+ <td>main.foo.foo.bar.Name</td>
+ <td><pre>[main.foo.f]</pre></td>
+ </tr>
+ </table>
+
+ <h3>Option handling</h3>
+
+ <p>
+ A conversion specifier can be followed by options between
+ braces. We have already seen some of the
+ possibilities offered by logback's option handling with, for
+ example, the MDC conversion specifier:
+ <em>%mdc{someKey}</em>.
+ </p>
+ <p>A conversion specifier might have more than one options. For example,
+ a conversion specifier that uses evaluators, which we will cover very soon,
+ simply adds the evaluator names to the option list, as shown below:</p>
+
+ <div class="source"><pre>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <param name="Pattern" value="%-4relative [%thread] %-5level - %msg%n \
+ <b>%caller{2, DISP_CALLER_EVAL, OTHER_EVAL_NAME, THIRD_EVAL_NAME}</b>" />
+ </layout>
+ </appender></pre></div>
+
+
+
+
+ <h4>Evaluators</h4>
+ <p>
+ Another use case for adding options to a conversion
+ specifier is when
+ <code>PatternLayout</code>
+ is used with
+ <a href="../xref/ch/qos/logback/core/boolex/EventEvaluator.html">
+ <code>EventEvaluator</code></a> objects.
+ </p>
+ <p>
+ <code>EventEvaluator</code> objects
+ have the responsability to check wether a given event
+ matches a given criteria.
+ </p>
+ <p>
+ Let's look at an example using
+ <code>EventEvaluator</code> objects.
+ The following configuration file outputs the logging
+ events to the console, displaying date, thread, level,
+ message and caller data.
+ </p>
+ <p>
+ Since displaying the caller data of a logging event is rather
+ expensive, this information will be displayed only when the
+ logging request comes from a specific logger, and whose
+ message contains a certain string. By doing that, we make
+ sure that only the specific logging requests will have
+ their caller information generated and displayed, without
+ penalizing application performance.
+ </p>
+
+ <p>
+ Here is how to configure logback to behave like we
+ described:
+ </p>
+ <em>
+ Example 5.2: Sample usage of EventEvaluators
+ (logback-examples/src/main/java/chapter5/callerEvaluatorConfig.xml)
+ </em>
+ <div class="source"><pre><configuration>
+ <b><evaluator name="DISP_CALLER_EVAL">
+ <Expression>logger.getName().contains("chapter5") &amp;&amp; \
+ message.contains("who calls thee")</Expression>
+ </evaluator></b>
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <param name="Pattern" value="%-4relative [%thread] %-5level - %msg%n \
+ <b>%caller{2, DISP_CALLER_EVAL}</b>" />
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+ <p>Please note that the & value cannot be written like one would do in a java
+ class, because of XML encoding rules.</p>
+ <p>Let us test this configuration with the following code.</p>
+ <em>
+ Example 5.2: Sample usage of EventEvaluators
+ <a href="../xref/chapter5/CallerEvaluatorExample.html">
+ (logback-examples/src/main/java/chapter5/CallerEvaluatorExample.java)</a>
+ </em>
+ <div class="source"><pre>package chapter5;
+
+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 CallerEvaluatorExample {
+
+ public static void main(String[] args) {
+ Logger logger = LoggerFactory.getLogger(CallerEvaluatorExample.class);
+ LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+
+ try {
+ JoranConfigurator configurator = new JoranConfigurator();
+ configurator.setContext(lc);
+ configurator.doConfigure(args[0]);
+ } catch (JoranException je) {
+ StatusPrinter.print(lc);
+ }
+
+ for (int i = 0; i < 5; i++) {
+ if (i == 3) {
+ logger.debug("who calls thee?");
+ } else {
+ logger.debug("I know me " + i);
+ }
+ }
+ }
+}</pre></div>
+ <p>
+ This excerpt does nothing too fancy. Five logging requests
+ are issued, the third one being different from the others.
+ </p>
+ <p>
+ When a logging request is sent, the corresponding logging
+ event will pass through the evaluation process. Here,
+ the third request will match the evaluation,
+ causing its caller data to be displayed.
+ </p>
+ <p>
+ Here is the output of the
+ <code>CallerEvaluatorExample</code>
+ class.
+ </p>
+ <div class="source"><pre>0 [main] DEBUG - I know me 0
+0 [main] DEBUG - I know me 1
+0 [main] DEBUG - I know me 2
+0 [main] DEBUG - who calls thee?
+Caller+0 at chapter5.CallerEvaluatorExample.main(CallerEvaluatorExample.java:28)
+
+0 [main] DEBUG - I know me 4</pre></div>
+
+ <p>
+ Of course, one can change the expression to match a real
+ world situation. An expression testing logger name and
+ request level could also be meaningful: all logging requests of
+ level <em>WARN</em> and up, coming from a sensible part of an application
+ like a financial transaction module, would have their caller data displayed.
+ </p>
+ <p><b>Important:</b> With the <em>caller</em> conversion specifier, the data is
+ displayed when <em>the expression evaluates to <b>true</b>.</em></p>
+ <p>
+ Let us look at a different situation. When exceptions are included in
+ a logging request, their stack trace is usually displayed. However, in some cases,
+ one might want to supress the stack trace of specific exception.
+ </p>
+ <p>The java code shown below creates five log requests, each one
+ with an exception. However, we do not want to have the stack trace of the
+ third request to be output.</p>
+
+<div class="source"><pre>package chapter5;
+
+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 ExceptionEvaluatorExample {
+
+ public static void main(String[] args) {
+ Logger logger = LoggerFactory.getLogger(ExceptionEvaluatorExample.class);
+ LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+
+ try {
+ JoranConfigurator configurator = new JoranConfigurator();
+ configurator.setContext(lc);
+ configurator.doConfigure(args[0]);
+ } catch (JoranException je) {
+ StatusPrinter.print(lc);
+ }
+ for (int i = 0; i < 5; i++) {
+ if (i == 3) {
+ logger.debug("logging statement " + i, new TestException(
+ "do not display this"));
+ } else {
+ logger.debug("logging statement " + i, new Exception("display"));
+ }
+ }
+ }
+}</pre></div>
+
+ <p>The following configuration will allow that.</p>
+ <em>
+ Example 5.3: Sample usage of EventEvaluators
+ (logback-examples/src/main/java/chapter5/exceptionEvaluatorConfig.xml)
+ </em>
+ <div class="source"><pre><configuration>
+
+ <b><evaluator name="DISPLAY_EX_EVAL">
+ <Expression>throwable != null && throwable instanceof \
+ chapter5.TestException</Expression>
+ </evaluator></b>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <param name="Pattern"
+ value="%-4relative [%thread] %-5level - %msg \
+ <b>%ex{full, DISPLAY_EX_EVAL}</b>%n" />
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+ <p>
+ With this configuration, each time an instance of the
+ <em>chapter5.TestException</em>
+ is included within a logging request, no stack trace will be displayed.
+ </p>
+ <p><b>Important:</b> With the <b><em>%ex</em></b> conversion specifier, the data is
+ displayed when <em>the expression evaluates to <b>false</b>.</em></p>
+
+ <h3>Creating a custom conversion specifier</h3>
+ <p>We've seen up to here quite a lot of possibilities with conversion specifier and
+ <code>PatternLayout</code> objects. But what if somebody wants to make her own conversion
+ specifier?</p>
+
+ <p>In that case, two steps are needed.</p>
+
+ <p>First, one must implement her own <code>Converter</code>
+ class. <a href="../xref/ch/qos/logback/core/pattern/Converter.html">
+ <code>Converter</code></a> objects are responsible to extract a specific information out of
+ a <code>LoggingEvent</code>. When <em>%logger</em> is used, a
+ <a href="../xref/ch/qos/logback/classic/pattern/LoggerConverter.html">
+ <code>LoggerConverter</code></a>
+ is called to extract the name of the logger from the <code>LoggingEvent</code>.</p>
+
+ <p>Let us say that our customized <code>Converter</code> will output the level of the logging
+ event, colored following ANSI rules. Here is the necessary implementation:</p>
+
+<em> Example 5.4: Sample Converter Example
+<a href="../xref/chapter5/MySampleConverter.html">
+(src/main/java/chapter5/MySampleConverter.java)</a></em>
+<div class="source"><pre>package chapter5;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.pattern.ClassicConverter;
+import ch.qos.logback.classic.spi.LoggingEvent;
+
+public class MySampleConverter extends ClassicConverter {
+
+ private static final String END_COLOR = "\u001b[m";
+
+ private static final String ERROR_COLOR = "\u001b[0;31m";
+ private static final String WARN_COLOR = "\u001b[0;33m";
+
+ @Override
+ <b>public String convert(LoggingEvent event) {
+ StringBuffer sbuf = new StringBuffer();
+ sbuf.append(getColor(event.getLevel()));
+ sbuf.append(event.getLevel());
+ sbuf.append(END_COLOR);
+ return sbuf.toString();
+ }</b>
+
+ /**
+ * Returns the appropriate characters to change the color for the specified
+ * logging level.
+ */
+ private String getColor(Level level) {
+ switch (level.toInt()) {
+ case Level.ERROR_INT:
+ return ERROR_COLOR;
+ case Level.WARN_INT:
+ return WARN_COLOR;
+ default:
+ return "";
+ }
+ }
+}
+</pre></div>
+
+ <p>This implementation is quite straightforward. The <code>MySampleConverter</code> class
+ extends <code>ClassicConverter</code>, and implements the <code>convert</code> method.
+ In that method, all it has to do is return the appropriate information.
+ </p>
+
+ <p>The second step, once the <code>Converter</code> class done, is to let logback know about
+ the new <code>Converter</code>. For this task, we just need to declare the new
+ conversion word in the configuration file, as shown below:</p>
+
+<em> Example 5.4: Sample Converter Example (src/main/java/chapter5/mySampleConverterConfig.xml)</em>
+<div class="source"><pre><configuration>
+
+ <b><conversionRule conversionWord="sample" converterClass="chapter5.MySampleConverter" /></b>
+
+ <appender name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <b><Pattern>%-4relative [%thread] %sample - %msg%n</Pattern></b>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration></pre></div>
+
+ <p>In this configuration file, once the new conversion word has been declared, we
+ just use it within a <code>PatternLayout</code> pattern element, as if
+ our custom conversion word had always been here.</p>
+
+ <p>The intersted reader might want to take a look at other <code>Converter</code> implementations
+ like
+ <a href="../xref/ch/qos/logback/classic/pattern/MDCConverter.html">
+ <code>MDCConverter</code></a> to learn how to implement more complex behaviours, involving
+ the use of options, in her custom <code>Converter</code> objects.
+ </p>
+
+ <a name="ClassicHTMLLayout"></a>
+ <h3>HTMLLayout</h3>
+ <p><a href="../xref/ch/qos/logback/classic/html/HTMLLayout.html">
+ <code>HTMLLayout</code></a> outputs events in an HTML table. Each row of the table corresponds to a
+ logging event.</p>
+
+ <p>Here is a sample of the output that can be obtained using <code>HTMLLayout</code>
+ along with the default CSS stylesheet:</p>
+ <img src="images/chapter5/htmlLayout1.gif" alt="HTML Layout Sample Image"></img>
+
+ <p>
+ The content of the table columns are specified using a
+ conversion pattern. See <code>PatternLayout</code> for documentation on
+ the available patterns. This ensures that the user has full control over the creation
+ of the html table. One can choose to display any (or all) data that <code>PatternLayout</code>
+ can provide.
+ </p>
+ <p>One notable point about the use of <code>PatternLayout</code> with <code>HTMLLayout</code>
+ is that conversion specifiers should not be separated by a space or in general
+ any literals. Each specifier found in the
+ pattern will result in a separate column, meaning that each literal will create
+ an extra column.</p>
+ <p>
+ The pattern <em>%ex</em>
+ used to display an Exception is not the only way to display
+ an Exception with this layout. If you use this pattern, a
+ table column will be created to display the potential
+ Exception's stacktrace. That means that, in most cases, the column
+ will be empty, and will take quite a lot of space when displaying
+ an exception's stack trace.
+ </p>
+ <p>
+ Since printing a stack trace on a separate column is not very readable,
+ a better solution is available in the form of
+ implementations of the <code>IThrowableRenderer</code> interface.
+ These implementations can be called and assigned to
+ <code>HTMLLayout</code> to manage the display of anything related to
+ Exceptions.
+ </p>
+ <p>
+ By default, a
+ <a href="../xref/ch/qos/logback/classic/html/DefaultThrowableRenderer.html">
+ <code>DefaultThrowableRenderer</code></a> is
+ assigned to the <code>HTMLLayout</code>. It writes the Exception on a <em>new
+ table row</em>, along with its stacktrace, in a easily readable
+ manner, like presented in the picture above.
+ </p>
+ <p>
+ If one wants to use the
+ <em>%ex</em>
+ pattern anyway, then a
+ <a href="../xref/ch/qos/logback/core/html/NOPThrowableRenderer.html">
+ <code>NOPThrowableRenderer</code></a> can be specified
+ in the configuration file.
+ </p>
+ <p>
+ A user-specified external CSS file can be linked to the html
+ page. In that case, the following
+ xml element can be nested into the <code><layout></code> element.
+ </p>
+<div class="source"><pre><layout>
+ ...
+ <cssBuilder class="ch.qos.logback.core.html.UrlCssBuilder">
+ <param name="url" value="path_to_StyleFile.css" />
+ </cssBuilder>
+ ...
+</layout></pre></div>
+
+ <p>In case one does not want to customize the html
+ output, an internal CSS style is used.</p>
+
+ <p>
+ The <code>HTMLLayout</code> is often, although not necessarily used in conjunction with
+ <code>SMTPAppender</code>, to send a nicely formatted html email.
+ </p>
+ <p>
+ When one wants to use the <code>HTMLLayout</code> with a
+ <code>SMTPAppender</code>,
+ the following configuration would be typical.
+ </p>
+ <div class="source"><pre><configuration>
+ <appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
+ <layout class="ch.qos.logback.classic.html.HTMLLayout">
+ <param name="pattern" value="%relative%thread%mdc%level%class%msg" />
+ </layout>
+ <param name="From" value="sender.email at domain.net" />
+ <param name="SMTPHost" value="mail.domain.net" />
+ <param name="Subject" value="LastEvent: %class - %msg" />
+ <param name="To" value="destination.email at domain.net" />
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="SMTP" />
+ </root>
+</configuration></pre></div>
+
+ <p><code>HTMLLayout</code> can also be used with any <code>FileAppender</code>. In that
+ case, one can specify a rolling policy to archive log messages automatically.
+ One real world example could use the configuration below.</p>
+
+<div class="source"><pre><configuration>
+ <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <ActiveFileName>lastLogEntries.html</ActiveFileName>
+ <FileNamePattern>logEntries.%d{yyyy-MM-dd}.log</FileNamePattern>
+ </rollingPolicy>
+
+ <layout class="ch.qos.logback.classic.html.HTMLLayout">
+ <cssBuilder class="ch.qos.logback.core.html.UrlCssBuilder">
+ <url>address_of_a_custom_stylesheet.css</url>
+ </cssBuilder>
+ <Pattern>%relative%thread%mdc%level%logger%msg</Pattern>
+ <b><Title>Logging Events</Title></b>
+ </layout>
+ </appender>
+
+ <root>
+ <level value="debug" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration></pre></div>
+
+ <h2>Logback access</h2>
+
+ <p>Many access layouts are mere adaptations of classic layouts. Logback
+ classic and access modules address different needs, but offer comparable power
+ and flexibility.</p>
+
+ <h3>Writing your own Layout</h3>
+ <p>Writing a custom <code>Layout</code> for logback access is nearly identical
+ as to writing a <code>Layout</code> for the classic module.</p>
+
+ <a name="AccessPatternLayout"></a>
+ <h3>PatternLayout</h3>
+ <p>Access' <a href="../xref/ch/qos/logback/access/PatternLayout.html">
+ <code>PatternLayout</code></a> work the exact same way as it's classic counterpart.
+ </p>
+ <p>However, the conversion specifier are different, giving specific access to request
+ and response objects' attributes.</p>
+
+ <p>Here are the conversion specifier one can use with logback access
+ <code>PatternLayout</code>.</p>
+
+ <table class="bodyTable">
+ <th>Conversion Word</th>
+ <th>Effect</th>
+
+ <tr class="b">
+ <td><b>a / remoteIP</b></td>
+ <td>
+ <p>
+ Remote IP address.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>A / localIP</b></td>
+ <td>
+ <p>
+ Local IP address.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>b / B / byteSent</b></td>
+ <td>
+ <p>
+ Response's content length.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>h / clientHost</b></td>
+ <td>
+ <p>
+ Remote host.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>H / protocol</b></td>
+ <td>
+ <p>
+ Request protocol.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>l</b></td>
+ <td>
+ <p>
+ Remote log name. In logback-access, this converter always
+ returns the value "-".
+ </p>
+ </td>
+ </tr>
+
+ <tr class="b">
+ <td><b>reqParameter{paramName}</b></td>
+ <td>
+ <p>
+ Parameter of the response.
+ </p>
+ <p>This conversion word takes the first option in braces and looks
+ for the corresponding parameter in the request.</p>
+ <p><b>%reqParameter{input_data}</b>
+ displays the corresponding parameter.</p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>i{header} / header{header}</b></td>
+ <td>
+ <p>
+ Request header.
+ </p>
+ <p>This conversion word takes the first option in braces and looks
+ for the corresponding header in the request.</p>
+ <p><b>%header{Referer}</b> displays the referer of the request.</p>
+ <p>
+ If no option is specified, it displays every available header.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>m / requestMethod</b></td>
+ <td>
+ <p>
+ Request method.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>r / requestURL</b></td>
+ <td>
+ <p>
+ URL requested.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>s / statusCode</b></td>
+ <td>
+ <p>
+ Status code of the request.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>t / date</b></td>
+ <td>
+ <p>
+ Used to output the date of the logging event.
+ The date conversion specifier may be followed by
+ a set of braces containing a date and time
+ pattern strings used by
+ <code>java.text.SimpleDateFormat</code>
+ .
+ <em>ABSOLUTE</em>
+ ,
+ <em>DATE</em>
+ or
+ <em>ISO8601</em>
+ can also be used.
+ </p>
+ <p>
+ For example,
+ <b>%d{HH:mm:ss,SSS}</b>
+ ,
+ <b>
+ %d{dd MMM yyyy ;HH:mm:ss,SSS}
+ </b>
+ or
+ <b>%d{DATE}</b>
+ . If no date format specifier is given then
+ ISO8601 format is assumed.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>u / user</b></td>
+ <td>
+ <p>
+ Remote user.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>U / requestURI</b></td>
+ <td>
+ <p>
+ Requested URI.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>v / server</b></td>
+ <td>
+ <p>
+ Server name.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>localPort</b></td>
+ <td>
+ <p>
+ Local port.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>reqAttribute{attributeName}</b></td>
+ <td>
+ <p>
+ Attribute of the request.
+ </p>
+ <p>This conversion word takes the first option in braces and looks
+ for the corresponding attribute in the request.</p>
+ <p><b>%reqAttribute{SOME_ATTRIBUTE}</b>
+ displays the corresponding attribute.</p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>reqCookie{cookie}</b></td>
+ <td>
+ <p>
+ Request cookie.
+ </p>
+ <p>This conversion word takes the first option in braces and looks
+ for the corresponding cookie in the request.</p>
+ <p><b>%cookie{COOKIE_NAME}</b> displays corresponding cookie.</p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>responseHeader{header}</b></td>
+ <td>
+ <p>
+ Header of the response.
+ </p>
+ <p>This conversion word takes the first option in braces and looks
+ for the corresponding header in the response.</p>
+ <p><b>%header{Referer}</b> displays the referer of the response.</p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>requestContent</b></td>
+ <td>
+ <p>
+ This conversion word displays the content of the request, that is the
+ request's <code>InputStream</code>. It is used in conjunction with a
+ <a href="../xref/ch/qos/logback/access/servlet/TeeFilter.html">
+ <code>TeeFilter</code></a>, a <code>javax.servlet.Filter</code> that
+ replaces the original <code>HttpServletRequest</code>
+ by a <a href="../xref/ch/qos/logback/access/servlet/TeeHttpServletRequest.html">
+ <code>TeeHttpServletRequest</code></a>. The latter object allows
+ access to the requet's <code>InputStream</code> multiple times without
+ any loss of data.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>fullRequest</b></td>
+ <td>
+ <p>
+ This conversion word takes all the available headers of the
+ request and displays their values.
+ </p>
+ </td>
+ </tr>
+ <tr class="a">
+ <td><b>responseContent</b></td>
+ <td>
+ <p>
+ This conversion word displays the content of the response, that is the
+ response's <code>InputStream</code>. It is used in conjunction with a
+ <a href="../xref/ch/qos/logback/access/servlet/TeeFilter.html">
+ <code>TeeFilter</code></a>, a <code>javax.servlet.Filter</code> that
+ replaces the original <code>HttpServletResponse</code>
+ by a <a href="../xref/ch/qos/logback/access/servlet/TeeHttpServletResponse.html">
+ <code>TeeHttpServletResponse</code></a>. The latter object allows
+ access to the requet's <code>InputStream</code> multiple times without
+ any loss of data.
+ </p>
+ </td>
+ </tr>
+ <tr class="b">
+ <td><b>fullResponse</b></td>
+ <td>
+ <p>
+ This conversion word takes all the available headers of the
+ response and displays their values.
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <p>Logback access' <code>PatternLayout</code> also recognize three keywords, which
+ act like shortcuts to a certain pattern.</p>
+
+ <ul>
+ <p><em>common</em> or <em>CLF</em></p>
+ <p><em>combined</em></p>
+ </ul>
+
+ <p>The <em>common</em> keyword corresponds to the pattern <em>%h %l %u %t \"%r\" %s %b</em>
+ which displays client host, remote log name, user, date, requested URL, status code
+ and response's content length</p>
+
+ <p>The <em>combined</em> keyword is a shortcut to
+ <em>%h %l %u %t \"%r\" %s %b \"%i{Referer}\" \"%i{User-Agent}\"</em>. This pattern begins
+ much like the <em>common</em> pattern but also displays two request headers, namely
+ referer, and user-agent.</p>
+
+ <a name="AccessHTMLLayout"></a>
+ <h3>HTMLLayout</h3>
+
+ <p>The access version of
+ <a href="../xref/ch/qos/logback/access/html/HTMLLayout.html">
+ <code>HTMLLayout</code></a> works like logback classic's
+ version.</p>
+
+ <p>By default, it will create a table containing the following data:</p>
+
+ <ul>
+ <p>Remote IP</p>
+ <p>Date</p>
+ <p>Request URL</p>
+ <p>Status code</p>
+ <p>Content Length</p>
+ </ul>
+
+ <p>Here is what you can expect from a configured access <code>HTMLLayout</code>:</p>
+ <img src="images/chapter5/htmlLayoutAccess.gif" alt="Access HTML Layout Sample Image"></img>
+
+ <p>What's better than a real world example? Our own log4j properties to logback configuration
+ <a href="http://logback.qos.ch/translator/">translator</a>
+ is using logback access to showcase a live ouput, using a <code>RollingFileAppender</code> and
+ access' <code>HTMLLayout</code>.</p>
+
+ <p>You can see the file by <a href="http://logback.qos.ch/translator/logs/access.html">following this link</a>.</p>
+
+ <p>Just like any access log, it can be altered simply by visiting the
+ <a href="http://logback.qos.ch/translator/">translator</a> application.</p>
+
+
+<script src="../templates/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/manual/mdc.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/manual/mdc.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,623 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Chapter 7: Diagnostic Context</title>
+<link rel="stylesheet" type="text/css" media="screen" href="../css/site.css" />
+</head>
+<body>
+<script src="../templates/header.js"></script>
+<div id="left">
+ <script src="../templates/left.js"></script>
+</div>
+<div id="right">
+ <script src="../templates/right.js"></script>
+</div>
+<div id="content">
+ <h2>Chapter 7: Diagnostic Context</h2>
+ <div class="author">
+ Authors: Ceki Gülcü, Sébastien Pennec
+ </div>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <td>
+ <a 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"></img>
+ </a>
+ </td>
+ <td>
+ <p>Copyright © 2000-2006, QOS.ch</p>
+
+ <p>
+
+ This work is licensed under a
+ <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
+ Creative Commons
+ Attribution-NonCommercial-ShareAlike 2.5
+ License
+ </a>.
+
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ One of the design goals of logback is to audit and debug complex distributed applications.
+ Most real-world distributed systems need to deal with multiple clients simultaneously.
+ In a typical multithreaded implementation of such a system, different threads will handle
+ different clients. A possible but discouraged approach to differentiate the logging output of
+ one client from another consists of instantiating a new and separate logger for each client.
+ This technique promotes the proliferation of loggers and considerably increases
+ their management overhead.
+ </p>
+ <div class="highlight">
+ <p>
+ In order to run the examples in this chapter, 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>
+
+ <p>
+ A lighter technique consists of uniquely stamping each
+ log request servicing a given client. Neil Harrison described this method in the book
+ <em>Patterns for Logging Diagnostic Messages</em> in
+ Pattern Languages of Program Design 3, edited by R. Martin, D. Riehle,
+ and F. Buschmann (Addison-Wesley, 1997). Logback offers a variant of this technique:
+ Mapped Diagnostic Contexts (MDC).
+ </p>
+
+ <p>
+ To uniquely stamp each request, the user puts contextual information into the
+ <code><a href="../xref/ch/qos/logback/classic/MDC.html">MDC</a></code>,
+ the abbreviation of Mapped Diagnostic Context.
+ The public interface of the MDC class is shown below.
+ </p>
+
+<div class="source"><pre>package ch.qos.logback.classic;
+
+public class MDC {
+ //Put a context value as identified by <em>key</em>
+ //into the current thread's context map.
+ <b>public static void put(String key, String val);</b>
+
+ //Get the context identified by the <code>key</code> parameter.
+ <b>public static String get(String key);</b>
+
+ //Remove the the context identified by the <code>key</code> parameter.
+ <b>public static void remove(String key);</b>
+
+ //Clear all entries in the MDC.
+ <b>public static void clear();</b>
+
+ //Returns the keys in the MDC as a Set. The returned value can be null.
+ <b>public static Set<String> getKeys();</b>
+}</pre></div>
+
+ <p>
+ The <code>MDC</code> class contains only static methods.
+ It lets the developer place information in a <em>diagnostic context</em> that can be
+ subsequently retrieved by certain logback components. The
+ <code>MDC</code> manages contextual information on a <em>per thread basis</em>.
+ Typically, while starting to service a new client request, the developer will
+ insert pertinent contextual information, such as the client id, client's IP
+ address, request parameters etc. into the <code>MDC</code>. Logback components,
+ if appropriately configured, will automatically include this information
+ in each log entry.
+ </p>
+
+ <p>
+ The next application named
+ <code><a href="../xref/chapter7/SimpleMDC.html">SimpleMDC</a></code>
+ demonstrates this basic principle.
+ </p>
+<em>Example 7.1: Basic MDC usage (<a href="../xref/chapter7/SimpleMDC.html">
+logback-examples/src/main/java/chapter7/SimpleMDC.java)</a></em>
+<div class="source"><pre>package chapter7;
+
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.MDC;
+import ch.qos.logback.classic.PatternLayout;
+import ch.qos.logback.core.ConsoleAppender;
+
+public class SimpleMDC {
+ static public void main(String[] args) throws Exception {
+ // You can put values in the MDC at any time. We first put the
+ // first name
+ <b>MDC.put("first", "Dorothy");</b>
+
+ // Configure logback
+ PatternLayout layout = new PatternLayout();
+ layout.setPattern("%X{first} %X{last} - %m%n");
+ layout.start();
+ ConsoleAppender<LoggingEvent> appender = new ConsoleAppender<LoggingEvent>();
+ appender.setLayout(layout);
+ appender.start();
+ Logger root = (Logger)LoggerFactory.getLogger("root");
+ root.addAppender(appender);
+
+ // get a logger
+ Logger logger = (Logger)LoggerFactory.getLogger(SimpleMDC.class);
+
+ // We now put the last name
+ <b>MDC.put("last", "Parker");</b>
+
+ // The most beautiful two words in the English language according
+ // to Dorothy Parker:
+ logger.info("Check enclosed.");
+ logger.debug("The most beautiful two words in English.");
+
+ MDC.put("first", "Richard");
+ MDC.put("last", "Nixon");
+ logger.info("I am not a crook.");
+ logger.info("Attributed to the former US president. 17 Nov 1973.");
+ }
+}</pre></div>
+
+ <p>
+ The main method starts by associating the value <em>Dorothy</em> with
+ the key <em>first</em> in the <code>MDC</code>. You can place as many
+ value/key associations in the <code>MDC</code> as you wish.
+ Multiple insertions with the same key will overwrite older values.
+ The code then proceeds to configure logback.
+ Note the usage of the <em>%X</em> specifier within the
+ <code>PatternLayout</code> conversion pattern. The <em>%X</em>
+ conversion specifier is employed twice, once for the key <em>first</em>
+ and once for the key <em>last</em>. After configuring the root logger,
+ the code associates the value <em>Parker</em> with the key <em>last</em>.
+ It then invokes the logger twice with different messages.
+ The code finishes by setting the <code>MDC</code> to different values
+ and issuing several logging requests. Running SimpleMDC yields:
+ </p>
+
+<div class="source"><pre>Dorothy Parker - Check enclosed.
+Dorothy Parker - The most beautiful two words in English.
+Richard Nixon - I am not a crook.
+Richard Nixon - Attributed to the former US president. 17 Nov 1973.</pre></div>
+
+
+ <p>
+ The <code>SimpleMDC</code> application illustrates how logback layouts,
+ if configured appropriately, automatically output <code>MDC</code> information.
+ Moreover, the information placed into the <code>MDC</code> can be used by
+ multiple logger invocations.
+ </p>
+
+ <h3>Advanced Use</h3>
+
+ <p>
+ Mapped Diagnostic Contexts shine brightest within client server architectures.
+ Typically, multiple clients will be served by multiple threads on the server.
+ Although the methods in the <code>MDC</code> class are static,
+ the diagnostic context is managed on a per thread basis, allowing each server
+ thread to bear a distinct <code>MDC</code> stamp. <code>MDC</code> operations
+ such as <code>put()</code> and <code>get()</code> affect the <code>MDC</code>
+ of the <em>current</em> thread only. The <code>MDC</code> in other threads remain
+ unaffected. Given that <code>MDC</code> information is managed on a
+ per thread basis, each thread will have its own copy of the <code>MDC</code>.
+ Thus, there is no need for the developer to worry about thread-safety or
+ synchronization when programming with the <code>MDC</code> because
+ it safely and transparently handles these issues.
+ </p>
+
+ <p>
+ The next example is somewhat more advanced.
+ It shows how the <code>MDC</code> can be used in a client-server setting.
+ The server-side implements the <code>NumberCruncher</code> interface shown in
+ Example 7.2 below. <code>The NumberCruncher</code> interface contains a single
+ method named <code>factor()</code>. Using RMI technology, client invokes the
+ <code>factor()</code> method of the server application to retrieve the distinct
+ factors of an integer.
+ </p>
+
+<em>Example 7.2: The service interface (<a href="../xref/chapter7/NumberCruncher.html">
+logback-examples/src/main/java/chapter7/NumberCruncher.java)</a></em>
+<div class="source"><pre>package chapter7;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * NumberCruncher factors positive integers.
+ */
+public interface NumberCruncher extends Remote {
+ /**
+ * Factor a positive integer <code>number</code> and return its
+ * <em>distinct</em> factor's as an integer array.
+ * */
+ int[] factor(int number) throws RemoteException;
+}</pre></div>
+
+ <p>
+ The <code>NumberCruncherServer</code> application, listed in Example 7.3 below,
+ implements the <code>NumberCruncher</code> interface. Its main method exports
+ an RMI Registry on the local host that accepts requests on a well-known port.
+ </p>
+
+<em>Example 7.3: The server side (<a href="../xref/chapter7/NumberCruncherServer.html">
+logback-examples/src/main/java/chapter7/NumberCruncherServer.java)</a></em>
+<div class="source"><pre>package chapter7;
+
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Vector;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.MDC;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+
+
+/**
+ * A simple NumberCruncher implementation that logs its progress when
+ * factoring numbers. The purpose of the whole exercise is to show the
+ * use of mapped diagnostic contexts in order to distinguish the log
+ * output from different client requests.
+ * */
+public class NumberCruncherServer extends UnicastRemoteObject
+ implements NumberCruncher {
+
+ private static final long serialVersionUID = 1L;
+
+ static Logger logger = LoggerFactory.getLogger(NumberCruncherServer.class);
+
+ public NumberCruncherServer() throws RemoteException {
+ }
+
+ public int[] factor(int number) throws RemoteException {
+ // The client's host is an important source of information.
+ try {
+ <b>MDC.put("client", NumberCruncherServer.getClientHost());</b>
+ } catch (java.rmi.server.ServerNotActiveException e) {
+ logger.warn("Caught unexpected ServerNotActiveException.", e);
+ }
+
+ // The information contained within the request is another source
+ // of distinctive information. It might reveal the users name,
+ // date of request, request ID etc. In servlet type environments,
+ // useful information is contained in the HttpRequest or in the
+ // HttpSession.
+ <b>MDC.put("number", String.valueOf(number));</b>
+
+ logger.info("Beginning to factor.");
+
+ if (number <= 0) {
+ throw new IllegalArgumentException(number +
+ " is not a positive integer.");
+ } else if (number == 1) {
+ return new int[] { 1 };
+ }
+
+ Vector<Integer> factors = new Vector<Integer>();
+ int n = number;
+
+ for (int i = 2; (i <= n) && ((i * i) <= number); i++) {
+ // It is bad practice to place log requests within tight loops.
+ // It is done here to show interleaved log output from
+ // different requests.
+ logger.debug("Trying " + i + " as a factor.");
+
+ if ((n % i) == 0) {
+ logger.info("Found factor " + i);
+ factors.addElement(new Integer(i));
+
+ do {
+ n /= i;
+ } while ((n % i) == 0);
+ }
+
+ // Placing artificial delays in tight-loops will also lead to
+ // sub-optimal resuts. :-)
+ delay(100);
+ }
+
+ if (n != 1) {
+ logger.info("Found factor " + n);
+ factors.addElement(new Integer(n));
+ }
+
+ int len = factors.size();
+
+ int[] result = new int[len];
+
+ for (int i = 0; i < len; i++) {
+ result[i] = ((Integer) factors.elementAt(i)).intValue();
+ }
+
+ <b>// clean up
+ MDC.remove("client");
+ MDC.remove("number");</b>
+
+ return result;
+ }
+
+ static void usage(String msg) {
+ System.err.println(msg);
+ System.err.println("Usage: java chapter7.NumberCruncherServer configFile\n" +
+ " where configFile is a logback configuration file.");
+ System.exit(1);
+ }
+
+ public static void delay(int millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ usage("Wrong number of arguments.");
+ }
+
+ String configFile = args[0];
+
+ if (configFile.endsWith(".xml")) {
+ try {
+ LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+ JoranConfigurator configurator = new JoranConfigurator();
+ configurator.setContext(lc);
+ lc.shutdownAndReset();
+ configurator.doConfigure(args[0]);
+ } catch (JoranException je) {
+ je.printStackTrace();
+ }
+ }
+
+ NumberCruncherServer ncs;
+
+ try {
+ ncs = new NumberCruncherServer();
+ logger.info("Creating registry.");
+
+ Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
+ registry.rebind("Factor", ncs);
+ logger.info("NumberCruncherServer bound and ready.");
+ } catch (Exception e) {
+ logger.error("Could not bind NumberCruncherServer.", e);
+
+ return;
+ }
+ }
+}</pre></div>
+
+ <p>
+ The implementation of the <code>factor(int number)</code> method is
+ of particular relevance. It starts by putting the client's hostname into the
+ <code>MDC</code> under the key <em>client</em>. The number to factor,
+ as requested by the client, is put into the <code>MDC</code> under the key
+ <em>number</em>. After computing the distinct factors of the integer
+ parameter, the result is returned to the client. Before returning the
+ result however, the values for the <em>client</em> and <em>number</em> are
+ cleared by calling the <code>MDC.remove()</code> method. Normally,
+ a <code>put()</code> operation should be balanced by the corresponding
+ <code>remove()</code> operation. Otherwise, the <code>MDC</code> will
+ contain stale values for certain keys. We would recommend that whenever
+ possible <code>remove()</code> operations be performed within finally blocks,
+ ensuring their invocation regardless of the execution path of the code.
+ </p>
+
+ <p>
+ After these theoretical explanations, we are ready to run the number
+ cruncher example. Start the server with the following command:
+ </p>
+
+<div class="source"><pre>java chapter7.NumberCruncherServer src/main/java/chapter7/mdc1.xml</pre></div>
+
+ <p>
+ The <em>mdc1.xml</em> configuration file is listed below:
+ </p>
+<em>Example 7.4: Configuration file (logback-examples/src/main/java/chapter7/mdc1.xml)</em>
+<div class="source"><pre><configuration>
+
+ <appender name="CONSOLE"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <Pattern>%-4r [%thread] %-5level <b>C:%X{client} N:%X{number}</b> - %msg%n</Pattern>
+ </layout>
+ </appender>
+
+ <root>
+ <level value ="debug"/>
+ <appender-ref ref="CONSOLE"/>
+ </root>
+</configuration></pre></div>
+
+ <p>
+ Note the use of the <em>%X</em> conversion specifier within the
+ <span class="option">Pattern</span> option.
+ </p>
+
+ <p>
+ The following command starts an instance of <code>NumberCruncherClient</code>
+ application:
+ </p>
+
+<div class="source"><pre>java chapter7.NumberCruncherClient <em>hostname</em></pre></div>
+
+ <p>
+ where <em>hostname</em> is the host where the
+ <code>NumberCruncherServer</code> is running
+ </p>
+
+ <p>
+ Executing multiple instances of the client and requesting the server to factor
+ the numbers 129 from the first client and shortly thereafter
+ the number 71 from the second client, the server outputs the following:
+ </p>
+
+<div class="source"><pre>
+<b>70984 [RMI TCP Connection(4)-192.168.1.6] INFO C:orion N:129 - Beginning to factor.</b>
+70984 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 2 as a factor.
+71093 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 3 as a factor.
+71093 [RMI TCP Connection(4)-192.168.1.6] INFO C:orion N:129 - Found factor 3
+71187 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 4 as a factor.
+71297 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 5 as a factor.
+71390 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 6 as a factor.
+<b>71453 [RMI TCP Connection(5)-192.168.1.6] INFO C:orion N:71 - Beginning to factor.</b>
+71453 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:orion N:71 - Trying 2 as a factor.
+71484 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 7 as a factor.
+71547 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:orion N:71 - Trying 3 as a factor.
+71593 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 8 as a factor.
+71656 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:orion N:71 - Trying 4 as a factor.
+71687 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 9 as a factor.
+71750 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:orion N:71 - Trying 5 as a factor.
+71797 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 10 as a factor.
+71859 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:orion N:71 - Trying 6 as a factor.
+71890 [RMI TCP Connection(4)-192.168.1.6] DEBUG C:orion N:129 - Trying 11 as a factor.
+71953 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:orion N:71 - Trying 7 as a factor.
+72000 [RMI TCP Connection(4)-192.168.1.6] INFO C:orion N:129 - Found factor 43
+72062 [RMI TCP Connection(5)-192.168.1.6] DEBUG C:orion N:71 - Trying 8 as a factor.
+72156 [RMI TCP Connection(5)-192.168.1.6] INFO C:orion N:71 - Found factor 71</pre></div>
+
+ <p>
+ The clients were run from a machine called <em>orion</em> as can be seen in
+ the above output. Even if the server processes the requests of clients
+ near-simultaneously in separate threads, the logging output pertaining
+ to each client request can be distinguished by studying the output of the
+ <code>MDC</code>. Note for example the stamp associated with <em>number</em>,
+ i.e. the number to factor.
+ </p>
+
+ <p>
+ The attentive reader might have observed that the thread name could
+ also have been used to distinguish each request. The thread name can cause
+ confusion if the server side technology recycles threads. In that case,
+ it may be hard to determine the boundaries of each request, that is,
+ when a given thread finishes servicing a request and when it begins servicing the next.
+ Because the <code>MDC</code> is under the control of the application developer,
+ <code>MDC</code> stamps do not suffer from this problem.
+ </p>
+
+
+
+ <h3>Automating access to the <code>MDC</code></h3>
+
+ <p>
+ As we've seen, the <code>MDC</code> is very useful when dealing with multiple
+ clients. In the case of a web application that manages user authentication, one
+ simple solution could be to set the user's name in the <code>MDC</code> and remove
+ it once the user logs out. Unfortunately, it is not always possible to achieve
+ reliable results using this technique. Since <code>MDC</code> is managing
+ information on a <em>per thread</em> basis, a server that recycles
+ threads might lead to false information contained in the <code>MDC</code>.
+ </p>
+
+ <p>
+ To allow the information contained in the <code>MDC</code> to be correct
+ at all times when a request is processed, a solution might be to store the
+ username at the beginning of the process, and remove it at the end of
+ said process. A servlet
+ <a href="http://java.sun.com/javaee/5/docs/api/javax/servlet/Filter.html">
+ <code>Filter</code></a> is a good tool to have at
+ hand in such case.
+ </p>
+
+ <p>
+ By using a servlet filter, one can access the request, try to access
+ to relevant user information and store it in the <code>MDC</code>.
+ Then, after the process of creating the response, one just needs
+ to remove the user information from the <code>MDC</code>.
+ </p>
+
+ <p>
+ Here is an implementation of such a filter:
+ </p>
+
+<em>Example 7.5: User servlet filter (<a href="../xref/chapter7/UserServletFilter.html">
+logback-examples/src/main/java/chapter7/UserServletFilter.java)</a></em>
+<div class="source"><pre>package chapter7;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import ch.qos.logback.classic.MDC;
+
+public class UserServletFilter implements Filter {
+
+ boolean userRegistered = false;
+
+ private final String userKey = "username";
+
+ public void destroy() {
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+
+ HttpServletRequest req = (HttpServletRequest) request;
+ Principal principal = req.getUserPrincipal();
+
+ if (principal != null) {
+ String username = principal.getName();
+ registerUsername(username);
+ } else {
+ HttpSession session = req.getSession();
+ String username = (String)session.getAttribute(userKey);
+ registerUsername(username);
+ }
+
+ try {
+ chain.doFilter(request, response);
+ } finally {
+ if (userRegistered) {
+ MDC.remove(userKey);
+ }
+ }
+ }
+
+ public void init(FilterConfig arg0) throws ServletException {
+ }
+
+ private void registerUsername(String username) {
+ if (username != null && username.trim().length() > 0) {
+ MDC.put(userKey, username);
+ userRegistered = true;
+ }
+ }
+}</pre></div>
+
+
+ <p>
+ When the filter's <code>doFilter()</code> method is called, is first looks for a
+ <code>java.security.Principal</code> object in the request. This object contains
+ the name of the currently authenticated user. In case the user principal is not set,
+ the filter looks for a session attribute matching a given key (here <em>username</em>).
+ If a user information is found, it is registered in the <code>MDC</code>.
+ </p>
+
+ <p>
+ Once the filter chain has completed, the filter removes the user information
+ from the <code>MDC</code>.
+ </p>
+
+ <p>
+ With this filter, the user information is present in the <code>MDC</code> only
+ the time it takes to process the request. The thread may be reused to process a
+ request for another user without risking to display false information in the
+ logs.
+ </p>
+<script src="../templates/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/news.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/news.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,283 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>News</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+
+ <h2>Logback News</h2>
+
+ <p>Here are the latest news about logback.</p>
+
+ <h3>January 31st, 2007 - Release of version 0.9</h3>
+
+ <p>
+ This version contains a new component, namely the <code>ContextSelector</code>,
+ that provides context separation and management when logback is used
+ by several web-apps running under the same server. A
+ <a href="manual/contextSelector.html">new chapter</a> was added to the logback manual to detail
+ the use of the <code>ContextSelector</code>, along with its associated components.
+ </p>
+
+ <p>
+ The <code>JMXConfigurator</code> has been improved. It now shows the context's
+ Status objects, which lets users check the internal state of logback.
+ </p>
+
+ <p>
+ The logback manual's chapter 2, about <a href="manual/architecture.html">logback's architecture</a>,
+ has been updated with two sections: Under the hood and Performance.
+ </p>
+
+ <h3>January 23th, 2007 - Release of version 0.8.1</h3>
+
+ <p>
+ This version contains new components in the Access module, allowing users
+ to display the full HttpServletRequest or HttpServletResponse of an access event.
+ </p>
+
+ <p>
+ The documentation section has been updated. The short introduction was split
+ into the chapter 1 and chapter 2 of the logback manual. The chapters about
+ Appenders and Layouts have been updated to document new components of logback.
+ </p>
+
+ <p>
+ A demonstration webApp presenting logback's major components is available.
+ A document explains how to run it, and provides a step-by-step visit of the
+ demo.
+ </p>
+
+ <p>
+ A first translation of logback jars to JDK1.4 is present in this release.
+ </p>
+
+
+ <h3>January 12th, 2007 - Release of version 0.8</h3>
+
+ <p>
+ This version contains a whole new chapter, namely Chapter 3, about logback
+ configuration. Several other documentation pages have been improved.
+ </p>
+
+ <p>
+ Logback now uses Generics in many components.
+ </p>
+
+ <p>
+ Several new components have been added to logback. A JMX Configurator now allows
+ users to see and modify loggers or reload configuration among other possibilities.
+ A <a href="jmxConfig.html">document</a>
+ about this configurator is available in the <a href="documentation.html">corresponding section</a>
+ of the site. We'd like to thank Sebastian Davids for his ideas and contributions to this
+ component.
+ </p>
+
+ <p>
+ A JMSTopicAppender and JMSQueueAppender are now available, as well as two new filters: LevelFilter
+ and ThresholdFilter. A refactoring was done in the filters objects to ease the implementation
+ of custom filters.
+ </p>
+
+
+ <h3>December 19th, 2006 - Release of version 0.7.1</h3>
+
+ <p>
+ Version 0.7.1 of logback has been released.
+ </p>
+
+ <p>
+ This version contains more detailled information about logback access module, and
+ its JMX components. A <a href="access.html">dedicated page</a> explains how to configure and use logback
+ access in Tomcat and Jetty, and access some of its components via JMX.
+ </p>
+
+ <h3>December 18th, 2006 - Release of version 0.7</h3>
+
+ <p>
+ Version 0.7 of logback has been released.
+ </p>
+
+ <p>
+ Logback now ships with a new module: <em>log4j-bridge</em>. This new module
+ can be used to intercept log4j calls and redirects them to logback components.
+ More information about this module can be found in the corresponding
+ <a href="bridge.html">documentation page</a>.
+ </p>
+
+ <p>
+ The documentation has been vastly updated. Two new chapters,
+ namely Filters and MDC, are available in the manual section.
+ </p>
+
+ <h3>November 30th, 2006 - Release of version 0.6</h3>
+
+ <p>
+ Version 0.6 of logback has been released.
+ </p>
+
+ <p>
+ Logback classic now supports automatic configuration, allowing test and production
+ environment configuration. <code>TurboFilters</code> make their first appearance
+ in a logback release. They provide ultra-fast filtering possibilities.
+ The logging context now supports listeners which will be contacted each
+ time the context is reset or started. <code>SMTPAppender</code>
+ allows for much more flexible configuration than before.
+ </p>
+
+ <p>
+ In logback access, new Appenders are available, namely <code>SocketAppender</code>
+ and <code>DBAppender</code>.
+ Logback access now supports filtering and event evaluations. A <code>CountingFilter</code>
+ has been added. It provides statistical views of server access, reachable
+ via JMX.
+ </p>
+
+ <p>
+ The documentation has also been improved. A complete new chapter
+ has been added about Appenders, the short introduction to logback
+ classic has been updated and a new module, containing many configuration
+ examples has been added.
+ </p>
+
+ <p>
+ Logback now uses continous integration in its development.
+ </p>
+
+ <p>
+ Tests have been improved, many new have been added.
+ This release also provides some bug fixes.
+ </p>
+
+ <hr width="80%" align="center"></hr>
+
+ <h3>October 26th, 2006 - Release of version 0.5</h3>
+
+ <p>
+ Version 0.5 of logback has been released.
+ </p>
+
+ <p>
+ This release offers a important improvements in Joran. In
+ particular, Joran can now replay configuration elements.
+ </p>
+
+ <p>
+ As in the previous release, a major area of work is the
+ documentation which is being continously improved.
+ </p>
+
+ <hr width="80%" align="center"></hr>
+
+ <h3>October 9th, 2006 - Release of version 0.4</h3>
+ <p>
+ Version 0.3 of logback has been released.
+ </p>
+
+ <p>
+ This release includes an improved access module, with specific
+ implementations for the Jetty and Tomcat servers. Documentation
+ was also added to show how to integrate logback-access with
+ Jetty.
+ </p>
+
+ <p>
+ As for the classic module, several appenders and layouts have
+ been added or improved. The error reporting of logback has also
+ been enhanced, presenting the user with a link to an online page
+ explaining possible reasons for the error.
+ </p>
+
+ <p>
+ A joran documentation was added, with examples in the core
+ module.
+ </p>
+
+ <hr width="80%" align="center"></hr>
+
+ <h3>September 8th, 2006 - Release of version 0.3</h3>
+ <p>
+ Version 0.3 of logback has been released.
+ </p>
+
+ <p>
+ This release offers several new Appenders, support for Mapped
+ Diagnostic Context, improved tests and documentation<br></br>
+ </p>
+
+ <p>
+ In response to a bug report by Rickard Nilsson on the logback
+ mailing list, a bug affecting parametrized logging was fixed.
+ </p>
+
+ <p>
+ We also released a <a href="http://logback.qos.ch/translator/">PropertiesTranslator</a>
+ webapp that converts <em>log4j.properties</em> files to joran
+ configuration files (in XML format).<br></br>
+ </p>
+
+ <hr width="80%" align="center"></hr>
+
+ <h3>August 23th, 2006 - Release of version 0.2.5</h3>
+
+ <p>
+ Version 0.2.5 of logback has been released.
+ </p>
+
+ <p>
+ This release offers better documentation. With a number of
+ correction mande in the short introduction to logback-classic.
+ </p>
+
+ <hr width="80%" align="center"></hr>
+
+
+ <h3>August 15th, 2006 - Release of version 0.2</h3>
+ <p>
+ Version 0.2 of logback has been released.
+ </p>
+
+ <p>
+ It offers better tests, a few more functionalities, and enhanced
+ documentation. We also improved the site design to make it
+ simpler and more efficient.
+ </p>
+
+ <hr width="80%" align="center"></hr>
+
+ <h3>July 26th, 2006 - Release of version 0.1</h3>
+
+ <p>
+ Version 0.1 of logback has been released.
+ </p>
+
+ <hr width="80%" align="center"></hr>
+
+ <h3>February 9th, 2006 - Logback web-site goes live</h3>
+ <p>
+ The logback web-site goes live on the 9th of February. At
+ its present state, it is pretty primitive but updates will
+ follow.
+ </p>
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/repos.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/repos.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,75 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Repository</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+ <h2>Source Repository</h2>
+
+ <p>
+ 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>
+ If you just wish to browse around or download a few individual
+ files, you can do so with web-based ViewVC interface:
+ </p>
+
+ <p>
+ <a href="http://svn.qos.ch/viewvc/logback/trunk/">http://svn.qos.ch/viewvc/logback/trunk/</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. You can check out the entire logback
+ project with the following command:</p>
+
+ <div class="source">svn co http://svn.qos.ch/repos/logback/trunk/ target_directory</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>
+
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/setup.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/setup.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,77 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Setup</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+ <h2>Classpath Setup</h2>
+
+<p>
+In order to run the examples provided in the documentation,
+you need to add the following jars to your class path:
+</p>
+
+<ul>
+ <p>logback-core-1.0-SNAPSHOT.jar</p>
+ <p>logback-classic-1.0-SNAPSHOT.jar</p>
+ <p>logback-examples-1.0-SNAPSHOT.jar</p>
+ <p>slf4j-api-1.2.jar</p>
+</ul>
+
+<h3>Example</h3>
+
+<p>
+Assuming your current directory is
+<em>$LOGBACK_HOME/logback-examples</em>, where <em>$LOGBACK_HOME</em> stands
+for the directory where you installed logback, you can launch the first
+sample application, <em>chapter1.HelloWord1</em> with the following command:
+</p>
+
+<div class="source"><pre>java -cp
+ lib/slf4j-api-1.2.jar;../logback-core-1.0-SNAPSHOT.jar;\
+ ../logback-classic-1.0-SNAPSHOT.jar;logback-examples-1.0-SNAPSHOT.jar\
+ chapter1.HelloWorld1</pre></div>
+
+<p>
+It is more convenient to set the CLASSPATH environment variable
+once and for all before running the examples.
+</p>
+<p>The <em>setClasspath.cmd</em> script located in the $LOGBACK_HOME/logback-examples
+folder will configure the class path for the MS Windows platform. For Unix, you can
+use <em>setClasspath.sh</em>.
+</p>
+
+<p>Please edit the script in order to adapt the <em>LB_HOME</em> variable
+to match your local environment.</p>
+
+<p>
+Please be aware that many examples will launch java classes along
+with configuration files. To access these files by using
+the same commands as written in the documentation, you will need to
+issue the commands from within the <em>$LOGBACK_HOME/logback-examples</em>
+directory.
+</p>
+
+
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/team.html
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/team.html Thu Feb 1 15:44:05 2007
@@ -0,0 +1,85 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Logback Team</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+</head>
+<body>
+<script src="templates/base/header.js"></script>
+<div id="left">
+ <script src="templates/base/left.js"></script>
+</div>
+<div id="right">
+ <script src="templates/base/right.js"></script>
+</div>
+<div id="content">
+
+
+
+ <h2>Logback Team</h2>
+
+ <p>Let us introduce you to the logback team members:</p>
+
+ <table class="bodyTable">
+ <tr class="a">
+ <td><img src="images/jeannoel.gif" alt="Jean-Noel"></img></td>
+ <td>
+ Jean-Noel Charpin has been designing and developing object oriented software
+ and decision making systems since 1998. He is particularly interested in
+ translating lean manufacturing principles and practices to the software development
+ domain in order to improve quality and reliability.
+ </td>
+ </tr>
+ <tr class="b">
+ <td><img src="images/ceki.gif" alt="Ceki"></img></td>
+ <td>
+ <p>Ceki Gülcü has been working on logging systems
+ since 1996. He is the founder of the log4j, slf4j and
+ logback projects. Ceki enjoys writing software, a task far
+ more difficult and time-consuming than what it seems at
+ first sight. His interests range from cryptography, systems
+ monitoring and testing to application interoperability.
+ </p>
+
+ <p>One of the core lessons he has learned over the years is
+ that unit tests lie at the heart of maintainable
+ software. Adding tests towards the end of development cycle
+ yields poor results. Tests must be an inherent part of the
+ development process right from the start.
+ </p>
+
+ <p>When not busy programming, Ceki enjoys watching the
+ Simpsons on DVD or alternatively preparing sushis for his
+ friends.
+ </p>
+
+ </td>
+ </tr>
+ <tr class="a">
+ <td><img src="images/seb.gif" alt="Sebastien"></img></td>
+ <td>
+ <p>Sébastien Pennec has been using computers for the most
+ part of his life, be it as a hobby, or during his studies
+ or, more recently, as Software Engineer. He loves to write
+ software in dynamic and enthusiastic environments, while
+ learning new technologies and practices.
+ </p>
+ <p>
+ Sébastien's hobbys include writing articles about
+ Macintosh products on <a href="http://www.cuk.ch">cuk.ch</a>,
+ digital photography and playing poker with his friends.
+ </p>
+ </td>
+ </tr>
+ </table>
+
+
+
+
+
+
+<script src="templates/base/footer.js"></script>
+</div>
+</body>
+</html>
Added: logback/trunk/logback-site/src/site/resources/templates/base/footer.js
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/templates/base/footer.js Thu Feb 1 15:44:05 2007
@@ -0,0 +1,4 @@
+
+document.write('<p class="footer">')
+document.write('<a href="http://www.qos.ch/">QOS.ch</a>')
+document.write('</p>')
\ No newline at end of file
Added: logback/trunk/logback-site/src/site/resources/templates/base/header.js
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/templates/base/header.js Thu Feb 1 15:44:05 2007
@@ -0,0 +1,7 @@
+
+document.write('<p align="left">');
+document.write('<a href="http://logback.qos.ch.ch/">');
+document.write('<img src="images/logos/lblogo.jpg" alt="" border="0"/>');
+document.write('</a>')
+document.write('</p>');
+document.write('<div id="breadcrumbs"></div>');
Added: logback/trunk/logback-site/src/site/resources/templates/base/left.js
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/templates/base/left.js Thu Feb 1 15:44:05 2007
@@ -0,0 +1,18 @@
+writeMenu('');
+function writeMenu(prefix) {
+ document.write('<p class="menu_header">Logback</p>');
+ document.write('<p><a href="index.html">Introduction</a>');
+ document.write('<a href="' + prefix + 'news.html">News</a>');
+ document.write('<a href="' + prefix + 'download.html">Download</a>');
+ document.write('<a href="' + prefix + 'documentation.html">Documentation</a>');
+ document.write('<a href="' + prefix + 'mailinglist.html">Mailing Lists</a>');
+ document.write('<a href="' + prefix + 'repos.html">Source Repository</a>');
+ document.write('<a href="' + prefix + 'bugreport.html">Bug Report</a>');
+ document.write('<a href="' + prefix + 'license.html">License</a>');
+ document.write('<a href="http://logback.qos.ch/translator/">Log4j Properties Translator</a>');
+ document.write('<a href="' + prefix + 'team.html">Logback Team</a>');
+ document.write('<a href="http://www.qos.ch/"><img src="' + prefix + 'images/logos/qosLogo.png" /></a>');
+ document.write('</p>');
+}
+
+
Added: logback/trunk/logback-site/src/site/resources/templates/base/right.js
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/templates/base/right.js Thu Feb 1 15:44:05 2007
@@ -0,0 +1,8 @@
+
+/*document.write('<p class="menu_header">Menu</p>')
+document.write('<p><a href=".">anc</a>')
+document.write('<a href=".">abc</a>')
+document.write('<a href=".">log4j configration ttnaslator</a>')
+document.write('<a href=".">xxxxxxxxxxx</a>')
+document.write('</p>')
+*/
\ No newline at end of file
Added: logback/trunk/logback-site/src/site/resources/templates/footer.js
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/templates/footer.js Thu Feb 1 15:44:05 2007
@@ -0,0 +1,4 @@
+
+document.write('<p class="footer">')
+document.write('<a href="http://www.qos.ch/">QOS.ch</a>')
+document.write('</p>')
\ No newline at end of file
Added: logback/trunk/logback-site/src/site/resources/templates/header.js
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/templates/header.js Thu Feb 1 15:44:05 2007
@@ -0,0 +1,7 @@
+
+document.write('<p align="left">');
+document.write('<a href="http://logback.qos.ch.ch/">');
+document.write('<img src="../images/logos/lblogo.jpg" alt="" border="0"/>');
+document.write('</a>')
+document.write('</p>');
+document.write('<div id="breadcrumbs"></div>');
Added: logback/trunk/logback-site/src/site/resources/templates/left.js
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/templates/left.js Thu Feb 1 15:44:05 2007
@@ -0,0 +1,18 @@
+writeMenu('../');
+function writeMenu(prefix) {
+ document.write('<p class="menu_header">Logback</p>');
+ document.write('<p><a href="index.html">Introduction</a>');
+ document.write('<a href="' + prefix + 'news.html">News</a>');
+ document.write('<a href="' + prefix + 'download.html">Download</a>');
+ document.write('<a href="' + prefix + 'documentation.html">Documentation</a>');
+ document.write('<a href="' + prefix + 'mailinglist.html">Mailing Lists</a>');
+ document.write('<a href="' + prefix + 'repos.html">Source Repository</a>');
+ document.write('<a href="' + prefix + 'bugreport.html">Bug Report</a>');
+ document.write('<a href="' + prefix + 'license.html">License</a>');
+ document.write('<a href="http://logback.qos.ch/translator/">Log4j Properties Translator</a>');
+ document.write('<a href="' + prefix + 'team.html">Logback Team</a>');
+ document.write('<a href="http://www.qos.ch/"><img src="../images/logos/qosLogo.png" /></a>');
+ document.write('</p>');
+}
+
+
Added: logback/trunk/logback-site/src/site/resources/templates/right.js
==============================================================================
--- (empty file)
+++ logback/trunk/logback-site/src/site/resources/templates/right.js Thu Feb 1 15:44:05 2007
@@ -0,0 +1,7 @@
+
+/*document.write('<p class="menu_header"></p>')
+document.write('<p><a href="http//www.slf4j.org">Sister Project: SLF4J</a>')
+document.write('<a href="."></a>')
+document.write('<a href=".">log4j configration ttnaslator</a>')
+document.write('<a href=".">xxxxxxxxxxx</a>')
+document.write('</p>')*/
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 Thu Feb 1 15:44:05 2007
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Logback Project">
- <skin>
+ <!-- <skin>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
<version>0.9.1-SNAPSHOT</version>
- </skin>
+ </skin>-->
<publishDate position="navigation-bottom" format="dd-MM-yyyy"/>
Modified: logback/trunk/pom.xml
==============================================================================
--- logback/trunk/pom.xml (original)
+++ logback/trunk/pom.xml Thu Feb 1 15:44:05 2007
@@ -22,7 +22,7 @@
<module>logback-classic</module>
<module>logback-access</module>
<module>logback-site</module>
- <module>logback-skin</module>
+ <!-- <module>logback-skin</module> -->
<module>logback-examples</module>
<module>log4j-bridge</module>
</modules>
Modified: logback/trunk/src/site/site.xml
==============================================================================
--- logback/trunk/src/site/site.xml (original)
+++ logback/trunk/src/site/site.xml Thu Feb 1 15:44:05 2007
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="LOGBack Main Site">
- <skin>
+ <!--<skin>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
<version>0.9.1-SNAPSHOT</version>
- </skin>
+ </skin> -->
<!--
<publishDate position="navigation-bottom" format="dd-MM-yyyy"/>
More information about the logback-dev
mailing list