logback-dev
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 9940 discussions
02 Feb '07
Author: seb
Date: Fri Feb 2 10:48:59 2007
New Revision: 1305
Modified:
logback/trunk/logback-site/src/site/resources/license.html
Log:
Corrected wrong div tag
Modified: logback/trunk/logback-site/src/site/resources/license.html
==============================================================================
--- logback/trunk/logback-site/src/site/resources/license.html (original)
+++ logback/trunk/logback-site/src/site/resources/license.html Fri Feb 2 10:48:59 2007
@@ -16,7 +16,7 @@
<div id="content">
<h2>Logback License</h2>
- </div>
+
<p>
Logback source code and binaries are distributed under the
1
0
01 Feb '07
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/catali…">
+ 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/FixedWindowRollin…">
+ 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/SizeBasedTriggeri…">
+ <code>SizeBasedTriggeringPolicy</code>
+ </a>
+ </li>
+ <li>
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/TimeBasedRollingP…">
+ <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/FixedWindowRollin…">
+ <code>FixedWindowRollingPolicy</code>
+ </a>
+ </li>
+ <li>
+ <a href="http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/TimeBasedRollingP…">
+ <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@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(a)xyz.com -Dto=recipient(a)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(a)host.com</From>
+ <SMTPHost>mail.domain.com</SMTPHost>
+ <To>recipient_email(a)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@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@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(a)domain.net" />
+ <param name="SMTPHost" value="mail.domain.net" />
+ <param name="Subject" value="LastEvent: %class - %msg" />
+ <param name="To" value="destination.email(a)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"/>
1
0
Online report : http://localhost:8090/continuum/servlet/continuum/target/ProjectBuild.vm/vi…
Build statistics:
State: Failed
Previous State: Ok
Started at: Wed, 31 Jan 2007 16:41:09 +0100
Finished at: Wed, 31 Jan 2007 16:41:12 +0100
Total time: 3s
Build Trigger: Schedule
Exit code: 1
Building machine hostname: pixie
Operating system : Linux(unknown)
Java version : 1.5.0_08(Sun Microsystems Inc.)
Changes
seb modified version number.
/logback/trunk/log4j-bridge/pom.xml
/logback/trunk/logback-access/pom.xml
/logback/trunk/logback-classic/pom.xml
/logback/trunk/logback-core/pom.xml
/logback/trunk/logback-examples/pom.xml
/logback/trunk/logback-site/pom.xml
/logback/trunk/logback-site/src/site/site.xml
/logback/trunk/logback-skin/pom.xml
/logback/trunk/pom.xml
/logback/trunk/src/site/site.xml
****************************************************************************
Output:
****************************************************************************
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[INFO] Building Logback Examples Module
[INFO] task-segment: [clean, install]
[INFO] ----------------------------------------------------------------------------
[INFO] [clean:clean]
[INFO] Deleting directory /opt/continuum-1.0.3/apps/continuum/working-directory/50/target
[INFO] Deleting directory /opt/continuum-1.0.3/apps/continuum/working-directory/50/target/classes
[INFO] Deleting directory /opt/continuum-1.0.3/apps/continuum/working-directory/50/target/test-classes
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed to resolve artifact.
Missing:
----------
1) ch.qos.logback:logback-access:jar:0.9.1-SNAPSHOT
Try downloading the file manually from the project website.
Then, install it using the command:
mvn install:install-file -DgroupId=ch.qos.logback -DartifactId=logback-access \
-Dversion=0.9.1-SNAPSHOT -Dpackaging=jar -Dfile=/path/to/file
Path to dependency:
1) ch.qos.logback:logback-examples:jar:0.9.1-SNAPSHOT
2) ch.qos.logback:logback-access:jar:0.9.1-SNAPSHOT
----------
1 required artifact is missing.
for artifact:
ch.qos.logback:logback-examples:jar:0.9.1-SNAPSHOT
from the specified remote repositories:
central (http://repo1.maven.org/maven2)
[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Wed Jan 31 16:41:12 CET 2007
[INFO] Final Memory: 11M/83M
[INFO] ------------------------------------------------------------------------
****************************************************************************
1
0
Online report : http://localhost:8090/continuum/servlet/continuum/target/ProjectBuild.vm/vi…
Build statistics:
State: Failed
Previous State: Ok
Started at: Wed, 31 Jan 2007 16:40:57 +0100
Finished at: Wed, 31 Jan 2007 16:41:08 +0100
Total time: 11s
Build Trigger: Schedule
Exit code: 1
Building machine hostname: pixie
Operating system : Linux(unknown)
Java version : 1.5.0_08(Sun Microsystems Inc.)
Changes
seb modified version number.
/logback/trunk/log4j-bridge/pom.xml
/logback/trunk/logback-access/pom.xml
/logback/trunk/logback-classic/pom.xml
/logback/trunk/logback-core/pom.xml
/logback/trunk/logback-examples/pom.xml
/logback/trunk/logback-site/pom.xml
/logback/trunk/logback-site/src/site/site.xml
/logback/trunk/logback-skin/pom.xml
/logback/trunk/pom.xml
/logback/trunk/src/site/site.xml
****************************************************************************
Output:
****************************************************************************
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[INFO] Building Logback Access Module
[INFO] task-segment: [clean, install]
[INFO] ----------------------------------------------------------------------------
[INFO] [clean:clean]
[INFO] Deleting directory /opt/continuum-1.0.3/apps/continuum/working-directory/47/target
[INFO] Deleting directory /opt/continuum-1.0.3/apps/continuum/working-directory/47/target/classes
[INFO] Deleting directory /opt/continuum-1.0.3/apps/continuum/working-directory/47/target/test-classes
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
Compiling 64 source files to /opt/continuum-1.0.3/apps/continuum/working-directory/47/target/classes
[INFO] [retrotranslator:translate {execution: default}]
[INFO] Transforming 80 file(s) from /opt/continuum-1.0.3/apps/continuum/working-directory/47/target/classes to /opt/continuum-1.0.3/apps/continuum/working-directory/47/target/logback-access-0.9.1-SNAPSHOT-jdk14.jar.
[INFO] Transformation of 80 file(s) completed successfully.
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
Compiling 22 source files to /opt/continuum-1.0.3/apps/continuum/working-directory/47/target/test-classes
[INFO] [surefire:test]
[INFO] Surefire report directory: /opt/continuum-1.0.3/apps/continuum/working-directory/47/target/surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running ch.qos.logback.access.db.DBAppenderTest
[Server@2e8f4fb3]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@2e8f4fb3]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@2e8f4fb3]: [Thread[main,5,main]]: setDatabaseName(0,test)
[Server@2e8f4fb3]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@2e8f4fb3]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@2e8f4fb3]: [Thread[main,5,main]]: setDatabasePath(0,mem:test;sql.enforce_strict_size=true)
[Server@16aa37a6]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@16aa37a6]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@16aa37a6]: [Thread[main,5,main]]: setDatabaseName(0,test)
[Server@16aa37a6]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@16aa37a6]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@16aa37a6]: [Thread[main,5,main]]: setDatabasePath(0,mem:test;sql.enforce_strict_size=true)
[Server@13b8f864]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@13b8f864]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@13b8f864]: [Thread[main,5,main]]: setDatabaseName(0,test)
[Server@13b8f864]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@13b8f864]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@13b8f864]: [Thread[main,5,main]]: setDatabasePath(0,mem:test;sql.enforce_strict_size=true)
[Server@9506dc4]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@9506dc4]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@9506dc4]: [Thread[main,5,main]]: setDatabaseName(0,test)
[Server@9506dc4]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@9506dc4]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@9506dc4]: [Thread[main,5,main]]: setDatabasePath(0,mem:test;sql.enforce_strict_size=true)
Tests run: 4, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.761 sec <<< FAILURE!
Running ch.qos.logback.access.jetty.JettyBasicTest
2007-01-31 16:41:06.867::INFO: Logging to STDERR via org.mortbay.log.StdErrLog
2007-01-31 16:41:06.927::INFO: jetty-6.1.1
2007-01-31 16:41:06.984::INFO: Started SelectChannelConnector @ 0.0.0.0:1234
31/01/2007:16:41:07 +0100 localhost 127.0.0.1
31/01/2007:16:41:07 +0100 localhost 127.0.0.1
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.43 sec
Running ch.qos.logback.access.filter.AccessStatsTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.009 sec
Running ch.qos.logback.access.pattern.ConverterTest
Tests run: 16, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.024 sec
Running ch.qos.logback.access.filter.StatsByDayTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.012 sec
Running ch.qos.logback.access.net.URLEvaluatorTest
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.012 sec
Running ch.qos.logback.access.net.SocketAppenderTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.128 sec
Results :
Tests run: 29, Failures: 0, Errors: 1, Skipped: 0
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] There are test failures.
[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10 seconds
[INFO] Finished at: Wed Jan 31 16:41:08 CET 2007
[INFO] Final Memory: 16M/114M
[INFO] ------------------------------------------------------------------------
****************************************************************************
1
0
svn commit: r1303 - in logback/trunk: . log4j-bridge logback-access logback-classic logback-core logback-examples logback-site logback-site/src/site logback-skin src/site
by noreply.seb@qos.ch 31 Jan '07
by noreply.seb@qos.ch 31 Jan '07
31 Jan '07
Author: seb
Date: Wed Jan 31 16:22:37 2007
New Revision: 1303
Modified:
logback/trunk/log4j-bridge/pom.xml
logback/trunk/logback-access/pom.xml
logback/trunk/logback-classic/pom.xml
logback/trunk/logback-core/pom.xml
logback/trunk/logback-examples/pom.xml
logback/trunk/logback-site/pom.xml
logback/trunk/logback-site/src/site/site.xml
logback/trunk/logback-skin/pom.xml
logback/trunk/pom.xml
logback/trunk/src/site/site.xml
Log:
modified version number.
Modified: logback/trunk/log4j-bridge/pom.xml
==============================================================================
--- logback/trunk/log4j-bridge/pom.xml (original)
+++ logback/trunk/log4j-bridge/pom.xml Wed Jan 31 16:22:37 2007
@@ -5,14 +5,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>log4j-bridge</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Log4j Bridge Module</name>
Modified: logback/trunk/logback-access/pom.xml
==============================================================================
--- logback/trunk/logback-access/pom.xml (original)
+++ logback/trunk/logback-access/pom.xml Wed Jan 31 16:22:37 2007
@@ -3,14 +3,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Logback Access Module</name>
Modified: logback/trunk/logback-classic/pom.xml
==============================================================================
--- logback/trunk/logback-classic/pom.xml (original)
+++ logback/trunk/logback-classic/pom.xml Wed Jan 31 16:22:37 2007
@@ -5,14 +5,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Logback Classic Module</name>
Modified: logback/trunk/logback-core/pom.xml
==============================================================================
--- logback/trunk/logback-core/pom.xml (original)
+++ logback/trunk/logback-core/pom.xml Wed Jan 31 16:22:37 2007
@@ -5,14 +5,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Logback Core Module</name>
Modified: logback/trunk/logback-examples/pom.xml
==============================================================================
--- logback/trunk/logback-examples/pom.xml (original)
+++ logback/trunk/logback-examples/pom.xml Wed Jan 31 16:22:37 2007
@@ -3,14 +3,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-examples</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Logback Examples Module</name>
Modified: logback/trunk/logback-site/pom.xml
==============================================================================
--- logback/trunk/logback-site/pom.xml (original)
+++ logback/trunk/logback-site/pom.xml Wed Jan 31 16:22:37 2007
@@ -3,7 +3,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -11,7 +11,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-site</artifactId>
<packaging>jar</packaging>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
<name>Logback Site</name>
<url>http://logback.qos.ch</url>
Modified: logback/trunk/logback-site/src/site/site.xml
==============================================================================
--- logback/trunk/logback-site/src/site/site.xml (original)
+++ logback/trunk/logback-site/src/site/site.xml Wed Jan 31 16:22:37 2007
@@ -4,7 +4,7 @@
<skin>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
</skin>
<publishDate position="navigation-bottom" format="dd-MM-yyyy"/>
Modified: logback/trunk/logback-skin/pom.xml
==============================================================================
--- logback/trunk/logback-skin/pom.xml (original)
+++ logback/trunk/logback-skin/pom.xml Wed Jan 31 16:22:37 2007
@@ -3,7 +3,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
</parent>
@@ -12,7 +12,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
<packaging>jar</packaging>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
<name>Logback Skin</name>
<url>http://logback.qos.ch</url>
Modified: logback/trunk/pom.xml
==============================================================================
--- logback/trunk/pom.xml (original)
+++ logback/trunk/pom.xml Wed Jan 31 16:22:37 2007
@@ -5,7 +5,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Logback-Parent</name>
Modified: logback/trunk/src/site/site.xml
==============================================================================
--- logback/trunk/src/site/site.xml (original)
+++ logback/trunk/src/site/site.xml Wed Jan 31 16:22:37 2007
@@ -4,7 +4,7 @@
<skin>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
- <version>1.0-SNAPSHOT</version>
+ <version>0.9.1-SNAPSHOT</version>
</skin>
<!--
<publishDate position="navigation-bottom" format="dd-MM-yyyy"/>
1
0
January 31st, 2007 - Release of version 0.9
This version contains a new component, namely the ContextSelector, that provides
context separation and management when logback is used by several web-apps running
under the same server. A new chapter[1] was added to the logback manual to detail the
use of the ContextSelector, along with its associated components.
The JMXConfigurator has been improved. It now shows the context's Status objects,
which lets users check the internal state of logback.
The logback manual's chapter 2, about logback's architecture[2], has been updated
with two sections: Under the hood and Performance.
Cheers,
Sébastien
Links:
[1] http://logback.qos.ch/manual/contextSelector.html
[2] http://logback.qos.ch/manual/architecture.html
--
Sébastien Pennec
sebastien(a)qos.ch
Logback: The reliable, generic, fast and flexible logging framework for Java.
http://logback.qos.ch/
1
0
svn commit: r1302 - in logback/trunk: . log4j-bridge logback-access logback-classic logback-core logback-examples logback-site logback-site/src/site logback-skin src/site
by noreply.seb@qos.ch 31 Jan '07
by noreply.seb@qos.ch 31 Jan '07
31 Jan '07
Author: seb
Date: Wed Jan 31 14:28:25 2007
New Revision: 1302
Modified:
logback/trunk/log4j-bridge/pom.xml
logback/trunk/logback-access/pom.xml
logback/trunk/logback-classic/pom.xml
logback/trunk/logback-core/pom.xml
logback/trunk/logback-examples/pom.xml
logback/trunk/logback-site/pom.xml
logback/trunk/logback-site/src/site/site.xml
logback/trunk/logback-skin/pom.xml
logback/trunk/pom.xml
logback/trunk/src/site/site.xml
Log:
New version: 1.0-SNAPSHOT :)
Modified: logback/trunk/log4j-bridge/pom.xml
==============================================================================
--- logback/trunk/log4j-bridge/pom.xml (original)
+++ logback/trunk/log4j-bridge/pom.xml Wed Jan 31 14:28:25 2007
@@ -5,14 +5,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>log4j-bridge</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Log4j Bridge Module</name>
Modified: logback/trunk/logback-access/pom.xml
==============================================================================
--- logback/trunk/logback-access/pom.xml (original)
+++ logback/trunk/logback-access/pom.xml Wed Jan 31 14:28:25 2007
@@ -3,14 +3,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Logback Access Module</name>
Modified: logback/trunk/logback-classic/pom.xml
==============================================================================
--- logback/trunk/logback-classic/pom.xml (original)
+++ logback/trunk/logback-classic/pom.xml Wed Jan 31 14:28:25 2007
@@ -5,14 +5,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Logback Classic Module</name>
Modified: logback/trunk/logback-core/pom.xml
==============================================================================
--- logback/trunk/logback-core/pom.xml (original)
+++ logback/trunk/logback-core/pom.xml Wed Jan 31 14:28:25 2007
@@ -5,14 +5,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Logback Core Module</name>
Modified: logback/trunk/logback-examples/pom.xml
==============================================================================
--- logback/trunk/logback-examples/pom.xml (original)
+++ logback/trunk/logback-examples/pom.xml Wed Jan 31 14:28:25 2007
@@ -3,14 +3,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-examples</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Logback Examples Module</name>
Modified: logback/trunk/logback-site/pom.xml
==============================================================================
--- logback/trunk/logback-site/pom.xml (original)
+++ logback/trunk/logback-site/pom.xml Wed Jan 31 14:28:25 2007
@@ -3,7 +3,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -11,7 +11,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-site</artifactId>
<packaging>jar</packaging>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
<name>Logback Site</name>
<url>http://logback.qos.ch</url>
Modified: logback/trunk/logback-site/src/site/site.xml
==============================================================================
--- logback/trunk/logback-site/src/site/site.xml (original)
+++ logback/trunk/logback-site/src/site/site.xml Wed Jan 31 14:28:25 2007
@@ -4,7 +4,7 @@
<skin>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
</skin>
<publishDate position="navigation-bottom" format="dd-MM-yyyy"/>
Modified: logback/trunk/logback-skin/pom.xml
==============================================================================
--- logback/trunk/logback-skin/pom.xml (original)
+++ logback/trunk/logback-skin/pom.xml Wed Jan 31 14:28:25 2007
@@ -3,7 +3,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
</parent>
@@ -12,7 +12,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
<packaging>jar</packaging>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
<name>Logback Skin</name>
<url>http://logback.qos.ch</url>
Modified: logback/trunk/pom.xml
==============================================================================
--- logback/trunk/pom.xml (original)
+++ logback/trunk/pom.xml Wed Jan 31 14:28:25 2007
@@ -5,7 +5,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Logback-Parent</name>
Modified: logback/trunk/src/site/site.xml
==============================================================================
--- logback/trunk/src/site/site.xml (original)
+++ logback/trunk/src/site/site.xml Wed Jan 31 14:28:25 2007
@@ -4,7 +4,7 @@
<skin>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
- <version>0.9</version>
+ <version>1.0-SNAPSHOT</version>
</skin>
<!--
<publishDate position="navigation-bottom" format="dd-MM-yyyy"/>
1
0
Author: seb
Date: Wed Jan 31 14:25:04 2007
New Revision: 1301
Added:
logback/tags/release-0.9/
- copied from r1300, /logback/trunk/
Log:
Tagging release 0.9
1
0
31 Jan '07
Author: seb
Date: Wed Jan 31 11:31:02 2007
New Revision: 1300
Added:
logback/trunk/log4j-bridge/compatibility/lib/log4j-bridge-0.9.jar (contents, props changed)
logback/trunk/log4j-bridge/compatibility/lib/logback-classic-0.9.jar (contents, props changed)
logback/trunk/log4j-bridge/compatibility/lib/logback-core-0.9.jar (contents, props changed)
Removed:
logback/trunk/log4j-bridge/compatibility/lib/log4j-bridge-0.8.jar
logback/trunk/log4j-bridge/compatibility/lib/logback-classic-0.8.jar
logback/trunk/log4j-bridge/compatibility/lib/logback-core-0.8.jar
Log:
Updated test jars to 0.9
Added: logback/trunk/log4j-bridge/compatibility/lib/log4j-bridge-0.9.jar
==============================================================================
Binary file. No diff available.
Added: logback/trunk/log4j-bridge/compatibility/lib/logback-classic-0.9.jar
==============================================================================
Binary file. No diff available.
Added: logback/trunk/log4j-bridge/compatibility/lib/logback-core-0.9.jar
==============================================================================
Binary file. No diff available.
1
0
svn commit: r1299 - in logback/trunk: . log4j-bridge logback-access logback-classic logback-core logback-examples logback-site logback-site/src/site logback-skin src/site
by noreply.seb@qos.ch 31 Jan '07
by noreply.seb@qos.ch 31 Jan '07
31 Jan '07
Author: seb
Date: Wed Jan 31 11:30:38 2007
New Revision: 1299
Modified:
logback/trunk/log4j-bridge/pom.xml
logback/trunk/logback-access/pom.xml
logback/trunk/logback-classic/pom.xml
logback/trunk/logback-core/pom.xml
logback/trunk/logback-examples/pom.xml
logback/trunk/logback-site/pom.xml
logback/trunk/logback-site/src/site/site.xml
logback/trunk/logback-skin/pom.xml
logback/trunk/pom.xml
logback/trunk/src/site/site.xml
Log:
Updated version to 0.9
Modified: logback/trunk/log4j-bridge/pom.xml
==============================================================================
--- logback/trunk/log4j-bridge/pom.xml (original)
+++ logback/trunk/log4j-bridge/pom.xml Wed Jan 31 11:30:38 2007
@@ -5,14 +5,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>log4j-bridge</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
<packaging>jar</packaging>
<name>Log4j Bridge Module</name>
Modified: logback/trunk/logback-access/pom.xml
==============================================================================
--- logback/trunk/logback-access/pom.xml (original)
+++ logback/trunk/logback-access/pom.xml Wed Jan 31 11:30:38 2007
@@ -3,14 +3,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
<packaging>jar</packaging>
<name>Logback Access Module</name>
Modified: logback/trunk/logback-classic/pom.xml
==============================================================================
--- logback/trunk/logback-classic/pom.xml (original)
+++ logback/trunk/logback-classic/pom.xml Wed Jan 31 11:30:38 2007
@@ -5,14 +5,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
<packaging>jar</packaging>
<name>Logback Classic Module</name>
Modified: logback/trunk/logback-core/pom.xml
==============================================================================
--- logback/trunk/logback-core/pom.xml (original)
+++ logback/trunk/logback-core/pom.xml Wed Jan 31 11:30:38 2007
@@ -5,14 +5,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
<packaging>jar</packaging>
<name>Logback Core Module</name>
Modified: logback/trunk/logback-examples/pom.xml
==============================================================================
--- logback/trunk/logback-examples/pom.xml (original)
+++ logback/trunk/logback-examples/pom.xml Wed Jan 31 11:30:38 2007
@@ -3,14 +3,14 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-examples</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
<packaging>jar</packaging>
<name>Logback Examples Module</name>
Modified: logback/trunk/logback-site/pom.xml
==============================================================================
--- logback/trunk/logback-site/pom.xml (original)
+++ logback/trunk/logback-site/pom.xml Wed Jan 31 11:30:38 2007
@@ -3,7 +3,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -11,7 +11,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-site</artifactId>
<packaging>jar</packaging>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
<name>Logback Site</name>
<url>http://logback.qos.ch</url>
Modified: logback/trunk/logback-site/src/site/site.xml
==============================================================================
--- logback/trunk/logback-site/src/site/site.xml (original)
+++ logback/trunk/logback-site/src/site/site.xml Wed Jan 31 11:30:38 2007
@@ -4,7 +4,7 @@
<skin>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
</skin>
<publishDate position="navigation-bottom" format="dd-MM-yyyy"/>
Modified: logback/trunk/logback-skin/pom.xml
==============================================================================
--- logback/trunk/logback-skin/pom.xml (original)
+++ logback/trunk/logback-skin/pom.xml Wed Jan 31 11:30:38 2007
@@ -3,7 +3,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
</parent>
@@ -12,7 +12,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
<packaging>jar</packaging>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
<name>Logback Skin</name>
<url>http://logback.qos.ch</url>
Modified: logback/trunk/pom.xml
==============================================================================
--- logback/trunk/pom.xml (original)
+++ logback/trunk/pom.xml Wed Jan 31 11:30:38 2007
@@ -5,7 +5,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
<packaging>pom</packaging>
<name>Logback-Parent</name>
Modified: logback/trunk/src/site/site.xml
==============================================================================
--- logback/trunk/src/site/site.xml (original)
+++ logback/trunk/src/site/site.xml Wed Jan 31 11:30:38 2007
@@ -4,7 +4,7 @@
<skin>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-skin</artifactId>
- <version>0.9-SNAPSHOT</version>
+ <version>0.9</version>
</skin>
<!--
<publishDate position="navigation-bottom" format="dd-MM-yyyy"/>
1
0