General Middleware

Enable debugging in Apache Tomcat

Tomcat uses JULI logging, by default. Let’s understand the basics of the logging mechanism and how to optimise that to our advantage.

1. What are the available log levels?

Log Levels in the order of least to most verbose
SEVERE
WARNING
INFO
CONFIG
FINE
FINER
FINEST
ALL

To enable debug logging for part of Tomcat internals, you should configure both the appropriate logger(s) and the appropriate handler(s). It is also recommended that debug is enabled for the narrowest possible scope as debug logging can generate large amounts of information.

By default the log files will be kept on the file system forever. This may be changed per handler using the handlerName.maxDays property. If the specified value for the property is 0, then the log files will be kept on the file system forever, otherwise they will be kept the specified maximum days.

A prefix may be added to handler names, so that multiple handlers of a single class may be instantiated. A prefix is a String which starts with a digit, and ends with ‘.’. For example, 22handler.* is a valid prefix.

Consider removing ConsoleHandler from configuration. By default, logging goes both to a FileHandler and to a ConsoleHandler. The output of the latter one is usually captured into a file, such as catalina.out. Thus you end up with two copies of the same messages.

Let’s look at the default log files, tomcat generates and the source for each. We also look at the ${TOMCAT_HOME}/conf/logging.properties file setting to modify the logging behaviour.

2. Standard Out/Err Logging

Tomcat dumps all the standard out/err logs into catalina.out. This file is generated from the startup script catalina.sh from the below code snippet.

if [ -z "$CATALINA_OUT" ] ; then
  CATALINA_OUT="$CATALINA_BASE"/logs/catalina.out
fi

Hence the file is generated, irrespective of other configurations. However, you can disable this standard out/err logging in the logging.properties. Below are the relevant configurations that can do this.

Just remove the java.util.logging.ConsoleHandler from the set of defined handlers. This is disable the catalina.out logging.

handlers = java.util.logging.ConsoleHandler

Also note that the catalina.out is just the std out/err and not the Tomcat logging. There are other files e.g. catalina.* and localhost.* files which actually logs all the detailed events and we can control their behaviour using the logging.properties.

Below section defines the way to enable different log levels.

3. Defining the log levels

To define the log levels, there are several steps that you need to perform in Tomcat. Follow through the below configurations in logging.properties.

Step1. Define all the handlers as a comma separated set of values and assign that to the variable handlers

handlers = 2localhost.org.apache.juli.AsyncFileHandler

Step2. Define the properties of the handler

2localhost.org.apache.juli.AsyncFileHandler.level = FINE
2localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost.
2localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8

Step3. Define the log level of the logger

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = FINE

This is a special way to represent the logger. It follows the below format

org.apache.catalina.core.ContainerBase.[${engine}].[${host}].[${context}]

[Catalina] -> This denotes the Tomcat Engine

[localhost] -> The host on which the Tomcat is running

If the context is not defined, that is considered as a global configuration. Suppose, you want to define a logger that is application to an application with context /myapp, use the below syntax.

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/myapp].level = FINE

Step4. Map the logger to the handler

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler

With the above steps, you should start seeing the FINE logs getting generated in the localhost.* log.

Note: One catch out of all these is that, even if there is no logger to handler mapping in the logging.properties, by default, the logs will go all the defined handlers. You do not necessarily map the logger to a particular handler.

Hence, you can enable a particular logging (e.g. classloaders) with just the below set of statements in logging.properties. Here we skip the Step4.

handlers = 2localhost.org.apache.juli.AsyncFileHandler

2localhost.org.apache.juli.AsyncFileHandler.level = FINE
2localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost.
2localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8

org.apache.catalina.loader.level = FINE

In the above scenario, there is only one handler. But if there are multiple handlers, then the unmapped logger will send the logs to all the handlers, thus duplicating a lot of logs and wasting disk space.

In order to separate the classloader loggings, use the below snippet.

handlers = 2localhost.org.apache.juli.AsyncFileHandler, 3localhost.org.apache.juli.AsyncFileHandler

2localhost.org.apache.juli.AsyncFileHandler.level = FINE
2localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost.
2localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8

3localhost.org.apache.juli.AsyncFileHandler.level = FINE
3localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
3localhost.org.apache.juli.AsyncFileHandler.prefix = localhost_classloader.
3localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8

org.apache.catalina.loader.level = FINE
org.apache.catalina.loader.handlers = 3localhost.org.apache.juli.AsyncFileHandler

In this case, the class loader FINE logging will only go to localhost_classloader.* log, and not the localhost.* log.

4. Which Loggers to enable?

No where in Tomcat documentation, you get a list of loggers to be used for troubleshooting issues. The hard truth is that you need to look it up yourself. All the Tomcat base packages has capability to define the various log levels. Below are few enhanced logging you can use in the logging.properties

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = FINE
org.apache.catalina.startup.level = FINE
org.apache.catalina.session.level = FINE
org.apache.coyote.http2.level = FINE
org.apache.catalina.util.LifecycleBase.level = FINE
org.apache.jasper.compiler.TldLocationsCache.level = FINE
org.apache.tomcat.websocket.level = FINE
org.apache.coyote.level = FINE

To enable SSL debugs, use below java flag.

-Djavax.net.debug=ssl:handshake

Leave a Reply

Your email address will not be published. Required fields are marked *