# Chapter 3: Logback configuration

In symbols one observes an advantage in discovery which is greatest when they express the exact nature of a thing briefly and, as it were, picture it; then indeed the labor of thought is wonderfully diminished.

—GOTTFRIED WILHELM LEIBNIZ

Joran stands for a cold north-west wind which, every now and then, blows forcefully on Lake Geneva. Located right in the middle of Europe, the Geneva lake happens to be the continent's largest sweet water reserve.

In the first part, we start by presenting ways for configuring logback, with many example configuration scripts. In the second part, we present Joran, a generic configuration framework, which you can put into use in order to configure your own applications.

## Configuration in logback

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 a moderately sized application will contain thousands of logging statements embedded within its code. Given their number, we need tools to manage these log statements.

Logback can be configured either programmatically or with a configuration script (expressed in XML format). By the way, existing log4j users can convert their log4j.properties files to logback.xml using our PropertiesTranslator web-application.

Let us begin by discussing the initialization steps that logback follows to try to configure itself:

1. Logback tries to find a file called logback-test.xml in the classpath.

2. If no such file is found, it checks for the file logback.xml in the classpath..

3. In case neither file is found, logback configures itself automatically using the `BasicConfigurator` which will cause logging output to be directed on the console.

The third and last step is meant to provide a default (but very basic) logging functionality in the absence of a configuration file.

If you are using Maven and assuming the logback-test.xml file is placed under src/test/resources folder, Maven will ensure that it won't be included in the artifact produced. Thus, you can use a different configuration file, namely logback-test.xml during testing, and another file, namely, logback.xml, in production. The same principle applies by analogy for Ant.

### Automatically configuring logback

The simplest way to configure logback is by letting logback fall back to its default configuration. Let us give a taste of how this is done in an imaginary application called `MyApp1`.

Example 3.: Simple example of `BasicConfigurator` usage (logback-examples/src/main/java/chapters/configuration/MyApp1.java)

    package manual.configuration;

    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.");
      }
    }

This class defines a static logger variable. It then instantiates a Foo object. The Foo class is listed below:

Example 3.: Small class doing logging (logback-examples/src/main/java/chapters/configuration/Foo.java)

    package chapters.configuration;

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

    public class Foo {
      static final Logger logger = LoggerFactory.getLogger(Foo.class);

      public void doIt() {
        logger.debug("Did it again!");
      }
    }

In order to run the examples in this chapter, you need to make sure that certain jar files are present on the class path. Please refer to the setup page for further details.

Assuming the configuration files logback-test.xml or logback.xml are not present, logback will default to invoking `BasicConfigurator` which will set up a minimal configuration. This minimal configuration consists of a `ConsoleAppender` attached to the root logger. The output is formatted using a `PatternLayoutEncoder` set to the pattern %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n. Moreover, by default the root logger is assigned the `DEBUG` level.

Thus, the output of the command java chapters.configuration.MyApp1 should be similar to:

16:06:09.031 [main] INFO chapters.configuration.MyApp1 - Entering application. 16:06:09.046 [main] DEBUG chapters.configuration.Foo - Did it again! 16:06:09.046 [main] INFO chapters.configuration.MyApp1 - Exiting application.

Except code that configures logback (if such code exists) client code does not need to depend on logback. Applications that use logback as their logging framework will have a compile-time dependency on SLF4J but not logback.

The `MyApp1` application links to logback via calls `org.slf4j.LoggerFactory` and `org.slf4j.Logger` classes, retrieve the loggers it wishes to use, and chugs on. Note that the only dependencies of the `Foo` class on logback are through `org.slf4j.LoggerFactory` and `org.slf4j.Logger` imports. Except code that configures logback (if such code exists) client code does not need to depend on logback. Given that SLF4J permits the use of any logging framework under its abstraction layer, it is rather easy to migrate large bodies of code from one logging framework to another.

### Automatic configuration with logback-test.xml or logback.xml

As mentioned earlier, logback will try to configure itself using the files logback-test.xml or logback.xml if found on the class path. Here is a configuration file equivalent to the one established by `BasicConfigurator` we've just seen.

Example 3.: Basic configuration file (logback-examples/src/main/java/chapters/configuration/sample0.xml)

    <configuration>

      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoders are assigned the type
             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
        <encoder>
          <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
      </appender>

      <root level="debug">
        <appender-ref ref="STDOUT" />
      </root>
    </configuration>

After you have renamed sample0.xml as logback.xml (or logback-test.xml) place it into a directory accessible from the class path. Running the MyApp1 application should give identical results to its previous run.

#### Automatic printing of status messages in case of warning or errors

If warning or errors occur during the parsing of the configuration file, logback will automatically print its internal status messages on the console.

If warnings or errors occur during the parsing of the configuration file, logback will automatically print status data on the console. In the absence of warnings or errors, if you still wish to inspect logback's internal status, then you can instruct logback to print status data by invoking the `print()` of the `StatusPrinter` class. The MyApp2 application shown below is identical to MyApp1 except the addition of two lines of code for printing internal status data.

Example 3.: Print logback's internal status information (logback-examples/src/main/java/chapters/configuration/MyApp2.java)

      public static void main(String[] args) {
        // assume SLF4J is bound to logback in the current environment
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        // print logback's internal status
        StatusPrinter.print(lc);
        ...
      }

If everything goes well, you should see the following output on the console

    17:44:58,578 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml]
    17:44:58,671 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
    17:44:58,671 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
    17:44:58,687 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
    17:44:58,812 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Popping appender named [STDOUT] from the object stack
    17:44:58,812 |-INFO in ch.qos.logback.classic.joran.action.LevelAction - root level set to DEBUG
    17:44:58,812 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[root]

    17:44:58.828 [main] INFO  chapters.configuration.MyApp2 - Entering application.
    17:44:58.828 [main] DEBUG chapters.configuration.Foo - Did it again!
    17:44:58.828 [main] INFO  chapters.configuration.MyApp2 - Exiting application.

At the end of this output, you can recognize the lines that were printed in the previous example. You should also notice the logback's internal messages, a.k.a. `Status` objects, which allow convenient access to logback's internal state.

Instead of invoking `StatusPrinter` programmatically from your code, you can instruct the configuration file to dump status data, even in the absence of errors. To achieve this, you need to set the debug attribute of the configuration element, i.e. the top-most element in the configuration file, as shown below. Please note that this debug attribute relates only to the status data. It does not affect logback's configuration otherwise, in particular with respect to logger levels. (If you are asking, no, the root logger will not be set to `DEBUG`.)

Example 3.: Basic configuration file using debug mode (logback-examples/src/main/java/chapters/configuration/sample1.xml)

    <configuration debug="true">

      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoders are  by default assigned the type
             ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
        <encoder>
          <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
      </appender>

      <root level="debug">
        <appender-ref ref="STDOUT" />
      </root>
    </configuration>

Setting the `debug` attribute within the <configuration> element will output status information, under the assumption that

1. the configuration file is found
2. the configuration file is well-formed XML.

If any of these two conditions is not fulfilled, Joran cannot interpret `debug` attribute since the configuration file cannot be read. If the configuration file is found but is ill-formed, then logback will detect the error condition and automatically print its internal status on the console. However, if the configuration file cannot be found, since this is not necessarily an error condition, logback will not automatically print its status data. Programmatically invoking `StatusPrinter.print()`, as as in MyApp2 application above, ensures that status information is always printed.

### Specifying the location of the default configuration file as a system property

If you wish, you can specify the location of the default configuration file with a system property named `logback.configurationFile`. The value of the this property can be a URL, a resource on the class path or a path to a file external to the application.

java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1

### Automatically reloading configuration file upon modification

Logback-classic can scan for changes in its configuration file and automatically reconfigure itself when the said configuration file changes.

If instructed to do so, logback-classic will scan for changes in its configuration file and automatically reconfigure itself when the said configuration file changes. In order to instruct logback-classic to scan for changes in its configuration file and to automatically re-configure itself set the scan atrribute of the `<configuration>` element to true, as shown next.

Example 3.: Scanning for changes in configuration file and automatic re-configuraion (logback-examples/src/main/java/chapters/configuration/scan1.xml)

    <configuration scan="true">
      ...
    </configuration>

By default, the configuration file will be scanned for changes once every minute. You can specify a different scanning period by setting the scanPeriod attribute of the `<configuration>` element. Values can be specified in units of milliseconds, seconds, minutes or hours. Here is an example:

Example 3.: Specifying a different scanning period (logback-examples/src/main/java/chapters/configuration/scan2.xml)

    <configuration scan="true" scanPeriod="30 seconds" >
      ...
    </configuration>

If no unit of time is specified, then the unit of time is assumed to be milliseconds, which is usually inappropriate. If you change the default scanning period, do not forget to specify a time unit.

Behind the scenes, when you set the scan attribute to true, a `TurboFilter` called ReconfigureOnChangeFilter will be installed. TurboFilters are described in a later chapter. As a consequence, scanning is done "in-thread", that is anytime a printing method of logger is invoked. For example, for a logger named `myLogger`, when you write "myLogger.debug("hello");", and if the scan attribute is set to true, then `ReconfigureOnChangeFilter` will be invoked. Moreover, the said filter will be invoked even if `myLogger` is disabled for the debug level.

Given that `ReconfigureOnChangeFilter` is invoked every time any logger is invoked, the filter is performance critical. In order to improve performance, instead of checking whether to scan or not on every logger invocation, `ReconfigureOnChangeFilter` is in reality "alive" only once every 16 logging operations. In short, when a configuration file changes, it will be automatically reloaded after a delay determined by the scanning period and several logger invocations.

### Invoking `JoranConfigurator` directly

Logback relies on a configuration library called Joran which is part of logback-core. Logback's default configuration mechanism invokes `JoranConfigurator` on the default configuration file it finds on the class path. For whatever reason if you wish to override logback's default configuration mechanism, you can do so by invoking `JoranConfigurator` directly. The next application, MyApp3, invokes JoranConfigurator on a configuration file passed as a parameter.

Example 3.: Invoking `JoranConfigurator` directly (logback-examples/src/main/java/chapters/configuration/MyApp3.java)

    package chapters.configuration;

    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 MyApp3 {
      final static Logger logger = LoggerFactory.getLogger(MyApp3.class);

      public static void main(String[] args) {
        // assume SLF4J is bound to logback in the current environment
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

        try {
          JoranConfigurator configurator = new JoranConfigurator();
          configurator.setContext(lc);
          // the context was probably already configured by default configuration
          // rules
          lc.reset();
          configurator.doConfigure(args[0]);
        } catch (JoranException je) {
           je.printStackTrace();
        }
        StatusPrinter.printInCaseOfErrorsOrWarnings(lc);

        logger.info("Entering application.");

        Foo foo = new Foo();
        foo.doIt();
        logger.info("Exiting application.");
      }
    }

This application fetches the `LoggerContext` currently in effect, creates a new `JoranConfigurator`, sets the context on which it will operate, resets the logger context, and then finally asks the configurator to configure the context using configuration file passed as parameter to the application. Internal status data is printed in case of warnings or errors.

### Viewing status messages

Logback collects its internal status data in a `StatusManager` object, accessible via the `LoggerContext`.

Given a `StatusManager` you an access all the status data associated with a logback context. To keep memory usage at reasonable levels, the default `StatusManager` implementation stores the status messages in two separate parts: the header part and the tail part. The header part stores the fist H status messages whereas the tail part stores the last T messages. At present time H=T=150, although these values may change in future releases.

Logback-classic ships with a servlet called ViewStatusMessagesServlet. This servlet prints the contents of the `StatusManager` associated with the current `LoggerContext` as an HTML table. Here is sample output.

To add this servlet to your web-application, add the following lines to its WEB-INF/web.xml file.

      <servlet>
        <servlet-name>ViewStatusMessages</servlet-name>
        <servlet-class>ch.qos.logback.classic.ViewStatusMessagesServlet</servlet-class>
      </servlet>

      <servlet-mapping>
        <servlet-name>ViewStatusMessages</servlet-name>
        <url-pattern>/lbClassicStatus</url-pattern>
      </servlet-mapping>

The `ViewStatusMessages` servlet will viewable under the URL `http://host/yourWebapp/lbClassicStatus`

### Listening to status messages

You may also attach a `StatusListener` to a `StatusManager` so that you can take immediate action in response to status messages, especially to messages occurring after logback configuration. Registering a status listener is a convenient way to supervise logback's internal state without human intervention.

Logback ships with a `StatusListener` implementation called `OnConsoleStatusListener` which, as its name indicates, prints all new incoming status messages on the console.

Here is sample code to register an OnConsoleStatusListener instance with the StatusManager.

       LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
       StatusManager statusManager = lc.getStatusManager();
       OnConsoleStatusListener onConsoleListener = new OnConsoleStatusListener();
       statusManager.add(onConsoleListener);

Note that the registered status listener will receive status events subsequent to its registration. It will not receive prior messages.

It is also possible to register one or more status listeners within a configuration file. Here is an example.

Example 3.: Registering a status listener (logback-examples/src/main/java/chapters/configuration/onConsoleStatusListener.xml)

    <configuration>
      <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />

      ... the rest of the configuration file
    </configuration>

One may also register a status listener by setting the "logback.statusListenerClass" Java system property to the name of the listener class you wish to register. For example,

java -Dlogback.statusListenerClass=ch.qos.logback.core.status.OnConsoleStatusListener ...

## Configuration file Syntax

As you have seen thus far in the manual with plenty of examples still to follow, logback allows you to redefine logging behavior without needing to recompile your code. Indeed, you can easily configure logback so as to disable logging for certain parts of your application, or direct output to a UNIX Syslog daemon, to a database, to a log visualizer, or forward 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.

The remainder of this section presents the syntax of configuration files.

As shall be demonstrated over and over, the syntax of logback configuration files is extremely flexible. As such, it is not possible to specify the allowed syntax with a DTD file or an XML schema. Nevertheless, the very basic structure of the configuration file can be described as, `<configuration>` element, followed by zero or more `<appender>` elements, followed by zero or more `<logger>` elements, followed by at most one `<root>` element. The following diagram illustrates this basic structure.

If you are unsure which case to use for a given tag name, just follow the camelCase convention which is almost always the corrrect convention.

#### Case sensitivity of tag names

As of logback version 0.9.17, tag names pertaining to explicit rules are case insensitive. For example, both `<logger>`, `<Logger>` and `<LOGGER>` are valid configuration elements and will be interpreted in the same way. Note that XML well-formedness rules still apply, if you open a tag as `<xyz>` you must close it as `</xyz>`, `</XyZ>` will not work. As for implicit rules, tag names are case sensitive except for the first letter. Thus, `<xyz>` and `<Xyz>` are equivalent but not `<xYz>`. Implicit rules usually follow the camel case convention, common in the Java world. Since it is not easy tell when a tag is associated with an explicit action and when it is associated with an implicit action, it is not trivial to say whether an XML tag is case-sensitive or insensitive with respect to the first letter. If you are unsure which case to use for a given tag name, just follow the camelCase convention which is almost always the correct convention.

#### Configuring loggers, or the `<logger>` element

At this point should have at least some understanding of level inherirance and the basic selection rule. Otherwise, and unless you are an egyptologist, logback configuration will be no more meaningful to you than are hieroglyphics.

A logger is configured using the `<logger>` element. A `<logger>` element takes exactly one mandatory name attribute, an optional level attribute, and an optional additivity attribute, admitting the values true or false. The value of the level attribute admitting the one of the case-insensitive string values TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF. The special case-insensitive value INHERITED, or its synonym NULL, will force the level of the logger to be inherited from higher up in the hierarchy. This comes in handy in case you set the level of a logger and later decide that it should inherit its level.

The `<logger>` element may contain zero or more `<appender-ref>` 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 `<logger>` 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.

#### Configuring the root logger, or the `<root>` element

The `<root>` element configures the root logger. It admits a single attribute, namely the level attribute. It does not admit any other attributes because the additivity flag does not apply to the root logger. Moreover, since the root logger is already named as "ROOT", it does not admit a name attribute either. The value of the level attribute can be one of the case-insensitive strings TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF. Note that the level of the root logger cannot be set to INHERITED or NULL.

The `<root>` element admits zero or more `<appender-ref>` elements. Similar to the `<logger>` element, declaring a `<root>` 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 the `<root>` element contains no appender references, then the root logger will lose all its appenders.

#### Example

Setting the level of a logger or root 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 DEBUG messages from any component belonging to the "chapters.configuration" package. The following configuration file shows how to achieve that.

Example 3.: Setting the level of a logger (logback-examples/src/main/java/chapters/configuration/sample2.xml)

    <configuration>

      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoders are assigned the type
             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
        <encoder>
          <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
      </appender>

      <logger name="chapters.configuration" level="INFO"/>

      <!-- Strictly speaking, the level attribute is not necessary since -->
      <!-- the level of the root level is set to DEBUG by default.       -->
      <root level="DEBUG">
        <appender-ref ref="STDOUT" />
      </root>

    </configuration>

When the above configuration file is given as argument to the MyApp3 application, it will yield the following output:

    17:34:07.578 [main] INFO  chapters.configuration.MyApp3 - Entering application.
    17:34:07.578 [main] INFO  chapters.configuration.MyApp3 - Exiting application.

Note that the message of level DEBUG generated by the "chapters.configuration.Foo" logger has been supressed. See also the Foo class.

You can configure the levels of as many loggers as you wish. In the next configuration file, we set the level of the chapters.configuration logger to INFO but at the same time set the level of the chapters.configuration.Foo logger to `DEBUG`.

Example 3.: Setting the level of multiple loggers (logback-examples/src/main/java/chapters/configuration/sample3.xml)

    <configuration>

      <appender name="STDOUT"
        class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>
            %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
         </pattern>
        </encoder>
      </appender>

      <logger name="chapters.configuration" level="INFO" />
      <logger name="chapters.configuration.Foo" level="DEBUG" />

      <root level="DEBUG">
        <appender-ref ref="STDOUT" />
      </root>

    </configuration>

Running `MyApp3` with this configuration file will result in the following output on the console:

17:39:27.593 [main] INFO chapters.configuration.MyApp3 - Entering application. 17:39:27.593 [main] DEBUG chapters.configuration.Foo - Did it again! 17:39:27.593 [main] INFO chapters.configuration.MyApp3 - Exiting application.

The table below list the loggers and their levels, after `JoranConfigurator` has configured logback with the sample3.xml configuration file.

Logger name | Assigned Level | Effective Level
--- | --- | ---
root | `DEBUG` | `DEBUG`
chapters.configuration | `INFO` | `INFO`
chapters.configuration.MyApp3 | `null` | `INFO`
chapters.configuration.Foo | `DEBUG` | `DEBUG`

It follows that the two logging statements of level `INFO` in the `MyApp3` class as well as the DEBUG messages in `Foo.doIt()` are all enabled. Note that the level of the root logger is always set to a non-null value, DEBUG by default.

Let us note that the basic-selection rule depends on the effective level of the logger being invoked, not the level of the logger where appenders are attached. Loback will first determine wheteher a logging statement is enabled or not, and if enabled, it will invoke the appenders found in the logger hierarchy, regardless of their level. The configuration file sample4.xml is a case in point:

Example 3.: Logger level sample (logback-examples/src/main/java/chapters/configuration/sample4.xml)

    <configuration>

      <appender name="STDOUT"
       class="ch.qos.logback.core.ConsoleAppender">
       <encoder>
         <pattern>
            %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
          </pattern>
        </encoder>
      </appender>

      <logger name="chapters.configuration" level="INFO" />

      <!-- turn OFF all logging (children can override) -->
      <root level="OFF">
        <appender-ref ref="STDOUT" />
      </root>

    </configuration>

The following table lists the loggers and their levels after applying the sample4.xml configuration file.

Logger name | Assigned Level | Effective Level
--- | --- | ---
root | `OFF` | `OFF`
chapters.configuration | `INFO` | `INFO`
chapters.configuration.MyApp3 | `null` | `INFO`
chapters.configuration.Foo | `null` | `INFO`

The ConsoleAppender named STDOUT, the only configured appender in sample4.xml, is attached to the root logger whose level is set to `OFF`. However, running MyApp3 with configuration script sample4.xml will yield:

    17:52:23.609 [main] INFO chapters.configuration.MyApp3 - Entering application.
    17:52:23.609 [main] INFO chapters.configuration.MyApp3 - Exiting application.

Thus, the level of the root logger has no apparent effect because the loggers in `chapters.configuration.MyApp3` and `chapters.configuration.Foo` classes are all enabled for the `INFO` level. As a side note, the chapters.configuration logger exists by virtue of its declaration in the configuration file - even if the Java source code does not directly refer to it.

#### Configuring Appenders

An appenders is configured with the `<appender>` element, which takes two mandatroy attributes name and class. The name attribute specifies the name of the appender whereas the class attribute specifies the fully qualified name of the appender class to instantiate. The `<appender>` element may contain zero or one `<layout>` elements, zero or more `<encoder>` elements and zero or more `<filter>` elements. Appart from these three common elements, `<appender>` elements may contain any number of elements corresponding to javabean properties of the appender class. Seamlessly supporting any property of a given logback component is one of the major strengths of Joran as discussed in a later chapter. The following diagram illustrates the common structure. Note that support for properties is not visible.

The `<layout>` element takes a mandatory class attribute specifying the fully qualified name of the layout class to instantiate. As with the the `<appender>` element, `<layout>` may contain other elements corresponding to properties of the layout instance. Since it's such a common case, if the layout class is `PatternLayout`, then the class attribute can be omitted as specified by default class mapping rules.

The `<encoder>` element takes a mandatory class attribute specifying the fully qualified name of the encoder class to instantiate. Since it's such a common case, if the encoder class is `PatternLayoutEncoder`, then the class attribute can be omitted as specified by default class mapping rules.

Logging to multiple appenders is as easy as defining the various appenders and referencing them in a logger, as the next configuration file illustrates:

Example 3.: Multiple loggers (logback-examples/src/main/java/chapters/configuration/multiple.xml)

    <configuration>

      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>myApp.log</file>

        <encoder>
          <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
        </encoder>
      </appender>

      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>

      <root level="debug">
        <appender-ref ref="FILE" />
        <appender-ref ref="STDOUT" />
      </root>
    </configuration>

This configuration scripts defines two appenders called FILE and STDOUT. The FILE appender logs to a file called myApp.log. The encoder for this appender is a `PatternLayoutEncoder` 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 `STDOUT` outputs to the console. The encoder for this appender outputs only the message string followed by a line separator.

The appenders are attached to the root logger by referencing them by name within an appender-ref element. Note that each appender has its own encoder. Encoders are usually not designed to be shared by multiple appenders. The same is true for layouts. As such, logback configuration files do not provide any syntactical means for sharing encoders or layouts.

#### Appenders accumulate

By default, appenders are cumulative: 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.

Example 3.: Duplicate appender (logback-examples/src/main/java/chapters/configuration/duplicate.xml)

    <configuration>

      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
      </appender>

      <logger name="chapters.configuration">
        <appender-ref ref="STDOUT" />
      </logger>

      <root level="debug">
        <appender-ref ref="STDOUT" />
      </root>
    </configuration>

Running `MyApp3` with duplicate.xml will yield the following output:

14:25:36.343 [main] INFO chapters.configuration.MyApp3 - Entering application. 14:25:36.343 [main] INFO chapters.configuration.MyApp3 - Entering application. 14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again! 14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again! 14:25:36.359 [main] INFO chapters.configuration.MyApp3 - Exiting application. 14:25:36.359 [main] INFO chapters.configuration.MyApp3 - Exiting application.

Notice the duplicated output. The appender named STDOUT is attached to two loggers, to root and to chapters.configuration. Since the root logger is the ancestor of all loggers and chapters.configuration is the parent of chapters.configuration.MyApp3 and chapters.configuration.Foo, logging request made with these two loggers will be output twice, once because STDOUT is attached to chapters.configuration and once because it is attached to root.

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.

Example 3.: Multiple appender (logback-examples/src/main/java/chapters/configuration/restricted.xml)

    <configuration>

      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>myApp.log</file>
        <encoder>
          <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
        </encoder>
      </appender>

      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>

      <logger name="chapters.configuration">
        <appender-ref ref="FILE" />
      </logger>

      <root level="debug">
        <appender-ref ref="STDOUT" />
      </root>
    </configuration>

In this example, the console appender will log all the messages (for all loggers in the system) whereas only logging request originating from loggers chapters.configuration and below go into the myApp.log file.

#### Overriding the default cumulative behaviour

In case the default cumulative behavior turns out to be unsuitable for your needs, you 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.

Example 3.: Additivity flag (logback-examples/src/main/java/chapters/configuration/additivityFlag.xml)

    <configuration>

      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>foo.log</file>
        <encoder>
          <pattern>%date %level [%thread] %logger{10} [%file : %line] %msg%n</pattern>
        </encoder>
      </appender>

      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>

      <logger name="chapters.configuration.Foo" additivity="false">
        <appender-ref ref="FILE" />
      </logger>

      <root level="debug">
        <appender-ref ref="STDOUT" />
      </root>
    </configuration>

This example, the appender named FILE is attached to the chapters.configuration.Foo logger. Moreover, the chapters.configuration.Foo logger has its additivity flag set to false such that its logging output will be sent to the appender named FILE but not to any appender attached higher in the hierarchy. Other loggers remain oblivious to the additivity setting of the chapters.configuration.Foo logger. Running the `MyApp3` application with the additivityFlag.xml configuration file will output results on the console from the chapters.configuration.MyApp3 logger. However, output from the chapters.configuration.Foo logger will appear in the foo.log file and only in that file.

#### Variable substitution

In principle, variable substitution can occur at any point where a value can be specified. The syntax of variable substitution is similar to that of Unix shells. The string between an opening ${ and closing } is interpreted as a key. The value of the substituted variable can be defined in the configuration file itself, in an external properties file or as a system property. The corresponding value replaces ${aKey} sequence. For example, if java.home.dir system property is set to /home/xyz, then every occurrence of the sequence ${java.home.dir} will be interpreted as /home/xyz. As it often comes in handy, the variable ${HOSTNAME} is automatically defined.

#### properties are inserted into the logger context

Note that the values defined via `<property>` element are actually inserted into the logger context. In other words, they become properties of the logger context. Consequently, they will be available in all logging events as well as remotely after serialization.

The next example shows a variable, a.k.a. a substitution property, declared the beginning of the configuration file. It is then used further down the file to specify the location of the output file.

Example 3.: Simple Variable substitution (logback-examples/src/main/java/chapters/configuration/variableSubstitution1.xml)

    <configuration>

      <property name="USER_HOME" value="/home/sebastien" />

      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${USER_HOME}/myApp.log</file>
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>

      <root level="debug">
        <appender-ref ref="FILE" />
      </root>
    </configuration>

The next example shows the use of a System property to achieve the same result. The property is not declared in the configuration file, thus logback will look for it in the System properties. Java system properties can be set on the command line.

java -DUSER_HOME="/home/sebastien" MyApp2

Example 3.: System Variable substitution (logback-examples/src/main/java/chapters/configuration/variableSubstitution2.xml)

    <configuration>

      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${USER_HOME}/myApp.log</file>
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>

      <root level="debug">
        <appender-ref ref="FILE" />
      </root>
    </configuration>

When multiple variables are needed, it may be more convenient to create a separate file that will contain all the variables. Here is how one can do such a setup.

Example 3.: Variable substitution using a separate file (logback-examples/src/main/java/chapters/configuration/variableSubstitution3.xml)

    <configuration>

      <property file="src/main/java/chapters/configuration/variables1.properties" />

      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
         <file>${USER_HOME}/myApp.log</file>
         <encoder>
           <pattern>%msg%n</pattern>
         </encoder>
       </appender>

       <root level="debug">
         <appender-ref ref="FILE" />
       </root>
    </configuration>

This configuration file contains a reference to a file named variables1.properties. The variables contained in that file will be read defined within the context of the logback configuration file. Here is what the variable.properties file might look like.

Example 3.: Variable file (logback-examples/src/main/java/chapters/configuration/variables1.properties)

    USER_HOME=/home/sebastien

You may also reference a resource on the class path instead of a file.

    <configuration>

      <property resource="resource1.properties" />

      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
         <file>${USER_HOME}/myApp.log</file>
         <encoder>
           <pattern>%msg%n</pattern>
         </encoder>
       </appender>

       <root level="debug">
         <appender-ref ref="FILE" />
       </root>
    </configuration>

#### Nested variable substitution

Nested variabled subsitution is also supported. By nested, we mean that the value definition of a variable contains references to other variables. Suppose you wish to use variables to specify not only the destination directory but also the file name, and combine those two variables in a third variable called "destination". The properties file shown below gives an example.

Example 3.: Nested variable references (logback-examples/src/main/java/chapters/configuration/variables2.properties)

    USER_HOME=/home/sebastien
    fileName=myApp.log
    destination=${USER_HOME}/${fileName}

Note that in the properties file above, "destination" is composed out of two other variables, namely "USER_HOME" and "fileName".

Example 3.: Variable substitution using a separate file (logback-examples/src/main/java/chapters/configuration/variableSubstitution4.xml)

    <configuration>

      <property file="variables2.properties" />

      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${destination}</file>
        <encoder>
          <pattern>%msg%n</pattern>
        </encoder>
      </appender>

      <root level="debug">
        <appender-ref ref="FILE" />
      </root>
    </configuration>

#### Default substitution values for variables

Under certain circumstances, it may be desirable for a variable to have a default value in case it is not declared or its value is null. As in the Bash shell, default values can be specified using the ":-" operator. For example, assuming aKey is not defined, `"${aKey:-golden}"` will be interpreted as "golden".

### File inclusion

Joran supports including parts of a configuration file from another file. This is done by declaring a `<include>` element, as shown below:

Example 3.: File include (logback-examples/src/main/java/chapters/configuration/containingConfig.xml)

    <configuration>
      <include file="src/main/java/chapters/configuration/includedConfig.xml"/>

      <root level="DEBUG">
        <appender-ref ref="includedConsole" />
      </root>

    </configuration>

The target file MUST have its elements nested inside an `<included>` element. For example, a `ConsoleAppender` could be declared as:

Example 3.: File include (logback-examples/src/main/java/chapters/configuration/includedConfig.xml)

    <included>
      <appender name="includedConsole" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>"%d - %m%n"</pattern>
        </encoder>
      </appender>
    </included>

The file to be included can be referenced as a file, as a URL or as a resource. To reference a file use the file attribute. To reference a URL use the url attribute. To reference a resource, use the resource attribute.

### Setting the context name

As mentioned in an earlier chapter, every logger is attached to logger context. By default, the logger context is called "default". However, you can set a different name with the help of the `<contextName>` configuration directive. Note that once set, the logger context name cannot be changed. Setting the context name is a simple and straightforward method in order to distinguish between multiple applications logging to the same target.

Example 3.: Set the context name and display it (logback-examples/src/main/java/chapters/configuration/contextName.xml)

    <configuration>
      <contextName>myAppName</contextName>
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%d %contextName [%t] %level %logger{36} - %msg%n</pattern>
        </encoder>
      </appender>

      <root level="debug">
        <appender-ref ref="STDOUT" />
      </root>
    </configuration>

This last examples illustrates naming of the logger context. Adding the the contextName conversion word in layout's pattern will output the said name.

### Obtaining variables from JNDI

Under certain circumstances, you may want to make use of env-entries stored in JNDI. The `<insertFromJNDI>` configuration directive extracts an env-entry stored in JNDI and inserts it as variable as specified by the as attribute.

Example 3.: Insert as properties env-entries obtained via JNDI (logback-examples/src/main/java/chapters/configuration/insertFromJNDI.xml)

    <configuration>
      <insertFromJNDI env-entry-name="java:comp/env/appName" as="appName" />
      <contextName>${appName}</contextName>

      <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%d %contextName %level %msg %logger{50}%n</pattern>
        </encoder>
      </appender>

      <root level="DEBUG">
        <appender-ref ref="CONSOLE" />
      </root>
    </configuration>

In this last example, the "java:comp/env/appName" env-entry is inserted as the appName property. Note that the `<contextName>` directive sets the context name based on the value of the appName property inserted by the previous `<insertFromJNDI>` directive..