All Downloads are FREE. Search and download functionalities are using the official Maven repository.

k.logback-site.0.7.source-code.shortIntro.xml Maven / Gradle / Ivy

<document>
	<!-- 
	
		Warning: do not use any auto-format function on this file.
		Since "source" divs use pre as white-space, it affects the
		look of the code parts in this document.
	
	 -->


	<body>
    <h2>Short introduction</h2>
    <div class="author">
    	Authors: Ceki G&#252;lc&#252;, S&#233;bastien Pennec
    </div>


		<table>
			<tr>
				<td valign="top" align="top">
						<a rel="license"
							href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
							<img alt="Creative Commons License"
								style="border-width: 0"
								src="http://creativecommons.org/images/public/somerights20.png" />
						</a>
				</td>
				<td>
					<p>Copyright &#169; 2000-2006, QOS.ch</p>

					<p>
						<!--Creative Commons License-->
						This work is licensed under a
						<a rel="license"
							href="http://creativecommons.org/licenses/by-nc-sa/2.5/">
							Creative Commons
							Attribution-NonCommercial-ShareAlike 2.5
							License
						</a>
						.
						<!--/Creative Commons License-->
					</p>
				</td>
			</tr>
		</table>


    <h2>Introduction</h2>

    <p>
    	Logback is intended as a successor to the popular log4j project.
    	It was designed by Ceki G&#252;lc&#252;, the founder of the
    	log4j project. 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 configutation system, which can be
    	put to use in your own projects for great effect.
    </p>

    <p>
    	This document presents the more basic concepts in logback,
    	enough to get you started.
    </p>

    <h2>Logback architecture</h2>

    <p>
    	Logback's basic architecture is sufficiently generic so as to
    	apply under different circumstances. At present time, logback is
    	divided into three modules, Core, Classic and Access.
    </p>

    <p>
    	The <em>core</em> module lays the groundwork for the other two
    	modules.  The <em>classic</em> module extends <em>core</em>. The
    	classic module can be assimilated 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 this document, we will write "logback" to refer to the
    	logback classic module.
    </p>

    <h2>First Baby Step</h2>

    <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>In order to facilitate running the the examples in this
    introduction, we have placed the required slf4j-api.jar file in
    the <em>$LOGBACK_HOME/logback-examples/lib</em>
    directory. Assuming your current directory is
    $LOGBACK_HOME/logback-examples, where $LOGBACK_HOME is the
    directory you've installed logback, you can launch the first
    sample application, <em>chapter1.HelloWord1</em> with the command:
    </p>
    <div class="source"><pre>java -cp lib/slf4j-api-1.1.0-beta0.jar;../logback-core-${version}.jar;\
     ../logback-classic-${version}.jar;logback-examples-${version}.jar\
     chapter1.HelloWorld1</pre></div>

		<p>
			Suprisingly enough, launching the <code>HelloWorld1</code>
			application will not produce <em>any</em> output. 
			Indeed, logback does not posses a default configuration.
			Without a valid configuration, logback will be as silent as a grave.
		</p>

		<p>
			Logback can report information about its internal state
			using a built-in status system. Important events occuring
			during logback's lifetime can be accessed through a
			<code>StatusManager</code>. For the time being, let us 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>ERROR in Logger[chapter1.HelloWorld2] - No appenders present in \ 
context [default] for logger [chapter1.HelloWorld2].</pre></div>


  <p>
  	Logback complains that no appenders were configured for the
  	default context. 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, Socket, JMS and
  	many more. Users can also easily create their own Appenders as
  	appropriate for their specific situation.
  </p>

  <p>
  	Configuring logback can be done in various ways. The simplest but
  	least flexible way is by calling the
  	<code>BasicConfigurator</code> class, like in the following code
  	snippet.
  </p>
  <em>Example 1.3: Configuring before logging (<a href="xref/chapter1/HelloWorld3.html">logback-examples/src/main/java/chapter1/HelloWorld3.java)</a></em>
  <div class="source"><pre>package chapter1;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

<b>import ch.qos.logback.classic.BasicConfigurator;</b>
import ch.qos.logback.classic.util.LoggerStatusPrinter;

public class HelloWorld3 {

  public static void main(String[] args) {
    Logger logger = LoggerFactory.getLogger("chapter1.HelloWorld3");
    <b>BasicConfigurator.configureDefaultContext();</b>
    logger.debug("Hello world.");
    LoggerStatusPrinter.printStatusInDefaultContext();

  }
}</pre></div>

		<p>
			Let's run the <code>HelloWorld3</code> application. In this
			example, the <code><a
			href="xref/ch/qos/logback/classic/BasicConfigurator.html">BasicConfigurator</a></code>
			class's <code>configureDefaultContext()</code> method is
			invoked. It will create a simple <code>ConsoleAppender</code>.
			The logging request will then be propagated to the
			<code>Appender</code> and the console will output the following:
		</p>
<div class="source"><pre>0    [main] DEBUG chapter1.HelloWorld3 - Hello world.</pre></div>

		<p>
			This example is 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 don't need
			(nor should) configure the logging context in each and every
			class that requires logging. As you will see later on in this
			document, configuring logback can be done in different flexible
			and powerfull ways.  Note that, normally, you won't need to
			invoke <code>LoggerStatusPrinter</code> after your log
			statements.
		</p>

		<p>	
			Here is a list of the three required steps in order to enable
			logging in your application.
		</p>

		<ol>

			<li>Configure the logback environment. You can do so in several
			more or less sophisticated ways. The BasicConfigurator is the
			simplest but also least flexible. More on this later.</li>

			<li>In every class where you wish to perform logging, retrieve a
			<code>Logger</code> instance by invoking the
			<code>org.slf4j.LoggerFactory</code> class'
			<code>getLogger()</code> method, passing the current class name
			or the class itself as parameter.</li>
			
      <li>Use this logger instance by invoking its printing methods,
      namely the debug(), info(), warn() and error(). This will
      produce logging output on the configured appenders.</li>
		</ol>

		
		<h2>Logger, Appenders and Layouts</h2>
		
		<p>
			Logback has three main components: Loggers,
			Appenders and Layouts. These three types of components work
			together to enable developers to log messages according to
			message type and level, and to control at runtime how these
			messages are formatted and where they are reported.
		</p>
		<p>
			The Logger class is part of the classic module. On the other
			hand, Appenders and Layouts are part of the core module. For the
			sake of genericity, logback-core has no notion of loggers.
		</p>

    <h3>Logger context</h3>

		<p>The first and foremost advantage of any logging API over plain
		<code>System.out.println</code> resides in its ability to disable
		certain log statements while allowing others to print
		unhindered. This capability assumes that the logging space, that
		is, the space of all possible logging statements, is categorized
		according to some developer-chosen criteria.  In logback, this
		categorization is an inherent part of loggers.
		</p>
			
		<p>
			Loggers are named entities. Their names are case-sensitive and
			they follow the hierarchical naming rule:
		</p>
		<div class="definition">
			<div class="deftitle">Named Hierarchy</div>
			<p>
				A logger is said to be an ancestor of another logger if
				its name followed by a dot is a prefix of the descendant
				logger name. A logger is said to be a parent of a child
				logger if there are no ancestors between itself and the
				descendant logger.
			</p>
		</div>

		<p>
			For example, the logger named <code>"com.foo"</code>
			is a parent of the logger named <code>"com.foo.Bar"</code>. 
			Similarly, <code>"java"</code>
			is a parent of <code>"java.util"</code> and an ancestor of
			<code>"java.util.Vector"</code>. 
			This naming scheme should be familiar to most developers.
		</p>
		<p>
			The root logger resides at the top of the logger hierarchy.  It
			is exceptional in that it is part of every hierarchy at its
			inception. Like every logger, it can be retrieved by its name,
			as follows:
		</p>
		<div class="source"><pre>Logger rootLogger = LoggerFactory.getLogger(<a href="apidocs/constant-values.html#ch.qos.logback.classic.LoggerContext.ROOT_NAME">LoggerContext.<em>ROOT_NAME</em></a>);</pre></div>

		<p>
			All other loggers are also retrieved with the class static
			<code>getLogger</code> method found in the <b>CHECK THE
			URL</b><a
			href="http://www.slf4j.org/javadocs/org/slf4j/Logger.html">org.slf4j.LoggerFactory</a>
			class. This method takes the name of the desired logger as a
			parameter. Some of the basic methods in the <code>Logger</code>
			interface are listed below.
		</p>

		<div class="source"><pre>package org.slf4j; 
public interface Logger {

  // Printing methods: 
  public void debug(String message);
  public void info(String message); 
  public void warn(String message); 
  public void error(String message); 
  public void fatal(String message); 
}</pre></div>

		<p>
			Loggers may be assigned levels. The set of possible levels, that
			is DEBUG, INFO, WARN and ERROR are defined in the
			<code>ch.qos.logback.classic.Level</code> class. Note that in
			logback, the level class is final and cannot be derived as a
			much more flexible approach exist in the form of Marker objects.
		</p>

		<p>
			If a given logger is not assigned a level, then it inherits
			one from its closest ancestor with an assigned level. More
			formally:
		</p>

		<div class="definition">
			<div class="deftitle">Level Inheritance</div>
			<p>
				The effective level for a given logger <em>L</em>, is equal to
				the first non-null level in its hierarchy, starting at
				<em>L</em> itself and proceeding upwards in the context
				towards the root logger.
			</p>
		</div>
	
		<p>
			To ensure that all loggers can eventually inherit a level, the
			root logger always has an assigned level. By default, this level
			is DEBUG.
		</p>
		<p>
			Below are four examples with various assigned level values and
			the resulting effective (inherited) levels according to the
			level inheritance rule.
		</p>

		<em>Example 1</em>
		<table>
			<tr>
				<th>
					Logger name
				</th>
				<th>
					Assigned level
				</th>

				<th>
					Effective level
				</th>
			</tr>
			<tr>
				<td>root</td>
				<td>DEBUG</td>
				<td>DEBUG</td>
			</tr>
			<tr>
				<td>X</td>
				<td>none</td>
				<td>DEBUG</td>
			</tr>

			<tr>
				<td>X.Y</td>
				<td>none</td>
				<td>DEBUG</td>
			</tr>
			<tr>
				<td>X.Y.Z</td>
				<td>none</td>
				<td>DEBUG</td>
			</tr>
		</table>

		<p> In example 1 above, only the root logger is assigned a level.
		This level value, <code>DEBUG</code>, is inherited by the other
		loggers <code>X</code>, <code>X.Y</code> and <code>X.Y.Z</code>
		</p>

		<em>Example 2</em>
		<table>
			<tr>
				<th>
					Logger name
				</th>
				<th>
					Assigned level
				</th>

				<th>
					Effective level
				</th>
			</tr>
			<tr align="left">
				<td>root</td>
				<td>ERROR</td>
				<td>ERROR</td>
			</tr>
			<tr align="left">
				<td>X</td>
				<td>INFO</td>
				<td>INFO</td>
			</tr>

			<tr align="left">
				<td>X.Y</td>
				<td>DEBUG</td>
				<td>DEBUG</td>
			</tr>
			<tr align="left">
				<td>X.Y.Z</td>
				<td>WARN</td>
				<td>WARN</td>
			</tr>
		</table>

		<p>In example 2 above, all loggers have an assigned level value.
		There is no need for level inheritence.
		</p>

		<em>Example 3</em>
		<table>
			<tr>
				<th>
					Logger name
				</th>
				<th>
					Assigned level
				</th>
				<th>
					Effective level
				</th>
			</tr>
			<tr align="left">
				<td>root</td>
				<td>DEBUG</td>
				<td>DEBUG</td>
			</tr>

			<tr align="left">
				<td>X</td>
				<td>INFO</td>
				<td>INFO</td>
			</tr>
			<tr align="left">
				<td>X.Y</td>
				<td>none</td>
				<td>INFO</td>
			</tr>
			<tr align="left">
				<td>X.Y.Z</td>
				<td>ERROR</td>
				<td>ERROR</td>
			</tr>
		</table>
		<p>
			In example 3 above, the loggers <code>root</code>, <code>X</code>
			and <code>X.Y.Z</code> are assigned the levels <code>DEBUG</code>,
			<code>INFO</code> and <code>ERROR</code>
			respectively. Logger <code>X.Y</code>
			inherits its level value from its parent <code>X</code>.
		</p>
		<em>Example 4</em>
		<table>

			<tr>
				<th>
					Logger name
				</th>
				<th>
					Assigned level
				</th>
				<th>
					Effective level
				</th>
			</tr>
			<tr align="left">
				<td>root</td>
				<td>DEBUG</td>
				<td>DEBUG</td>
			</tr>

			<tr align="left">
				<td>X</td>
				<td>INFO</td>
				<td>INFO</td>
			</tr>
			<tr align="left">
				<td>X.Y</td>
				<td>none</td>
				<td>INFO</td>
			</tr>
			<tr align="left">
				<td>X.Y.Z</td>
				<td>none</td>
				<td>INFO</td>
			</tr>
		</table>

   
		<p>In example 4 above, the loggers <code>root</code> and
		<code>X</code> and are assigned the levels <code>DEBUG</code> and
		<code>INFO</code> respectively. The loggers <code>X.Y</code> and
		<code>X.Y.Z</code> inherit their level value from their nearest
		parent <code>X</code>, which has an assigned level.
		</p>

    <h3>Printing methods</h3>

		<p>By definition, the printing method determines the level of a
		logging request. For example, if <code>L</code> is a logger
		instance, then the statement <code>L.info("..")</code> is a
		logging request of level INFO.
		</p>
		
    <p>A logging request is said to be <em>enabled</em> if its level
    is higher than or equal to the level of its logger. Otherwise, the
    request is said to be <em>disabled</em>. A logger without an
    assigned level will inherit one from the context. This rule is
    summarized below.
		</p>

		<div class="definition">
			<div class="deftitle">Basic Selection Rule</div>

			<p>A log request of level <em>p</em> in a logger with an
			effective level <em>q</em>, is enabled if <em>p &gt;= q</em>.
			</p>
		</div>

		<p>
			This rule is at the heart of logback. It assumes
			that levels are ordered as follows: 
			<code>DEBUG &lt; INFO &lt; WARN &lt; ERROR</code>.
		</p>
				
		<p>In a more graphic way, here is how the selection rule works. In
		the following table, the vertical header shows the the level of
		the logging request, designated by <em>p</em>, while the
		horizontal header shows effective level of the logger, designated
		by <em>q</em>.
		</p>
		
		<table>
			<tr>
				<th><span style="align:center"><em>p</em>/<em>q</em></span></th>
				<th>DEBUG</th>
				<th>INFO</th>
				<th>WARN</th>
				<th>ERROR</th>				
			</tr>
			<tr>
				<th>DEBUG</th>
				<td><span class="greenBold">YES</span></td>
				<td><span class="redBold">NO</span></td>
				<td><span class="redBold">NO</span></td>
				<td><span class="redBold">NO</span></td>
			</tr>
			<tr>
				<th>INFO</th>
				<td><span class="greenBold">YES</span></td>
				<td><span class="greenBold">YES</span></td>
				<td><span class="redBold">NO</span></td>
				<td><span class="redBold">NO</span></td>
			</tr>
			<tr>
				<th>WARN</th>
				<td><span class="greenBold">YES</span></td>
				<td><span class="greenBold">YES</span></td>
				<td><span class="greenBold">YES</span></td>
				<td><span class="redBold">NO</span></td>
			</tr>
			<tr>
				<th>ERROR</th>
				<td><span class="greenBold">YES</span></td>
				<td><span class="greenBold">YES</span></td>
				<td><span class="greenBold">YES</span></td>
				<td><span class="greenBold">YES</span></td>
			</tr>		
		</table>
		
		<p>Here is an example of the basic selection rule.</p>

		<div class="source"><pre>// get a logger instance named "com.foo", with an <span class="blue">INFO</span> level. 
Logger logger = LoggerFactory.getLogger("com.foo");
//set its Level to <span class="blue">INFO</span>
logger.setLevel(Level. <span class="blue">INFO</span>);
Logger barlogger = LoggerFactory.getLogger("com.foo.Bar");

// This request is enabled, because <span class="green bold">WARN</span> &gt;= <span class="blue">INFO</span>
logger.<span class="green bold">warn</span>("Low fuel level.");

// This request is disabled, because <span class="green bold">DEBUG</span> &lt; <span class="blue">INFO</span>. 
logger.<span class="green bold">debug</span>("Starting search for nearest gas station.");

// The logger instance barlogger, named "com.foo.Bar", 
// will inherit its level from the logger named 
// "com.foo" Thus, the following request is enabled 
// because <span class="green bold">INFO</span> &gt;= <span class="blue">INFO</span>. 
barlogger.<span class="green bold">info</span>("Located nearest gas station.");

// This request is disabled, because <span class="green bold">DEBUG</span> &lt; <span class="blue">INFO</span>. 
barlogger.<span class="green bold">debug</span>("Exiting gas station search");</pre></div>

		<h3>Retrieving Loggers</h3>
		<p>
			Calling the <code><a href="/apidocs/org/slf4j/LoggerFactory.html#getLogger(java.lang.String)">LoggerFactory.getLogger</a></code>
			method with the same name will always return a reference to
			the exact same logger object.
		</p>

		<p>For example, in</p>
		<div class="source"><pre>Logger x = LoggerFactory.getLogger("wombat"); 
Logger y = LoggerFactory.getLogger("wombat");</pre></div>

		<p>
			<code>x</code> and <code>y</code> refer to
			<em>exactly</em> the same logger object.
		</p>

		<p>
			Thus, it is possible to configure a logger and then to
			retrieve the same instance somewhere else in the code
			without passing around references. In fundamental
			contradiction to biological parenthood, where parents always
			preceed their children, logback loggers can be
			created and configured in any order. In particular, a
			"parent" logger will find and link to its descendants even
			if it is instantiated after them.
		</p>
		<p>
			Configuration of the logback environment is typically done
			at application initialization. The preferred way is by
			reading a configuration file. This approach will be
			discussed shortly.
		</p>
		<p>
			Logback makes it easy to name loggers by <em>software
			component</em>.  This can be accomplished by instantiating a
			logger in each class, with the logger name equal to the fully
			qualified name of the class. This is a useful and
			straightforward method of defining loggers. As the log output
			bears the name of the generating logger, this naming strategy
			makes it easy to identify the origin of a log message. However,
			this is only one possible, albeit common, strategy for naming
			loggers. Logback does not restrict the possible set of
			loggers. As a developer, you are free to name loggers as you
			wish.
		</p>

		<p>Nevertheless, naming loggers after the class where they are
		located seems to be the best strategy known so far.
		</p>

    <h3>Appenders and Layouts</h3>

		<p>
			The ability to selectively enable or disable logging requests
			based on their logger is only part of the picture.  Logback
			allows logging requests to print to multiple destinations. In
			logback speak, an output destination is called an
			appender. Currently, appenders exist for the console, files,
			remote socket servers, to MySQL, PostgreSQL, Oracle and other
			databases, to JMS, and remote UNIX Syslog daemons. 

      <!--It is also possible to log asynchronously. -->
		</p>

		<p>More than one appender can be attached to a logger.</p>

		<p> The <code><a href="apidocs/ch/qos/logback/classic/Logger.html#addAppender(ch.qos.logback.core.Appender)">addAppender</a></code> method adds an appender to a
		given logger.  Each enabled logging request for a given logger
		will be forwarded to all the appenders in that logger as well as
		the appenders higher in the context. In other words, appenders are
		inherited additively from the logger context. For example, if a
		console appender is added to the root logger, then all enabled
		logging requests will at least print on the console. If in
		addition a file appender is added to a logger, say <em>L</em>,
		then enabled logging requests for <em>L</em> and <em>L</em>'s
		children will print on a file <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
		to false.
		</p>

		<p>
			The rules governing appender additivity are summarized
			below.
		</p>
		<div class="definition">

			<div class="deftitle">Appender Additivity</div>

			<p>
				The output of a log statement of logger <em>L</em>
				will go to all the appenders in <em>L</em>
				and its ancestors. This is the meaning of the term
				"appender additivity".
			</p>

			<p>
				However, if an ancestor of logger <em>L</em>, say
				<em>P</em>, has the additivity flag set to false, then
				<em>L</em>'s output will be directed to all the appenders in
				<em>L</em> and it's ancestors upto and including
				<em>P</em> but not the appenders in any of the ancestors of
				<em>P</em>.
			</p>

			<p>
				Loggers have their additivity flag set to true by
				default.
			</p>

		</div>
		The table below shows an example:

		<table class="bodyTable">
			<tr>
				<th>Logger Name</th>
				<th>Attached Appenders</th>
				<th>Additivity Flag</th>
				<th>Output Targets</th>
				<th>Comment</th>
			</tr>
			<tr>
				<td>root</td>
				<td>A1</td>
				<td>not applicable</td>
				<td>A1</td>

				<td>Since the root logger stands at the top of the logger
				hiearchy, the additivity flag does not apply to it.
				</td>
			</tr>
			<tr>
				<td>x</td>
				<td>A-x1, A-x2</td>
				<td>true</td>
				<td>A1, A-x1, A-x2</td>
				<td>Appenders of "x" and of root.</td>
			</tr>
			<tr>
				<td>x.y</td>
				<td>none</td>
				<td>true</td>
				<td>A1, A-x1, A-x2</td>
				<td>Appenders of "x" and of root.</td>
			</tr>
			<tr>
				<td>x.y.z</td>
				<td>A-xyz1</td>
				<td>true</td>
				<td>A1, A-x1, A-x2, A-xyz1</td>
				<td>Appenders of "x.y.z", "x" and of root.</td>
			</tr>
			<tr>
				<td>security</td>
				<td>A-sec</td>
				<td class="blue"><span class="blue">false</span></td>
				<td>A-sec</td>

				<td>
					No appender accumulation since the additivity flag is set to
					<code>false</code>. Only appender A-sec will be used.
				</td>
			</tr>
			<tr>
				<td>security.access</td>
				<td>none</td>
				<td>true</td>				
        <td>A-sec</td>
				<td>
					Only appenders of "security" because the additivity
					flag in "security" is set to
					<code>false</code>.
				</td>
			</tr>
		</table>


		<p>
			More often than not, users wish to customize not only the
			output destination but also the output format. This is
			accomplished by associating a <em>layout</em>
			with an appender. The layout is responsible for formatting
			the logging request according to the user's wishes, whereas
			an appender takes care of sending the formatted output to
			its destination. The <code>PatternLayout</code>, part of the standard
			logback distribution, lets the user specify the output
			format according to conversion patterns similar to the C
			language <code>printf</code>
			function.
		</p>

		<p>
			For example, the PatternLayout with the conversion pattern
			"%-4relative [%thread] %-5level %logger{32} - %msg%n" will output something akin to:
		</p>

		<div class="source"><pre>176  [main] DEBUG chapter1.HelloWorld3 - 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 statement. The fourth field is the name of the logger
			associated with the log request. The text after the '-' is
			the message of the statement.
		</p>

		<h3>Parameterized logging</h3>

		<p>
			Given that loggers in logback-classic implement the <a
			href="http://www.slf4j.org/api/org/slf4j/Logger.html">SLF4J's
			Logger interface</a>, certain printing methods admit more than
			one parameter. These printing method variants are mainly
			intended to improve performance while minimizing the impact on
			the readability of the code.
		</p>

		<p>
			For some Logger <code>logger</code>, writing,
		</p>

		<div class="source"><pre>logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));</pre></div>

		<p>
			incurs the cost of constructing the message parameter, that
			is converting both integer <code>i</code> and <code>entry[i]</code>
			to a String, and concatenating intermediate strings. This,
			regardless of whether the message will be logged or not.
		</p>

		<p>
			One possible way to avoid the cost of parameter construction
			is by surrounding the log statement with a test. Here is an
			example.
		</p>

		<div class="source"><pre>if(logger.isDebugEnabled()) { 
  logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}</pre></div>


		<p>
			This way you will not incur the cost of parameter
			construction if debugging is disabled for <code>logger</code>. 
			On the other hand, if the logger is enabled for the DEBUG
			level, you will incur the cost of evaluating whether the
			logger is enabled or not, twice: once in <code>debugEnabled</code>
			and once in <code>debug</code>. 
			This is an insignificant overhead because evaluating a
			logger takes less than 1% of the time it takes to actually
			log a statement.
		</p>



		<h4>Better alternative</h4>

		<p>
			There exists a very convenient alternative based on message
			formats. Assuming <code>entry</code> is an object, you can write:
		</p>


		<div class="source"><pre>Object entry = new SomeObject(); 
logger.debug("The entry is {}.", entry);</pre></div>

		<p>
			After evaluting whether to log or not, and only if the decision
			is positive, will the logger implementation format the message
			and replace the '{}' pair with the string value of
			<code>entry</code>.  In other words, this form does not incur
			the cost of parameter construction in case the log statement is
			disabled.
		</p>


		<p>
			The following two lines will yield the exact same output.
			However, in case of a <em>disabled</em>
			logging statement, the second variant will outperform the first variant by a
			factor of at least 30.
		</p>

		<div class="source"><pre>logger.debug("The new entry is "+entry+".");
logger.debug("The new entry is {}.", entry);</pre></div>


		<p>
			A two argument variant is also availalble. For example, you
			can write:
		</p>

		<div class="source"><pre>logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);</pre></div>

		<p>If three or more arguments need to be passed, an
		<code>Object[]</code> variant is also availalble. For example, you
		can write:
		</p>


		<div class="source"><pre>Object[] paramArray = {newVal, below, above};
logger.debug("Value {} was inserted between {} and {}.", paramArray);</pre></div>

    <h3>Configuration</h3>

		<p>Inserting log requests into the application code requires a
		fair amount of planning and effort. Observation shows that
		approximately four percent of code is dedicated to
		logging. Consequently, even moderately sized applications will
		contain thousands of logging statements embedded within its
		code. Given their number, it becomes imperative to manage these
		log statements without the need to modify them manually.
		</p>

		<p>The logback environment is fully configurable programmatically.
		However, it is far more flexible to configure logback using
		configuration files. In logback, configuration files are expressed
		in XML.
		</p>

		<p>Existing log4j users can convert their
		<em>log4j.properties</em> files to <em>logback.xml</em> using <a
		href="http://logback.qos.ch/translator/">PropertiesTranslator</a>
		web-application.
		</p>

		<p>Let us give a taste of how logback configuration is done with
		the help of a trivial application named <em>MyApp</em>.
		</p>

		<em>Example 1.4: Basic configuration (<a href="xref/chapter1/MyApp.html">logback-examples/src/main/java/chapter1/MyApp.java</a>)</em>
<div class="source"><pre>package chapter1;

// Import SLF4J classes.
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;

import ch.qos.logback.classic.BasicConfigurator;

public class MyApp {

  public static void main(String[] args) {
	
    // Set up a simple configuration that logs on the console.
    BasicConfigurator.configureDefaultContext();

    Logger logger = LoggerFactory.getLogger(MyApp.class);
	
    logger.info("Entering application.");
    Bar bar = new Bar();
    bar.doIt();
    logger.info("Exiting application.");
  }
}</pre></div>

		<p>This class defines a logger instance variable with the name
		<em>MyApp</em>. It then instantiates a <code>Bar</code>
		object. The <code>Bar</code> class is listed below:
		</p>

		<em>Example 1.4: Basic configuration (<a href="xref/chapter1/Bar.html">logback-examples/src/main/java/chapter1/Bar.java</a>)</em>
<div class="source"><pre>package chapter1;
  
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class Bar {

  Logger logger = LoggerFactory.getLogger(Bar.class);	
	
  public void doIt() {
    logger.debug("doing my job");
  }
}</pre></div>

		<p>The invocation of the <code>configureDefaultContext()</code>
		method in <code>BasicConfigurator</code> creates, as we have seen
		previously, a minimal logback setup. Note that, by default, the
		root Logger is assigned to Level.DEBUG.
		</p>

		<p>
			The output of MyApp is:
		</p>
<div class="source"><pre>22:05:21.461 [main] INFO  chapter1.MyApp - Entering application.
22:05:21.461 [main] DEBUG chapter1.Bar - doing my job
22:05:21.461 [main] INFO  chapter1.MyApp - Exiting application.</pre></div>

<!-- =========  CEKI: STOPPED HERE =================== -->

    <p><em>MyApp</em> configures logback by invoking
    <code>BasicConfigurator.configureDefaultContext()</code>. 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>The previous example output logging information always in the
  	same fixed format. Fortunately, it is easy to modify an
  	application so that logging environment is configured at runtime.
    </p>

     <em>Example 1.5: Logback configuration from file ((<a
  href="xref/chapter1/MyAppWithConfigFile.html">logback-examples/src/main/java/chapter1/MyAppWithConfigFile.java</a>)</em>

<div class="source"><pre>package chapter1;

//Import SLF4J classes.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.util.StatusPrinter;

public class MyAppWithConfigFile {
	
  public static void main(String[] args) {
    Logger logger = LoggerFactory.getLogger(MyAppWithConfigFile.class);
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
		
    JoranConfigurator configurator = new JoranConfigurator();
    configurator.setContext(lc);
    configurator.doConfigure(args[0]);

    logger.info("Entering application.");
    Bar bar = new Bar();
    bar.doIt();
    logger.info("Exiting application.");
	
    StatusPrinter.print(lc.getStatusManager());
  }
}</pre></div>	

    <p>MyApp2 instructs PropertyConfigurator to parse a configuration
    file and to set up logging according to the instructions found
    therein. The sample configuration file listed below, also
    available as examples/chapter3/sample0.properties, configures
    log4j (after parsing by PropertyConfigurator) in the same way as
    BasicCon-figurator.configure.
    </p>

    <p>Let us configure logback in the exact same way,
  	but this time with an XML configuration file. The next
  	configuration file, once executed, will have the same affect as
  	calling <code>BasicConfigrator</code>.</p>

	<em>Example 1.4: Basic configuration (logback-examples/src/main/java/chapter1/sample-config-1.xml)</em>	
<div class="source"><pre>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;

&lt;configuration&gt;

  &lt;appender name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender"&gt;
    &lt;layout class="ch.qos.logback.classic.PatternLayout"&gt;
      &lt;pattern&gt;%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n&lt;/pattern&gt;
    &lt;/layout&gt;
  &lt;/appender&gt;

  &lt;root&gt;
    &lt;level value="debug" /&gt;
    &lt;appender-ref ref="STDOUT" /&gt;
  &lt;/root&gt;
&lt;/configuration&gt;</pre></div>
	
	<p>We first created an <code>Appender</code>, named <em>STDOUT</em>
	that is of <code>ConsoleAppender</code> tye. Its layout is managed
	by a PatternLayout, that uses the value of the "pattern" parameter
	to generate the logging statement. We then configured the root
	logger, set its level to DEBUG, and linked the newly configured
	<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 examle, use this command:</p>
	
<div class="source"><pre>java chapter1.MyApp <b>HOW ABOUT PATH?</b>sample-config-1.xml</pre></div>

	<p>The console output will be exactly the same as before. However,
	this time, we didn't need to import and call the BasicConfigurator
	class, as you can see in the following code section:
	</p>
	
 
	<p>We used the JoranConfigurator class to parse the configuration
	file we just created.  Joran is a XML interpreter, similar to the
	commons-digester API, but offering several advantages over
	commons-digester. Here, it parses the xml file and runs actions
	depending on the tags it finds.  To setup the JoranConfigurator
	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>Logging to the console is a rather simple example. Let's now
	configure logback so that it logs to the console, but also to a
	custom file.</p>

<em>Example 1.5: Logback configuration from file (logback-examples/src/main/java/chapter1/sample-config-2.xml)</em>
<div class="source"><pre>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;

&lt;configuration&gt;

  &lt;appender name="STDOUT"
      class="ch.qos.logback.core.ConsoleAppender"&gt;
    &lt;layout class="ch.qos.logback.classic.PatternLayout"&gt;
      &lt;param name="pattern"
        value="%-4relative [%thread] %-5level %class - %msg%n" /&gt;
    &lt;/layout&gt;
  &lt;/appender&gt;

  &lt;appender name="FILE"
      class="ch.qos.logback.core.FileAppender"&gt;
    &lt;layout class="ch.qos.logback.classic.PatternLayout"&gt;
      &lt;param name="pattern"
        value="%-4relative [%thread] %-5level %class - %msg%n" /&gt;
    &lt;/layout&gt;
    &lt;param name="File"
      value="sample-log.txt" /&gt;
  &lt;/appender&gt;

  &lt;root&gt;
    &lt;level value="debug" /&gt;
    &lt;appender-ref ref="STDOUT" /&gt;
    &lt;appender-ref ref="FILE" /&gt;
  &lt;/root&gt;
&lt;/configuration&gt;</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 param
	element, in either Appender configuration, reads the <em>name</em>
	attribute and assigns its value to the corresponding attribute in
	the specified java class.
	</p>
	
	<p>Suppose that we do not want to see the DEBUG level statements in
	the chapter1 package anymore.  This is done by adding the following
	xml snippet to the configuration file, right before the
	<code>&lt;root&gt;</code> element.</p>

<em>Example 1.5: Logback configuration from file (logback-examples/src/main/java/chapter1/sample-config-3.xml)</em>	
<div class="source"><pre>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;

&lt;configuration&gt;

  &lt;appender name="STDOUT"
      class="ch.qos.logback.core.ConsoleAppender"&gt;
    &lt;layout class="ch.qos.logback.classic.PatternLayout"&gt;
      &lt;param name="pattern"
          value="%-4relative [%thread] %-5level %class - %msg%n" /&gt;
    &lt;/layout&gt;
  &lt;/appender&gt;

  &lt;appender name="FILE"
      class="ch.qos.logback.core.FileAppender"&gt;
    &lt;layout class="ch.qos.logback.classic.PatternLayout"&gt;
      &lt;param name="pattern"
          value="%-4relative [%thread] %-5level %class - %msg%n" /&gt;
    &lt;/layout&gt;
      &lt;param name="File"
          value="sample-log.txt" /&gt;
  &lt;/appender&gt;
<b>
  &lt;logger name="chapter1"&gt;
    &lt;level value="info" /&gt;
  &lt;/logger&gt;
</b>
  &lt;root&gt;
    &lt;level value="debug" /&gt;
    &lt;appender-ref ref="STDOUT" /&gt;
    &lt;appender-ref ref="FILE" /&gt;
  &lt;/root&gt;
&lt;/configuration&gt;
</pre></div>	
	
	<p>This done, the output is modified to show only statements of level INFO and higher.</p>
	
<div class="source"><pre>0    [main] INFO  chapter1.MyAppWithConfigFile - Entering application.
0    [main] INFO  chapter1.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 chapter1 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>
	
	</body>
</document>




© 2015 - 2025 Weber Informatics LLC | Privacy Policy