Logging and Access Log

Introduction

When Tomcat fails to start or returns 500, the answer is usually in logs/. When you need to know who hit which URL, you enable AccessLogValve—Tomcat’s request access log, similar to Nginx access.log. This chapter maps log files, tunes logging.properties, configures access logging, and shows tail workflows for deploy verification.

Prerequisites

Log Files Overview

File (typical)Contents
catalina.yyyy-mm-dd.logContainer startup, shutdown, deploy/undeploy, severe errors
catalina.outSometimes stdout/stderr redirect (depends on how you start Tomcat)
localhost.yyyy-mm-dd.logApplication stack traces, ServletContext log messages
manager.yyyy-mm-dd.logManager app activity (if deployed)
host-manager.yyyy-mm-dd.logHost Manager activity
localhost_access_log.yyyy-mm-dd.txtHTTP access lines (only if AccessLogValve enabled)

All paths are relative to $CATALINA_BASE/logs/ (usually $CATALINA_HOME/logs/).

Live follow:

bash
tail -f $CATALINA_HOME/logs/catalina.$(date +%Y-%m-%d).log
tail -f $CATALINA_HOME/logs/localhost.$(date +%Y-%m-%d).log

Windows PowerShell:

powershell
Get-Content "$env:CATALINA_HOME\logs\catalina.$(Get-Date -Format yyyy-MM-dd).log" -Wait -Tail 20

What Goes Where

text
  Startup failure (port bind, XML error)
       → catalina.*.log
 
  Servlet NullPointerException
       → localhost.*.log
 
  "Deployment of web application archive … has finished"
       → catalina.*.log
 
  GET /hello/api 200 42
       → localhost_access_log.*.txt  (with AccessLogValve)

Code explanation:

  • catalina — Tomcat’s own voice (container lifecycle)
  • localhost — name of the default Engine/Host pipeline in logs, not “only 127.0.0.1 traffic”
  • Application code using SLF4J/Logback inside a WAR may write to localhost.*.log or separate files depending on config

logging.properties

Tomcat uses java.util.logging (JUL) by default via conf/logging.properties.

Common tweaks:

Code explanation:

  • ${catalina.base}/logs — log directory follows instance base
  • FINE / FINER — more verbose; use temporarily when debugging
  • Restart Tomcat after editing logging.properties

Tip

Do Not Set DEBUG on Production Long-Term

Verbose JUL fills disks and hides real errors. Revert to INFO/WARNING after diagnosis.

Spring Boot WAR on Tomcat

Boot apps often use Logback via logback-spring.xml—those logs may appear in localhost.*.log or stdout captured by systemd. Container logging.properties still controls Tomcat internals.

Enable AccessLogValve

By default, Tomcat may not write HTTP access logs until you add AccessLogValve under a <Host> in conf/server.xml.

Backup and edit conf/server.xml:

xml
<Host name="localhost" appBase="webapps"
      unpackWARs="true" autoDeploy="true">
 
  <Valve className="org.apache.catalina.valves.AccessLogValve"
         directory="logs"
         prefix="localhost_access_log"
         suffix=".txt"
         pattern="common" />
 
</Host>

Restart Tomcat, generate traffic:

bash
curl http://127.0.0.1:8080/hello/api
tail -3 $CATALINA_HOME/logs/localhost_access_log.$(date +%Y-%m-%d).txt

Example line (common pattern):

text
127.0.0.1 - - [07/Jun/2026:14:22:01 +0000] "GET /hello/api HTTP/1.1" 200 28

Code explanation:

  • directory="logs" — relative to CATALINA_BASE
  • prefix / suffix — file name = localhost_access_log.yyyy-mm-dd.txt
  • pattern="common" — Apache common log format (IP, time, request, status, bytes)

Combined pattern (referer + user agent)

xml
<Valve className="org.apache.catalina.valves.AccessLogValve"
       directory="logs"
       prefix="localhost_access_log"
       suffix=".txt"
       pattern="combined" />

Adds referer and User-Agent—useful for browser vs bot traffic analysis.

Custom pattern

xml
pattern="%h %l %u %t &quot;%r&quot; %s %b %D ms"

%D — time taken in milliseconds. See Apache Tomcat Access Log Valve docs for full placeholders.

Tomcat Access Log vs Nginx Access Log

Typical production stack:

text
  Internet → Nginx (443) → Tomcat (8080 localhost)
                │                    │
         /var/log/nginx/      logs/localhost_access_log.*
         access.log
LayerSeesGood for
NginxClient IP (public), TLS, cache statusEdge traffic, CDN, rate limits
TomcatOften 127.0.0.1 if proxiedServlet path, app status codes, backend timing

When Nginx proxies to Tomcat, Tomcat access logs show 127.0.0.1 unless Nginx sends X-Forwarded-For and you configure Tomcat RemoteIpValve (advanced). For client IP at the edge, trust Nginx access.log.

Pair with Nginx access log chapter and Nginx + Tomcat.

Reading Logs After Deploy

Checklist after copying a WAR:

bash
LOG_DATE=$(date +%Y-%m-%d)
 
grep -i "hello" $CATALINA_HOME/logs/catalina.$LOG_DATE.log
grep -i "SEVERE\|ERROR" $CATALINA_HOME/logs/catalina.$LOG_DATE.log
grep -i "Exception" $CATALINA_HOME/logs/localhost.$LOG_DATE.log
curl -I http://127.0.0.1:8080/hello/api
tail -5 $CATALINA_HOME/logs/localhost_access_log.$LOG_DATE.txt
SignalMeaning
Deployment … finishedContext /hello live
SEVERE + stack traceFix before testing features
404 in access logWrong URL or missing Servlet mapping
500 in access logApp exception—read localhost.*.log

Application Logging from Servlets

Quick learning approach (not production best practice):

java
getServletContext().log("Processing request");

Appears in localhost.*.log.

Production WARs: SLF4J + Logback or Log4j2 with rolling file appenders—configure inside the app, not only JUL.

Manager and Host Manager Logs

If Manager (/manager/html) is deployed:

  • Operations (deploy/undeploy) log to manager.yyyy-mm-dd.log
  • Failed auth attempts may appear in localhost.*.log

Host Manager logs to host-manager.*.log.

Warning

Manager Exposure

Manager is powerful—restrict access in production. See Tomcat Security Basics.

Log Rotation and Disk Space

Tomcat rotates by date in the file name (catalina.2026-06-07.log). It does not compress old files automatically.

Ops habits:

  • logrotate on Linux for logs/
  • Monitor disk: df -h, du -sh logs/
  • Delete ancient catalina.*.log after archive to S3/backup

systemd journal (if using journalctl -u tomcat) is separate from logs/—check both when using catalina.sh run under systemd.

systemd and catalina.out

With Type=simple and catalina.sh run, some messages go to journald:

bash
sudo journalctl -u tomcat -n 100 --no-pager

With startup.sh, file logs under logs/ are primary.

Common Problems

SymptomCauseFix
No access log fileAccessLogValve missingAdd Valve under Host; restart
Empty catalina logWrong CATALINA_BASEConfirm instance paths
Logs not updatingTail wrong date fileUse today’s date suffix or ls -lt logs/
Huge logs overnightDEBUG level left onReset logging.properties levels
Permission denied writing logstomcat user cannot write logs/chown tomcat:tomcat logs/

Post-Chapter Checklist

  • Know catalina.* vs localhost.* vs access log
  • Enabled AccessLogValve with common or combined pattern
  • Can tail -f and grep SEVERE / Exception
  • Understand Nginx vs Tomcat access log roles

What Comes Next

ChapterTopic
11 — Tomcat security basicsRemove samples, lock Manager
12 — Nginx reverse proxy TomcatEdge logs + proxy headers
20 — TroubleshootingFull diagnostic guide

FAQ

catalina.out vs catalina.yyyy-mm-dd.log?

.out is legacy stdout capture; dated catalina.*.log is JUL AsyncFileHandler output on modern Tomcat. Check both if unsure how Tomcat was started.

Log4j2 inside my WAR?

App logging is independent—configure logback.xml / log4j2.xml in the WAR. Tomcat logging.properties does not replace app log config.

Access log shows 127.0.0.1 only?

Expected behind Nginx on same host. Use Nginx log for real client IP or add RemoteIpValve.

Can I log only one web app?

Configure AccessLogValve on a Context fragment or separate Host—default Host valve logs all contexts on that host.

Where do JSP compile errors go?

localhost.*.log with Jasper compiler stack traces; also check work/ after fixes.

Reload logging without restart?

logging.properties changes need restart. AccessLogValve server.xml changes need restart too.