본문으로 건너뛰기
Advertisement

Tomcat 로그 관리

Tomcat은 여러 종류의 로그를 생성합니다. 각 로그의 역할을 이해하고 적절히 설정하면 장애 진단과 성능 분석에 큰 도움이 됩니다. 이 챕터에서는 catalina.out, 액세스 로그 Valve, 그리고 Log4j2 통합까지 다룹니다.


Tomcat 로그 종류

로그 파일설명기본 위치
catalina.outTomcat 표준 출력/오류 (메인 로그)$CATALINA_HOME/logs/
catalina.YYYY-MM-DD.logjava.util.logging 일별 로그$CATALINA_HOME/logs/
localhost.YYYY-MM-DD.log가상 호스트 로그$CATALINA_HOME/logs/
localhost_access_log.txtHTTP 접근 로그 (Access Log Valve)$CATALINA_HOME/logs/
manager.YYYY-MM-DD.logManager 앱 로그$CATALINA_HOME/logs/

catalina.out

catalina.out은 Tomcat 시작/종료, 앱 배포/언배포, 에러 등이 모두 기록되는 핵심 로그입니다.

# 실시간 모니터링
tail -f /opt/tomcat/latest/logs/catalina.out

# 에러만 필터링
grep -E "(ERROR|SEVERE|Exception)" /opt/tomcat/latest/logs/catalina.out

# 최근 100줄 + 실시간
tail -100f /opt/tomcat/latest/logs/catalina.out

# 특정 앱 관련 로그
grep "myapp" /opt/tomcat/latest/logs/catalina.out

주의: catalina.out은 기본적으로 로테이션되지 않습니다. 장기 운영 시 파일 크기가 무한정 커질 수 있으므로 logrotate 설정이 필수입니다.


logging.properties — 기본 로그 설정

conf/logging.properties로 Tomcat 내부 로거(java.util.logging)를 설정합니다.

# $CATALINA_HOME/conf/logging.properties

# 핸들러 목록
handlers = 1catalina.org.apache.juli.AsyncFileHandler, \
2localhost.org.apache.juli.AsyncFileHandler, \
3manager.org.apache.juli.AsyncFileHandler, \
java.util.logging.ConsoleHandler

# 기본 로그 레벨
.handlers = 1catalina.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler

# catalina 핸들러 설정
1catalina.org.apache.juli.AsyncFileHandler.level = FINE
1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina.
1catalina.org.apache.juli.AsyncFileHandler.suffix = .log
1catalina.org.apache.juli.AsyncFileHandler.encoding = UTF-8

# localhost 핸들러 설정
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.suffix = .log
2localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8

# 콘솔 핸들러 (catalina.out으로 가는 스트림)
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
java.util.logging.ConsoleHandler.encoding = UTF-8

# 특정 패키지 로그 레벨 조정
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler

# 불필요한 로그 억제 예시
org.apache.coyote.http11.Http11Processor.level = WARNING

로그 레벨 (java.util.logging)

레벨설명
SEVERE심각한 에러
WARNING경고
INFO일반 정보 (기본)
CONFIG설정 관련
FINE상세 디버그
FINER더 상세
FINEST최대 상세

Access Log Valve — HTTP 접근 로그

server.xml의 Host 내에 AccessLogValve를 추가합니다.

기본 설정

<!-- server.xml -->
<Host name="localhost" appBase="webapps" ...>
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="combined"/>
</Host>

커스텀 패턴 — 응답 시간 포함

<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="access_log"
suffix=".txt"
rotatable="true"
fileDateFormat="yyyy-MM-dd"
pattern="%h %l %u %t &quot;%r&quot; %s %b %D &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot;"/>
패턴 변수설명
%h원격 호스트 (IP)
%l원격 논리적 사용자명
%u인증된 사용자
%t요청 시각
%r요청 라인 (메서드 + URI + 프로토콜)
%sHTTP 상태 코드
%b응답 바이트 수
%D처리 시간 (밀리초)
%T처리 시간 (초)
%{헤더명}i요청 헤더 값

JSON 형식 로그

<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="access_log"
suffix=".json"
pattern="{&quot;time&quot;:&quot;%t&quot;,&quot;method&quot;:&quot;%m&quot;,&quot;uri&quot;:&quot;%U%q&quot;,&quot;status&quot;:%s,&quot;bytes&quot;:%b,&quot;duration_ms&quot;:%D,&quot;ip&quot;:&quot;%h&quot;}"/>

Log4j2 통합 (권장)

Java 애플리케이션에서 더 강력한 로깅이 필요하다면 Log4j2를 사용합니다.

의존성 추가 (Maven)

<!-- pom.xml -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.1</version>
</dependency>
<!-- JUL → Log4j2 브릿지 (Tomcat 내부 로그도 Log4j2로) -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
<version>2.23.1</version>
</dependency>

log4j2.xml 설정

<!-- src/main/resources/log4j2.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="60">

<Properties>
<Property name="LOG_DIR">/opt/tomcat/latest/logs</Property>
<Property name="APP_NAME">myapp</Property>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>

<Appenders>
<!-- 콘솔 출력 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
</Console>

<!-- 일별 로테이션 파일 -->
<RollingFile name="AppLog"
fileName="${LOG_DIR}/${APP_NAME}.log"
filePattern="${LOG_DIR}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log.gz">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>

<!-- 에러 전용 파일 -->
<RollingFile name="ErrorLog"
fileName="${LOG_DIR}/${APP_NAME}-error.log"
filePattern="${LOG_DIR}/${APP_NAME}-error.%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="${LOG_PATTERN}"/>
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>

<Loggers>
<!-- 루트 로거 -->
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="AppLog"/>
<AppenderRef ref="ErrorLog"/>
</Root>

<!-- 패키지별 레벨 조정 -->
<Logger name="com.example.myapp" level="DEBUG" additivity="false">
<AppenderRef ref="AppLog"/>
</Logger>

<!-- SQL 로그 (개발용) -->
<Logger name="org.hibernate.SQL" level="DEBUG" additivity="false">
<AppenderRef ref="AppLog"/>
</Logger>

<!-- 불필요한 라이브러리 로그 억제 -->
<Logger name="org.springframework" level="WARN"/>
<Logger name="org.hibernate" level="WARN"/>
</Loggers>

</Configuration>

logrotate 설정 (catalina.out 로테이션)

# /etc/logrotate.d/tomcat
/opt/tomcat/latest/logs/catalina.out {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate # Tomcat 재시작 없이 로테이션 (중요!)
dateext
dateformat -%Y%m%d
postrotate
# 로테이션 후 알림 (선택)
echo "Tomcat log rotated: $(date)" | logger -t tomcat-logrotate
endscript
}

# 액세스 로그도 함께 관리
/opt/tomcat/latest/logs/*.log
/opt/tomcat/latest/logs/*.txt {
daily
rotate 30
compress
delaycompress
missingok
notifempty
copytruncate
dateext
}
# logrotate 설정 테스트
sudo logrotate -d /etc/logrotate.d/tomcat

# 즉시 강제 실행
sudo logrotate -f /etc/logrotate.d/tomcat

실전 로그 분석

# 느린 요청 분석 (처리 시간 > 1000ms)
awk '{ if ($NF > 1000) print }' /opt/tomcat/latest/logs/localhost_access_log*.txt

# 500 에러 요청 집계
awk '{print $9}' /opt/tomcat/latest/logs/localhost_access_log*.txt | \
grep "^5" | sort | uniq -c | sort -rn

# 특정 URL 평균 응답 시간
awk '/\/api\/users/ {sum+=$NF; cnt++} END {print "Avg:", sum/cnt "ms"}' \
/opt/tomcat/latest/logs/localhost_access_log*.txt

# OutOfMemoryError 발생 확인
grep -c "OutOfMemoryError" /opt/tomcat/latest/logs/catalina.out

Summary

로그설정 위치주요 역할
catalina.outSystemd 서비스 or bin/catalina.shTomcat 전반 이벤트
java.util.loggingconf/logging.propertiesTomcat 내부 컴포넌트
Access Logserver.xml AccessLogValveHTTP 접근 기록
Log4j2WEB-INF 또는 classpath앱 레벨 구조화 로그
logrotate/etc/logrotate.d/tomcatcatalina.out 파일 크기 제어
Advertisement