Tomcat uses JULI logging, by default. Let’s understand the basics of the logging mechanism and how to optimise that to our advantage.
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.
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.
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.
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