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

Manual ยท Configuration

Configuration of logback

We start by presenting ways for configuring logback, with many example configuration scripts. Joran, the configuration framework upon which logback relies will be presented in a later chapter.

Configuration at initialization

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 programmatically or via a configuration script written in XML, Groovy, or as a serialized model. Existing log4j users can convert their log4j.properties files to logback.xml using the properties translator web application.

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

  1. Logback will search for any custom Configurator providers using service-provider loading facility. If any such custom provider is found, it takes precedence over logback's own configurators, e.g. DefaultJoranConfigurator (see below).

    A custom Configurator is an implementation of ch.qos.logback.​classic.spi.​Configurator interface. Custom configurators are searched by looking up file resources located under META-INF/services/​ch.qos.logback.​classic.spi.​Configurator. The contents of this file should specify the fully qualified class name of the desired Configurator implementation.

  2. Nominal step If the previous configurators could not locate their required resources, then an instance of DefaultJoranConfigurator will be created and invoked.

    • If the system property "logback.configurationFile" is set, then DefaultJoranConfigurator will try to locate the file specified by the aforementioned system property. If this file can be located, it will be read and interpreted for configuration.

    • If the previous step fails, DefaultJoranConfigurator will try to locate the configuration file "logback-test.xml" on the classpath. If this file can be located, it will be read and interpreted for configuration.

    • If no such file is found, it will try to locate the configuration file "logback.xml" in the classpath. If this file can be located, it will be read and interpreted for configuration. Note that this is the nominal configuration step.

    since 1.5.8 PropertiesConfigurator, introduced in version 1.5.8, allows for setting logger levels via a properties file. The location of properties files can be specified as a file path as well as a URL via HTTP or HTTPS protocols. Watching files and reconfiguration upon change is also supported. Note that configuration files in properties format are intended to be part of a main configuration file in XML format or a configurator produced by logback-tyler.

    • If no configuration file could be located, DefaultJoranConfigurator will return with an execution status asking for the next available configurator, i.e. BasicConfigurator, to be invoked.

  3. If none of the above succeeds, logback-classic will configure itself using the BasicConfigurator which will cause logging output to be directed to the console.

The last step is meant as a last-ditch effort to provide a default (but very basic) logging functionality in the absence of a configuration file.

If you are using a build tool according to Maven's folder structure, then if you place the logback-test.xml under the 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.

Fast start-up It takes about 100 milliseconds for Joran to parse a given logback configuration file. To shave off those milliseconds at application start up, you can use the service-provider loading facility (item 1 above) to load your own custom Configurator class with BasicConfigurator serving as a good starting point. Better yet, converting an XML file to Java using TylerConfigurator is a quick and quite convenient way of improving configuration times.

Groovy Given that Groovy is a full-fledged language, we have dropped support for logback.groovy in order to protect against potential attacks. Fortunately, groovy support was picked up at virtualdogbert/logback-groovy-config by Tucker Pelletier.

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: Simple example of BasicConfigurator usage (logback-examples/​src/main/​java/chapters/​configuration/MyApp1.java)

package chapters.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: 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} -%kvp- %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 for 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 to 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. Since SLF4J permits the use of any logging framework under its abstraction layer, it is easy to migrate large bodies of code from one logging framework to another.

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: Basic configuration file (logback-examples/​src/main/resources/​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} -%kvp- %msg%n</pattern>
    </encoder>
  </appender>

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

Requires a server call.

Requires a server call.

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 warnings or errors

When warnings or errors occur while parsing the configuration file, Logback prints its internal status messages to the console to aid diagnosis.

If warnings or errors occur during the parsing of the configuration file, logback will automatically print its internal status data on the console. Note that to avoid duplication, automatic status printing is disabled if the user explicitly registers a status listener (discussed below).

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 for the addition of two lines of code for printing internal status data.

Example: 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 logback's internal messages, a.k.a. Status objects, which allow convenient access to logback's internal state.

Status data

Enabling status output is often helpful when diagnosing issues with Logback.

Errors can also occur after configuration, for example when a disk is full or log files cannot be archived due to wrong permissions. Registering a StatusListener is recommended; it receives status events as they occur and facilitates troubleshooting.

The next example illustrates the installation of OnConsoleStatusListener.

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

<configuration>
   <!-- Recommendation: place status listeners towards the the top of the configuration file -->
   <statusListener class="ch.qos.logback.​core.status.OnConsoleStatusListener" />

   <!-- ... the rest of the configuration file -->

</configuration>

Requires a server call.

Requires a server call.

A StatusListener can be installed using a configuration file assuming 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 the configuration file and in particular the <statusListener> element. If the configuration file is found but is malformed, then logback will detect the error condition and automatically print its internal status on the console. However, if the configuration file cannot be found, logback will not automatically print its status data, since this is not necessarily an error condition. Programmatically invoking StatusPrinter.print() as shown in the MyApp2 application above ensures that status information is printed in every case.

Forcing status output In the absence of status messages, tracking down a rogue logback.xml configuration file can be difficult, especially in production where the application source cannot be easily modified. To help identify the location of a rogue configuration file, you can set a StatusListener via the "logback.statusListenerClass" system property (discussed below) to force output of status messages. The "logback.statusListenerClass" system property can also be used to silence output automatically generated in case of errors.

Shorthand

As a shorthand, it is possible to register an OnConsoleStatusListener by setting the debug attribute to true within the <configuration> element, as shown below.

Example: Basic configuration file using debug mode (logback-examples/​src/main/resources/​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} -%kvp- %msg%n</pattern>
    </encoder>
  </appender>

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

Requires a server call.

Requires a server call.

By the way, setting debug="true" is strictly equivalent to installing an OnConsoleStatusListener as shown previously.

"logback.statusListenerClass" system property

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 .​...

As a shorthand, the string "ch.qos.logback.​core.status.OnConsoleStatusListener" can be replaced by the case insensitive strings "STDOUT" or "SYSOUT". For example:

java -Dlogback.statusListenerClass=stdout ...

or equivalently:

java -Dlogback.statusListenerClass=sysout ...

Other StatusListener implementations

Logback ships with several status listener implementations. OnConsoleStatusListener prints incoming status messages on the console, i.e. on System.out. OnErrorConsoleStatusListener prints incoming status messages on System.err. NopStatusListener drops incoming status messages.

Note that automatic status printing (in case of errors) is disabled if any status listener is registered during configuration and in particular if the user specifies a status listener via the "logback.statusListenerClass" system property. Thus, by setting NopStatusListener as a status listener, you can silence internal status printing altogether.

java -Dlogback.statusListenerClass=ch.qos.logback.​core.status.NopStatusListener .​..

Viewing status messages

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

Given a StatusManager you can 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 first 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.

click to enlarge

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 be viewable at the URL http://host/yourWebapp/lbClassicStatus

Listening to status messages via code

You may also register a StatusListener via Java code. Here is sample code.

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

Note that the registered status listener will only receive status events subsequent to its registration. It will not receive prior messages. Thus, it is usually a good idea to place status listener registration directives at the top of the configuration file before other directives.

Setting the location of the configuration file via a system property

You may specify the location of the default configuration file with a system property named "logback.configurationFile". The value of 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

Note that the file extension must be ".xml" or ".groovy". Other extensions are ignored. Explicitly registering a status listener may help debugging issues with locating the configuration file.

Given that "logback.configurationFile" is a Java system property, it may be set within your application as well. However, the system property must be set before any logger instance is created.

import ch.qos.logback.classic.util.ContextInitializer;

public class ServerMain {
    public static void main(String args[]) throws IOException, InterruptedException {
       // must be set before the first call to  LoggerFactory.getLogger();
       // ContextInitializer.CONFIG_FILE_PROPERTY is set to "logback.configurationFile"
       System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, "/path/to/config.xml");
       ...
    }
}

Automatically reloading configuration file upon modification

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

If instructed to do so, logback-classic will scan for changes in its configuration file and automatically reconfigure itself when the 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 attribute of the <configuration> element to true, as shown next.

Example: Scanning for changes in configuration file and automatic re-configuration (logback-examples/​src/main/resources/​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: Specifying a different scanning period (logback-examples/​src/main/resources/​chapters/configuration/​scan2.xml)

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

Note 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 ReconfigureOnChangeTask will be installed. This task run in a separate thread and will check whether your configuration file has changed. ReconfigureOnChangeTask will automatically watch for any included files as well.

As it is easy to make errors while editing a configuration file, in case the latest version of the configuration file has XML syntax errors, it will fall back to a previous configuration file free of XML syntax errors.

Since 1.5.9 It is possible to watch for modifications in configuration files in properties format. See PropertiesConfigurator for further details.

Enabling packaging data in stack traces

While useful, packaging data is expensive to compute, especially in applications that frequently throw exceptions.

NOTE As of version 1.1.4, packaging data is disabled by default.

If instructed to do so, logback can include packaging data for each stack trace line it outputs. Packaging data consists of the name and version of the jar file whence the class of the stack trace line originated. Packaging data can be very useful in identifying software versioning issues. However, it is rather expensive to compute, especially in applications where exceptions are thrown frequently. Here is a sample output:

14:28:48.835 [btpool0-7] INFO  c.q.l.demo.prime.PrimeAction - 99 is not a valid value
java.lang.Exception: 99 is invalid
  at ch.qos.logback.demo.prime.PrimeAction.execute(PrimeAction.java:28) [classes/:na]
  at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431) [struts-1.2.9.jar:1.2.9]
  at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236) [struts-1.2.9.jar:1.2.9]
  at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432) [struts-1.2.9.jar:1.2.9]
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) [servlet-api-2.5-6.1.12.jar:6.1.12]
  at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502) [jetty-6.1.12.jar:6.1.12]
  at ch.qos.logback.demo.UserServletFilter.doFilter(UserServletFilter.java:44) [classes/:na]
  at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115) [jetty-6.1.12.jar:6.1.12]
  at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361) [jetty-6.1.12.jar:6.1.12]
  at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417) [jetty-6.1.12.jar:6.1.12]
  at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) [jetty-6.1.12.jar:6.1.12]

Packaging data is disabled by default but can be enabled by configuration:

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

Alternatively, packaging data can be enabled/disabled programmatically by invoking the setPackagingDataEnabled(boolean) method in LoggerContext, as shown next:

  LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
  lc.setPackagingDataEnabled(true);

Invoking JoranConfigurator directly

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

Example: 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 context = (LoggerContext) LoggerFactory.getILoggerFactory();

    try {
      JoranConfigurator configurator = new JoranConfigurator();
      configurator.setContext(context);
      // Call context.reset() to clear any previous configuration, e.g. default
      // configuration. For multi-step configuration, omit calling context.reset().
      context.reset();
      configurator.doConfigure(args[0]);
    } catch (JoranException je) {
      // StatusPrinter will handle this
    }
    StatusPrinter.printInCaseOfErrorsOrWarnings(context);

    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 the configuration file passed as a parameter to the application. Internal status data is printed in case of warnings or errors. Note that for multi-step configuration, context.reset() invocation should be omitted.

Stopping logback-classic

In order to release the resources used by logback-classic, it is always a good idea to stop the logback context. Stopping the context will close all appenders attached to loggers defined by the context and stop any active threads in an orderly way. Please also read the section on "shutdown hooks" just below.


import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
...

// assume SLF4J is bound to logback-classic in the current environment
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
loggerContext.stop();

In web-applications the above code could be invoked from within the contextDestroyed method of Servlet​ContextListener in order to stop logback-classic and release resources. Starting with version 1.1.10, the appropriate ServletContextListener is installed automatically for you (see just below).

Stopping logback-classic via a shutdown hook

Installing a JVM shutdown hook is a convenient way for shutting down logback and releasing associated resources.

<configuration debug="true"> <!-- in the absence
   of the class attribute, assume
   ch.qos.logback.core.hook.DefaultShutdownHook -->
   <shutdownHook/>

   <!-- rest of the config file.. -->

</configuration>

Requires a server call.

Requires a server call.

Note that you may install a shutdown hook of your own making by setting the class attribute to correspond to your shutdown hook's class name.

The default shutdown hook, namely DefaultShutdownHook, will stop the logback context after a specified delay (0 by default). Stopping the context will allow up to 30 seconds for any log file compression tasks running in the background to finish. In standalone Java applications, adding a <shutdownHook/> directive to your configuration file is an easy way to ensure that any ongoing compression tasks are allowed to finish before JVM exit. In applications within a Web server, webShutdownHook will be installed automatically making <shutdownHook/> directive quite redundant and unnecessary.

As of version 1.5.7, installing a shutdown hook replaces any previously installed hook. Therefore, at most one Logback shutdown hook can be installed via the usual logback.xml configuration.

WebShutdownHook or stopping logback-classic in web-applications

since 1.1.10 Logback-classic will automatically ask the web-server to install a LogbackServlet​ContainerInitializer implementing the ServletContainer​Initializer interface (available in servlet-api 3.x and later). This initializer will in turn install an instance of LogbackServlet​ContextListener.w This listener will stop the current logback-classic context when the web-app is stopped or reloaded.

You may disable automatic installation of LogbackServletContextListener by setting a <context-param> named logbackDisableServletContainerInitializer in your web application's WEB-INF/web.xml. Here is the relevant snippet.

<web-app>
    <context-param>
        <param-name>logbackDisableServletContainerInitializer</param-name>
        <param-value>true</param-value>
    </context-param>
    ....
</web-app>

Note that logbackDisableServlet​ContainerInitializer variable can also be set as a Java system property or an OS environment variable. The most local setting has priority, i.e. web-app first, system property second and OS environment last.

Configuration topics