Tomcat JULI to Log4j API bridge

Tomcat uses an internal logging API called Tomcat JULI. The Tomcat JULI to Log4j API bridge contains an implementation of Tomcat JULI, which forwards all log events to Log4j API.

Installation

To install the bridge, you need to:

  1. Create a $CATALINA_BASE/bin/logging folder and add the following content:

  2. Create an empty $CATALINA_BASE/conf/logging folder for the configuration files of the logging backend.

  3. Add the libraries to Tomcat’s CLASSPATH environment variable:

    UNIX

    On a UNIX system, create a $CATALINA_BASE/bin/setenv.sh files with the following content:

    #!/bin/sh
    ##
    # Add the additional libraries
    CLASSPATH="$CLASSPATH:$CATALINA_BASE/bin/logging/*"
    ##
    # Add a folder for the logging configuration
    CLASSPATH="$CLASSPATH:$CATALINA_BASE/conf/logging/"
    Windows

    Windows users start the Tomcat Monitor application, e.g. $CATALINA_HOME/bin/tomcat10w.exe and add the libraries to "Java Classpath" configuration entry in the "Java" tab.

Click here for a definition of CATALINA_BASE and CATALINA_HOME

A Tomcat installation can be split in two separate folders:

CATALINA_HOME

This is the folder that contains the code of the server and the default configuration of Tomcat instances.

CATALINA_BASE

This is the folder that contains the runtime configuration and working directories of a specific Tomcat instance.

The typical location of these folders varies between OSes:

Debian

On Debian and derived GNU/Linux distributions CATALINA_BASE is located in the /var/lib folder (e.g. /var/lib/tomcat10). CATALINA_HOME on the other hand is located in /usr/share (e.g. /usr/share/tomcat10).

Windows

If you installed Tomcat from the MSI package, both CATALINA_BASE and CATALINA_HOME point to the same subfolder of C:\Program Files\Apache Software Foundation, e.g. C:\Program Files\Apache Software Foundation/Tomcat 10.1.

Configuration

You need to configure the logging implementation of your choice.

Log4j Core Configuration

If you use Log4j Core as logging implementation, and you wish to keep the standard Tomcat log files, create a $CATALINA_BASE/conf/logging/log4j2.xml file like the one below:

  • XML

  • JSON

  • YAML

Example log4j2.xml file equivalent to Tomcat’s standard configuration
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="https://logging.apache.org/xml/ns"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="
                   https://logging.apache.org/xml/ns
                   https://logging.apache.org/xml/ns/log4j-config-2.xsd">
  <Properties>
    <Property name="logs.dir" value="${sys:catalina.base}/logs"/>
    <Property name="one.line.pattern" value="%d{dd-MMM-yyyy HH:mm:ss.SSS} %p [%t] %C.%M %m%n"/>
  </Properties>
  <Appenders>
    <RollingFile name="catalina"
                 filePattern="${logs.dir}/catalina.%d{yyyy-MM-dd}.log">
      <PatternLayout pattern="${one.line.pattern}"/>
      <DirectWriteRolloverStrategy>
        <Delete basePath="${logs.dir}">
          <IfFileName regex="catalina\.\d{4}-\d{2}-\d{2}\.log"/>
          <IfLastModified age="P90D"/>
        </Delete>
      </DirectWriteRolloverStrategy>
      <TimeBasedTriggeringPolicy/>
    </RollingFile>
    <RollingFile name="localhost"
                 filePattern="${logs.dir}/localhost.%d{yyyy-MM-dd}.log">
      <PatternLayout pattern="${one.line.pattern}"/>
      <DirectWriteRolloverStrategy>
        <Delete basePath="${logs.dir}">
          <IfFileName regex="catalina\.\d{4}-\d{2}-\d{2}\.log"/>
          <IfLastModified age="P90D"/>
        </Delete>
      </DirectWriteRolloverStrategy>
      <TimeBasedTriggeringPolicy/>
    </RollingFile>
    <RollingFile name="manager"
                 filePattern="${logs.dir}/manager.%d{yyyy-MM-dd}.log">
      <PatternLayout pattern="${one.line.pattern}"/>
      <DirectWriteRolloverStrategy>
        <Delete basePath="${logs.dir}">
          <IfFileName regex="catalina\.\d{4}-\d{2}-\d{2}\.log"/>
          <IfLastModified age="P90D"/>
        </Delete>
      </DirectWriteRolloverStrategy>
      <TimeBasedTriggeringPolicy/>
    </RollingFile>
    <RollingFile name="host-manager"
                 filePattern="${logs.dir}/host-manager.%d{yyyy-MM-dd}.log">
      <PatternLayout pattern="${one.line.pattern}"/>
      <DirectWriteRolloverStrategy>
        <Delete basePath="${logs.dir}">
          <IfFileName regex="catalina\.\d{4}-\d{2}-\d{2}\.log"/>
          <IfLastModified age="P90D"/>
        </Delete>
      </DirectWriteRolloverStrategy>
      <TimeBasedTriggeringPolicy/>
    </RollingFile>
    <Console name="console"
             target="SYSTEM_ERR">
      <PatternLayout pattern="${one.line.pattern}"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="INFO">
      <AppenderRef ref="catalina"/>
      <AppenderRef ref="console"/>
    </Root>
    <Logger name="org.apache.catalina.core.ContainerBase.[Catalina].[localhost]"
            additivity="false">
      <AppenderRef ref="localhost"/>
    </Logger>
    <Logger name="org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]"
            additivity="false">
      <AppenderRef ref="manager"/>
    </Logger>
    <Logger name="org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]"
            additivity="false">
      <AppenderRef ref="host-manager"/>
    </Logger>
  </Loggers>
</Configuration>
Example log4j2.json file equivalent to Tomcat’s standard configuration
{
  "Configuration": {
    "Properties": {
      "Property": [
        {
          "name": "logs.dir",
          "value": "${sys:catalina.base}/logs"
        },
        {
          "name": "one.line.pattern",
          "value": "%d{dd-MMM-yyyy HH:mm:ss.SSS} %p [%t] %C.%M %m%n"
        }
      ]
    },
    "Appenders": {
      "RollingFile": [
        {
          "name": "catalina",
          "filePattern": "${logs.dir}/catalina.%d{yyyy-MM-dd}.log",
          "PatternLayout": {
            "pattern": "${one.line.pattern}"
          },
          "DirectWriteRolloverStrategy": {
            "Delete": {
              "basePath": "${logs.dir}",
              "IfFileName": {
                "regex": "catalina\\.\\d{4}-\\d{2}-\\d{2}\\.log"
              },
              "IfLastModified": {
                "age": "P90D"
              }
            }
          },
          "TimeBasedTriggeringPolicy": {}
        },
        {
          "name": "localhost",
          "filePattern": "${logs.dir}/localhost.%d{yyyy-MM-dd}.log",
          "PatternLayout": {
            "pattern": "${one.line.pattern}"
          },
          "DirectWriteRolloverStrategy": {
            "Delete": {
              "basePath": "${logs.dir}",
              "IfFileName": {
                "regex": "localhost\\.\\d{4}-\\d{2}-\\d{2}\\.log"
              },
              "IfLastModified": {
                "age": "P90D"
              }
            }
          },
          "TimeBasedTriggeringPolicy": {}
        },
        {
          "name": "manager",
          "filePattern": "${logs.dir}/manager.%d{yyyy-MM-dd}.log",
          "PatternLayout": {
            "pattern": "${one.line.pattern}"
          },
          "DirectWriteRolloverStrategy": {
            "Delete": {
              "basePath": "${logs.dir}",
              "IfFileName": {
                "regex": "manager\\.\\d{4}-\\d{2}-\\d{2}\\.log"
              },
              "IfLastModified": {
                "age": "P90D"
              }
            }
          },
          "TimeBasedTriggeringPolicy": {}
        },
        {
          "name": "host-manager",
          "filePattern": "${logs.dir}/host-manager.%d{yyyy-MM-dd}.log",
          "PatternLayout": {
            "pattern": "${one.line.pattern}"
          },
          "DirectWriteRolloverStrategy": {
            "Delete": {
              "basePath": "${logs.dir}",
              "IfFileName": {
                "regex": "host-manager\\.\\d{4}-\\d{2}-\\d{2}\\.log"
              },
              "IfLastModified": {
                "age": "P90D"
              }
            }
          },
          "TimeBasedTriggeringPolicy": {}
        }
      ],
      "Console": {
        "name": "console",
        "target": "SYSTEM_ERR",
        "PatternLayout": {
          "pattern": "${one.line.pattern}"
        }
      }
    },
    "Loggers": {
      "Root": {
        "level": "INFO",
        "AppenderRef": [
          {
            "ref": "catalina"
          },
          {
            "ref": "console"
          }
        ]
      },
      "Logger": [
        {
          "name": "org.apache.catalina.core.ContainerBase.[Catalina].[localhost]",
          "additivity": false,
          "AppenderRef": {
            "ref": "localhost"
          }
        },
        {
          "name": "org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]",
          "additivity": false,
          "AppenderRef": {
            "ref": "manager"
          }
        },
        {
          "name": "org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]",
          "additivity": false,
          "AppenderRef": {
            "ref": "host-manager"
          }
        }
      ]
    }
  }
}
Example log4j2.yaml file equivalent to Tomcat’s standard configuration
Configuration:
  Properties:
    Property:
      - name: "logs.dir"
        value: "${sys:catalina.base}/logs"
      - name: "one.line.pattern"
        value: "%d{dd-MMM-yyyy HH:mm:ss.SSS} %p [%t] %C.%M %m%n"
  Appenders:
    RollingFile:
      - name: "catalina"
        filePattern: "${logs.dir}/catalina.%d{yyyy-MM-dd}.log"
        PatternLayout:
          pattern: "${one.line.pattern}"
        DirectWriteRolloverStrategy:
          Delete:
            basePath: "${logs.dir}"
            IfFileName:
              regex: "catalina\.\d{4}-\d{2}-\d{2}\.log"
            IfLastModified:
              age: "P90D"
        TimeBasedTriggeringPolicy: { }
      - name: "localhost"
        filePattern: "${logs.dir}/localhost.%d{yyyy-MM-dd}.log"
        PatternLayout:
          pattern: "${one.line.pattern}"
        DirectWriteRolloverStrategy:
          Delete:
            basePath: "${logs.dir}"
            IfFileName:
              regex: "localhost\.\d{4}-\d{2}-\d{2}\.log"
            IfLastModified:
              age: "P90D"
        TimeBasedTriggeringPolicy: { }
      - name: "manager"
        filePattern: "${logs.dir}/manager.%d{yyyy-MM-dd}.log"
        PatternLayout:
          pattern: "${one.line.pattern}"
        DirectWriteRolloverStrategy:
          Delete:
            basePath: "${logs.dir}"
            IfFileName:
              regex: "manager\.\d{4}-\d{2}-\d{2}\.log"
            IfLastModified:
              age: "P90D"
        TimeBasedTriggeringPolicy: { }
      - name: "host-manager"
        filePattern: "${logs.dir}/host-manager.%d{yyyy-MM-dd}.log"
        PatternLayout:
          pattern: "${one.line.pattern}"
        DirectWriteRolloverStrategy:
          Delete:
            basePath: "${logs.dir}"
            IfFileName:
              regex: "host-manager\.\d{4}-\d{2}-\d{2}\.log"
            IfLastModified:
              age: "P90D"
        TimeBasedTriggeringPolicy: { }
    Console:
      name: "console"
      target: "SYSTEM_ERR"
      PatternLayout:
        pattern: "${one.line.pattern}"
  Loggers:
    Root:
      level: "INFO"
      AppenderRef:
        - ref: "catalina"
        - ref: "console"
    Logger:
      - name: "org.apache.catalina.core.ContainerBase.[Catalina].[localhost]"
        additivity: false
        AppenderRef:
          ref: "localhost"
      - name: "org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]"
        additivity: false
        AppenderRef:
          ref: "manager"
      - name: "org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]"
        additivity: false
        AppenderRef:
          ref: "host-manager"