Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apache/tomcat/llms.txt

Use this file to discover all available pages before exploring further.

Tomcat uses JULI (Java Util Logging Infrastructure), an enhanced implementation of java.util.logging, for system and container logs. JULI adds class-loader awareness so that each web application can maintain isolated logging configuration, a critical feature in multi-tenant deployments. Access logging — recording every HTTP request — is handled separately by the AccessLogValve family of valves, which write structured log files independently of the JULI system.

JULI and logging.properties

Tomcat’s JULI layer extends java.util.logging with asynchronous file handlers, per-webapp logger isolation, and class-loader-scoped configuration. The system-level logging configuration lives in conf/logging.properties. The default conf/logging.properties shipped with Tomcat configures four AsyncFileHandler instances (one per internal component) plus a ConsoleHandler:
# conf/logging.properties

handlers = 1catalina.org.apache.juli.AsyncFileHandler, \
           2localhost.org.apache.juli.AsyncFileHandler, \
           3manager.org.apache.juli.AsyncFileHandler, \
           4host-manager.org.apache.juli.AsyncFileHandler, \
           java.util.logging.ConsoleHandler

.handlers = 1catalina.org.apache.juli.AsyncFileHandler, \
            java.util.logging.ConsoleHandler

############################################################
# Handler specific properties.
############################################################

1catalina.org.apache.juli.AsyncFileHandler.level     = ALL
1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.AsyncFileHandler.prefix    = catalina.
1catalina.org.apache.juli.AsyncFileHandler.maxDays   = 90
1catalina.org.apache.juli.AsyncFileHandler.encoding  = UTF-8

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

3manager.org.apache.juli.AsyncFileHandler.level     = ALL
3manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
3manager.org.apache.juli.AsyncFileHandler.prefix    = manager.
3manager.org.apache.juli.AsyncFileHandler.maxDays   = 90
3manager.org.apache.juli.AsyncFileHandler.encoding  = UTF-8

4host-manager.org.apache.juli.AsyncFileHandler.level     = ALL
4host-manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
4host-manager.org.apache.juli.AsyncFileHandler.prefix    = host-manager.
4host-manager.org.apache.juli.AsyncFileHandler.maxDays   = 90
4host-manager.org.apache.juli.AsyncFileHandler.encoding  = UTF-8

java.util.logging.ConsoleHandler.level     = ALL
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
java.util.logging.ConsoleHandler.encoding  = UTF-8

############################################################
# Facility specific properties.
############################################################

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

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level    = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = \
    3manager.org.apache.juli.AsyncFileHandler

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level    = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = \
    4host-manager.org.apache.juli.AsyncFileHandler
Key concepts:
  • Handlers are output destinations. AsyncFileHandler writes to a rotating file; ConsoleHandler writes to stdout.
  • Loggers are named hierarchically by Java class name. The ContainerBase logger names encode the Engine, Host, and context path, allowing per-context log routing.
  • The maxDays property on AsyncFileHandler controls automatic file retention (90 days by default).
  • The numeric prefix on handler names (e.g., 1catalina) is just a naming convention to allow multiple instances of the same handler class.
To enable debug logging for a specific Tomcat subsystem, add a logger entry to conf/logging.properties:
# Debug HTTP/2 handling
org.apache.coyote.http2.level = FINE

# Trace lifecycle state changes for all components
org.apache.catalina.util.LifecycleBase.level = FINE

Log Files

By default, Tomcat writes the following log files to the $CATALINA_BASE/logs/ directory:
FileContents
catalina.outAll console output; startup.sh redirects stdout/stderr here
catalina.YYYY-MM-DD.logCatalina engine log (startup, shutdown, internal errors)
localhost.YYYY-MM-DD.logVirtual host-level events (deployment, context startup errors)
manager.YYYY-MM-DD.logManager application request and audit log
host-manager.YYYY-MM-DD.logHost Manager application log
localhost_access_log.YYYY-MM-DD.txtHTTP access log written by AccessLogValve (default pattern)
catalina.out is not managed by JULI — it is a redirection artifact of the catalina.sh startup script and will grow without bound unless you configure external rotation with logrotate or equivalent.

Per-Application Logging

Each web application can carry its own logging.properties file at WEB-INF/classes/logging.properties. JULI loads this file using the webapp’s ClassLoader, so loggers and handlers defined there are scoped to that application and do not interfere with other applications or with Tomcat’s system loggers. A minimal per-application logging.properties:
# WEB-INF/classes/logging.properties

handlers = org.apache.juli.FileHandler

org.apache.juli.FileHandler.level     = INFO
org.apache.juli.FileHandler.directory = ${catalina.base}/logs
org.apache.juli.FileHandler.prefix    = myapp.

# Set the application root logger level
com.example.myapp.level = INFO
When the application is undeployed, JULI closes and removes all handlers registered under that webapp’s class loader, preventing resource leaks.

AccessLogValve

AccessLogValve (org.apache.catalina.valves.AccessLogValve) records every HTTP request processed by Tomcat in a configurable format. It is configured as a <Valve> child element of <Host> or <Context> in server.xml.

Key Attributes

AttributeDefaultDescription
directorylogsDirectory where log files are written (relative to $CATALINA_BASE)
prefixaccess_logFilename prefix
suffix"" (empty)Filename suffix appended after the date stamp
patterncommonLog format pattern string, or common / combined alias
rotatabletrueRotate the file daily
fileDateFormat.yyyy-MM-ddDate format inserted into the filename on rotation
bufferedtrueBuffer writes for performance; flush on rotation
conditionIfOnly log if this request attribute is set
conditionUnlessSkip logging if this request attribute is set
encodingUTF-8Character encoding for the log file

Pattern Tokens

TokenDescription
%hRemote host name (or IP if DNS lookups are disabled)
%lRemote logical username (always -)
%uRemote authenticated username
%tRequest timestamp in Common Log Format
%rFirst line of the HTTP request
%sHTTP response status code
%bResponse body bytes sent (excluding headers); - if zero
%DRequest processing time in microseconds
%TRequest processing time in seconds
%{Header}iIncoming request header value
%{Header}oOutgoing response header value
%{Cookie}cCookie value
%qQuery string (including leading ?)
%URequest URI path
%vLocal server name
The built-in aliases common and combined expand to standard formats:
common   → %h %l %u %t "%r" %s %b
combined → %h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"

Example Configuration

<!-- Combined log format with microsecond response time (%D) -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
       directory="logs"
       prefix="access_log"
       suffix=".txt"
       pattern="%h %l %u %t &quot;%r&quot; %s %b %D &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot;"
       rotatable="true"
       fileDateFormat=".yyyy-MM-dd"
       buffered="true"/>

Conditional Logging

To skip logging health-check requests (e.g., from a load balancer), use conditionUnless:
<!-- Set the attribute in a Filter, then skip it in access log -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
       pattern="combined"
       conditionUnless="skipAccessLog"/>
In a servlet filter, set request.setAttribute("skipAccessLog", "true") to suppress logging for matched requests.

JSON Access Logging

JsonAccessLogValve (org.apache.catalina.valves.JsonAccessLogValve) extends AccessLogValve and serializes each log entry as a JSON object. This makes log output directly consumable by log aggregation pipelines without a parsing step. Pattern tokens are mapped to JSON field names (e.g., %hhost, %sstatusCode, %DelapsedTime, %{User-Agent}irequestHeaders).
<Valve className="org.apache.catalina.valves.JsonAccessLogValve"
       directory="logs"
       prefix="access_log_json"
       suffix=".log"
       pattern="%h %l %u %t %r %s %b %D %{Referer}i %{User-Agent}i"
       rotatable="true"/>
Example output:
{"host":"192.168.1.10","logicalUserName":"-","user":"-","time":"2024-06-01T12:34:56.789Z","request":"GET /api/users HTTP/1.1","statusCode":200,"size":1482,"elapsedTime":23,"requestHeaders":{"referer":"-","user-agent":"curl/8.4.0"}}
JSON access logs pair naturally with log aggregation platforms such as the Elastic Stack (Filebeat → Elasticsearch → Kibana), Splunk, or Grafana Loki. Each log line is a self-describing document, eliminating the need for Grok patterns or custom parsing rules. Set buffered="false" if you need near-real-time delivery to log shippers.

ExtendedAccessLogValve

ExtendedAccessLogValve (org.apache.catalina.valves.ExtendedAccessLogValve) implements the W3C Extended Log File Format, which adds structured field declarations to the log header and supports a richer set of fields than the Common Log Format. Supported fields include c-dns, c-ip, cs-method, cs-uri, cs-uri-stem, cs-uri-query, sc-status, bytes, time-taken, cs(xxx) (request headers), sc(xxx) (response headers), and x-threadname.
<Valve className="org.apache.catalina.valves.ExtendedAccessLogValve"
       directory="logs"
       prefix="extended_access_log"
       suffix=".log"
       pattern="date time c-ip cs-method cs-uri-stem cs-uri-query sc-status bytes time-taken cs(User-Agent) cs(Referer)"
       rotatable="true"/>
Example output:
#Version: 1.0
#Date: 2024-06-01 12:00:00
#Fields: date time c-ip cs-method cs-uri-stem cs-uri-query sc-status bytes time-taken cs(User-Agent) cs(Referer)
2024-06-01 12:34:56 192.168.1.10 GET /api/users - 200 1482 0.023 curl/8.4.0 -

Log Rotation

Access logs are rotated daily by AccessLogValve based on the fileDateFormat attribute. The current log file is named <prefix><fileDateFormat><suffix> (e.g., access_log.2024-06-01.txt). When rotatable="true", a new file is opened automatically at midnight. For more granular rotation (e.g., hourly), change fileDateFormat:
<Valve className="org.apache.catalina.valves.AccessLogValve"
       fileDateFormat=".yyyy-MM-dd.HH"
       .../>
System logs managed by AsyncFileHandler rotate daily based on the date suffix in the filename. Retention is controlled by maxDays in conf/logging.properties (default: 90 days). Files older than maxDays are deleted automatically. catalina.out does not rotate automatically. On Linux, integrate it with logrotate:
# /etc/logrotate.d/tomcat
/opt/tomcat/logs/catalina.out {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}
The copytruncate directive is important: it copies the file and then truncates the original in-place, rather than renaming it, so Tomcat’s open file descriptor remains valid.

Build docs developers (and LLMs) love