Jetty Logo
Contact the core Jetty developers at www.webtide.com

private support for your internal/customer projects ... custom extensions and distributions ... versioned snapshots for indefinite support ... scalability guidance for your apps and Ajax/Comet projects ... development services from 1 day to full product delivery

Example: Centralized Logging with Logback

The term "Centralized Logging" refers to a forced logging configuration for the Jetty Server and all Web Applications that are deployed on the server. Routing all logging events from even the Web Applications down to a single configuration on the Server side.

The example below will present how to accomplish this with Jetty and Slf4j, using Logback to manage the final writing of logs to disk.

The Required JARs

There will be 3 JARs you will need to download

logback-classic-1.0.7.jar

This is the underlying logging framework and adaption layer for Slf4j

logback-core-1.0.7.jar

The common implementation classes for the Logback project.

log4j-over-slf4j-1.6.6.jar

The Slf4j Binding JAR for Log4j

jul-to-slf4j-1.6.6.jar

The Slf4j Binding JAR for java.util.logging

jcl-over-slf4j-1.6.6.jar

The Slf4j Binding JAR for Commons Logging

slf4j-api-1.6.6.jar

This is the basic Slf4j API that Jetty's Slf4jLog implementation uses.

jetty-webapp-logging-9.0.0.jar

Provides a custom Deployment Lifecycle Binding to force Web Applications to use Server side logging implementations. See github.com/jetty-project/jetty-webapp-logging for source.

This will allow to capture Logging events generated by any of the following APIs.

Any logging event from those APIs will now route down into Logback Classic to work with.

Configuring Server Classpath

In order for the Server to use these new JARs you will need to put them into place and tell Jetty to load them on each startup.

Create a ${jetty.home}/lib/logging/ directory and place the 7 files you downloaded there.

[jetty-distribution-9.0.0.v20130308]$ ls -l lib/logging/
total 632
-rw-rw-r-- 1 jetty jetty  17289 Mar 12 16:21 jcl-over-slf4j-1.6.6.jar
-rw-rw-r-- 1 jetty jetty   6221 Mar 12 16:21 jetty-webapp-logging-9.0.0.jar
-rw-rw-r-- 1 jetty jetty   4955 Mar 12 16:21 jul-to-slf4j-1.6.6.jar
-rw-rw-r-- 1 jetty jetty  20647 Mar 12 16:21 log4j-over-slf4j-1.6.6.jar
-rw-rw-r-- 1 jetty jetty 251679 Mar 12 16:21 logback-classic-1.0.7.jar
-rw-rw-r-- 1 jetty jetty 364399 Mar 12 16:21 logback-core-1.0.7.jar
-rw-rw-r-- 1 jetty jetty  26176 Mar 12 16:21 slf4j-api-1.6.6.jar

Next, we need to edit the ${jetty.home}/start.ini to get jetty to load these logging files into the Server classpath.

Edit the start.ini and check for the following entries. (Add them to the end if missing)

# Force Server side Logging APIs
etc/jetty-webapp-logging.xml
# Enable jul-to-slf4j layer
etc/jetty-jul-to-slf4j.xml
# Adding lib/logging to server classpath
OPTIONS=logging

Now verify that the 7 jars will be loaded by server classpath

[jetty-distribution-9.0.0.v20130308]$ java -jar start.jar --version | grep logging
Active Options: [Server, client, ext, jmx, jsp, logging, resources, websocket]
18:                1.6.6 | ${jetty.home}/lib/logging/jcl-over-slf4j-1.6.6.jar
19:                9.0.0 | ${jetty.home}/lib/logging/jetty-webapp-logging-9.0.0.jar
20:                1.6.6 | ${jetty.home}/lib/logging/jul-to-slf4j-1.6.6.jar
21:                1.6.6 | ${jetty.home}/lib/logging/log4j-over-slf4j-1.6.6.jar
22:                1.0.7 | ${jetty.home}/lib/logging/logback-classic-1.0.7.jar
23:                1.0.7 | ${jetty.home}/lib/logging/logback-core-1.0.7.jar
24:                1.6.6 | ${jetty.home}/lib/logging/slf4j-api-1.6.6.jar

Configuring Server Logging

If you have a ${jetty.home}/resources/jetty-logging.properties, make sure it contains just the following

# Configure Jetty for SLf4j Logging
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog

This will tell Jetty to use the Slf4jLog implementation for its internal Logging.

Forcing Server Logging APIs on Web Applications

In order to force all deployed Web Applications to use the Server side implementations for the various Logging APIs, we will utilize a custom Deployment Lifecycle Binding to configure the Web Application Classloader appropriately.

A custom Deployment Lifecycle Binding for this precise purpose is provided as part of the jetty-webapp-logging.jar.

The implementation for the CentralizedWebAppLoggingBinding class found in the jetty-webapp-logging.jar.

package org.eclipse.jetty.webapp.logging;

import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppLifeCycle;
import org.eclipse.jetty.deploy.graph.Node;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.webapp.WebAppContext;

public class CentralizedWebAppLoggingBinding implements AppLifeCycle.Binding
{
    public String[] getBindingTargets()
    {
        return new String[]
        { "deploying" };
    }

    public void processBinding(Node node, App app) throws Exception
    {
        ContextHandler handler = app.getContextHandler();
        if (handler == null)
        {
            throw new NullPointerException("No Handler created for App: " + app);
        }

        if (handler instanceof WebAppContext)
        {
            WebAppContext webapp = (WebAppContext)handler;
            webapp.addSystemClass("org.apache.log4j.");
            webapp.addSystemClass("org.slf4j.");
            webapp.addSystemClass("org.apache.commons.logging.");
        }
    }
}

In order for Jetty's DeploymentManager to utilize this class, we'll need create the etc/jetty-webapp-logging.xml file (the same one that is referenced above in the start.ini)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">

<!-- =============================================================== -->
<!-- Enable Centralized Logging in the Jetty Server                  -->
<!-- =============================================================== -->

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  <Ref refid="DeploymentManager">
    <Call name="addLifeCycleBinding">
      <Arg>
        <New class="org.eclipse.jetty.webapp.logging.CentralizedWebAppLoggingBinding">
        </New>
      </Arg>
    </Call>
  </Ref>
</Configure>

The configuration of the start.ini above will use this xml file.

Initializing Jul-to-Slf4j Bridge

There is an extra requirement when using the jul-to-slf4j.jar that requires us to inform java.util.logging of the existence of the SLF4JBridgeHandler.

We'll satisfy this requirement with a new etc/jetty-jul-to-slf4j.xml file, lovingly included in the start.ini above.

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  <Call class="org.slf4j.bridge.SLF4JBridgeHandler" name="removeHandlersForRootLogger"/>
  <Call class="org.slf4j.bridge.SLF4JBridgeHandler" name="install"/>
</Configure>

Configuring Logback

You'll need a ${jetty.home}/resources/logback.xml file to define what you want Logback to do. It will be automatically located and loaded on Logging startup.

Example ${jetty.home}/resources/logback.xml file

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
  Example LOGBACK Configuration File
  http://logback.qos.ch/manual/configuration.html
  -->
<configuration>
  <!-- address performance concern with jul-to-slf4j -->
  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
    <resetJUL>true</resetJUL>
  </contextListener>

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

  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>\${jetty.home}/logs/jetty.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>jetty_%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>

    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

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

Note

When using the jul-to-slf4j Binding JAR, be sure you also utilize the LevelChangePropagator (as referenced in the SLF4JBridgeHandler javadoc.

Verify start.ini configuration

Before you start Jetty, lets verify that our start.ini is correctly setup.

Run the following command and check the last section of the output. It should contain the highlighted entries.

[jetty-distribution-9.0.0.v20130308]$ java -jar start.jar --help
...
  The current start.ini arguments are:

    OPTIONS=Server,websocket,resources,ext
    etc/jetty.xml
    OPTIONS=client
    etc/test-realm.xml
    OPTIONS=jmx
    etc/jetty-jmx.xml
    OPTIONS=jsp
    etc/jetty-http.xml
    etc/jetty-deploy.xml
    etc/jetty-requestlog.xml
    etc/jetty-webapp-logging.xml
    etc/jetty-jul-to-slf4j.xml
    OPTIONS=logging

You are done.

Start Jetty

You are now done configuring Jetty for all logging APIs. Just start Jetty to start utilizing it.

[jetty-distribution-9.0.0.v20130308]$ java -jar start.jar 

Note

This configuration will capture all Server side logging events and route them to the console and logging file handled by Logback. If you also want to capture all of the Web Application logging events, be sure to read Example: Centralized Logging with Logback for details.

See an error or something missing? Contribute to this documentation at Github!