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
- Tomcat Directory Layout —
logs/directory - Start, Stop, and Environment
- Your First Servlet Application — app deployed for sample lines
Log Files Overview
| File (typical) | Contents |
|---|---|
catalina.yyyy-mm-dd.log | Container startup, shutdown, deploy/undeploy, severe errors |
catalina.out | Sometimes stdout/stderr redirect (depends on how you start Tomcat) |
localhost.yyyy-mm-dd.log | Application stack traces, ServletContext log messages |
manager.yyyy-mm-dd.log | Manager app activity (if deployed) |
host-manager.yyyy-mm-dd.log | Host Manager activity |
localhost_access_log.yyyy-mm-dd.txt | HTTP access lines (only if AccessLogValve enabled) |
All paths are relative to $CATALINA_BASE/logs/ (usually $CATALINA_HOME/logs/).
Live follow:
tail -f $CATALINA_HOME/logs/catalina.$(date +%Y-%m-%d).log
tail -f $CATALINA_HOME/logs/localhost.$(date +%Y-%m-%d).logWindows PowerShell:
Get-Content "$env:CATALINA_HOME\logs\catalina.$(Get-Date -Format yyyy-MM-dd).log" -Wait -Tail 20What Goes Where
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.*.logor 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 baseFINE/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:
<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:
curl http://127.0.0.1:8080/hello/api
tail -3 $CATALINA_HOME/logs/localhost_access_log.$(date +%Y-%m-%d).txtExample line (common pattern):
127.0.0.1 - - [07/Jun/2026:14:22:01 +0000] "GET /hello/api HTTP/1.1" 200 28Code explanation:
directory="logs"— relative toCATALINA_BASEprefix/suffix— file name =localhost_access_log.yyyy-mm-dd.txtpattern="common"— Apache common log format (IP, time, request, status, bytes)
Combined pattern (referer + user agent)
<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
pattern="%h %l %u %t "%r" %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:
Internet → Nginx (443) → Tomcat (8080 localhost)
│ │
/var/log/nginx/ logs/localhost_access_log.*
access.log| Layer | Sees | Good for |
|---|---|---|
| Nginx | Client IP (public), TLS, cache status | Edge traffic, CDN, rate limits |
| Tomcat | Often 127.0.0.1 if proxied | Servlet 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:
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| Signal | Meaning |
|---|---|
| Deployment … finished | Context /hello live |
| SEVERE + stack trace | Fix before testing features |
| 404 in access log | Wrong URL or missing Servlet mapping |
| 500 in access log | App exception—read localhost.*.log |
Application Logging from Servlets
Quick learning approach (not production best practice):
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.*.logafter 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:
sudo journalctl -u tomcat -n 100 --no-pagerWith startup.sh, file logs under logs/ are primary.
Common Problems
| Symptom | Cause | Fix |
|---|---|---|
| No access log file | AccessLogValve missing | Add Valve under Host; restart |
| Empty catalina log | Wrong CATALINA_BASE | Confirm instance paths |
| Logs not updating | Tail wrong date file | Use today’s date suffix or ls -lt logs/ |
| Huge logs overnight | DEBUG level left on | Reset logging.properties levels |
| Permission denied writing logs | tomcat user cannot write logs/ | chown tomcat:tomcat logs/ |
Post-Chapter Checklist
- Know
catalina.*vslocalhost.*vs access log - Enabled AccessLogValve with common or combined pattern
- Can
tail -fand grep SEVERE / Exception - Understand Nginx vs Tomcat access log roles
What Comes Next
| Chapter | Topic |
|---|---|
| 11 — Tomcat security basics | Remove samples, lock Manager |
| 12 — Nginx reverse proxy Tomcat | Edge logs + proxy headers |
| 20 — Troubleshooting | Full 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.