1. 서론: WAS 장애 대응의 나침반, 접근 로그(Access Log)
웹 서비스 운영 중 “어제 밤 특정 시간대에 서비스가 10초간 멈칫했다"거나 “간헐적으로 500 에러가 발생한다"는 사용자 인입이 들어왔을 때, 장애 원인을 규명하기 위한 가장 첫 번째 단서는 바로 **WAS의 접근 로그(Access Log)**입니다.
애플리케이션 로그(app.log)는 개발자가 명시적으로 log.info()나 log.error()를 찍어둔 코드 블록만 기록하지만, Tomcat의 접근 로그는 웹 서버로 인입된 **모든 HTTP 요청의 생애 주기(클라이언트 IP, 요청 URL, 처리 소요 시간, HTTP 상태 코드, 응답 바이트 수)**를 누락 없이 100% 포착합니다.
그러나 안타깝게도 많은 운영 환경에서 Tomcat의 기본 common 로그 포맷을 그대로 방치하여, 장애 분석에 가장 필수적인 **‘요청 처리 시간(%D)’**이나 **‘실제 클라이언트 원천 IP(%{X-Forwarded-For}i)’**를 유실하고 있습니다.
이번 포스팅에서는 Tomcat server.xml의 AccessLogValve 커스텀 패턴 작성법, 프록시 환경의 RemoteIpValve 연동, ELK/Loki 연동을 위한 JSON 포맷 로깅, 그리고 리눅스 셸을 활용한 실전 분석 기법까지 완벽히 정리합니다.
2. 접근 로그 처리 파이프라인과 아키텍처
클라이언트 요청이 리버스 프록시(Nginx / ALB)를 거쳐 Tomcat의 AccessLogValve에 도달하고 디스크에 플러시되는 구조입니다.
3. AccessLogValve 핵심 패턴 토큰 총정리
conf/server.xml의 <Host> 태그 내부에 정의되는 AccessLogValve에서 사용할 수 있는 대표적인 지시자(Token)들입니다.
| 토큰 | 의미 및 출력 데이터 | 실무 활용도 |
|---|---|---|
%h |
원격 클라이언트 호스트명 또는 IP 주소 | 필수 (단, 프록시 환경에서는 프록시 IP가 찍힘) |
%t |
요청 수신 일시 ([dd/MMM/yyyy:HH:mm:ss Z]) |
필수 (시계열 분석) |
%r |
요청의 첫 번째 라인 ("GET /api/orders HTTP/1.1") |
필수 (메서드 및 URI 추적) |
%s |
HTTP 응답 상태 코드 (200, 404, 500 등) | 필수 (에러 발생률 모니터링) |
%b |
전송된 바이트 수 (HTTP 헤더 제외) | 트래픽 대역폭 추적 |
%D |
요청 처리에 소요된 시간 (밀리초, ms 단위) | 최우선 필수 (성능 지연/슬로우 쿼리 탐지) |
%F |
첫 번째 응답 바이트를 커밋하는 데 걸린 시간 (ms) | Time To First Byte (TTFB) 분석 |
%{X-Forwarded-For}i |
요청 헤더 중 X-Forwarded-For 값 추출 |
프록시/로드밸런서 뒷단 필수 |
%{User-Agent}i |
클라이언트 브라우저 / 봇 User-Agent 헤더 | 봇 크롤링 및 모바일 트래픽 식별 |
4. 실무 표준 커스텀 패턴 (server.xml)
가장 권장되는 표준 텍스트 기반 커스텀 패턴입니다. 기존 Apache 공통 포맷 끝에 %D, %F, 그리고 프록시 헤더들을 결합합니다.
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<!-- 실무 프로덕션 권장 AccessLogValve 설정 -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".log"
rotatable="true"
renameOnRotate="true"
fileDateFormat="yyyy-MM-dd"
maxDays="30"
buffered="true"
bufferSize="16384"
pattern="%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %D %F "%{X-Forwarded-For}i"" />
</Host>
핵심 옵션 파라미터 해설
buffered="true"&bufferSize="16384": 매 요청마다 디스크 I/O를 발생시키지 않고 16KB 버퍼에 모아두었다가 일괄 기록하여 디스크 병목을 획기적으로 줄입니다.maxDays="30": 30일이 지난 오래된 접근 로그를 Tomcat이 스스로 자동 삭제(Purge)하여 디스크 풀 장애를 영구적으로 예방합니다 (Tomcat 8.5+ 지원).%D포함: 요청 시작부터 응답 완료까지의 전체 지연 시간을 밀리초 단위로 정확히 남깁니다.
5. 프록시 환경의 필수품: RemoteIpValve
앞단에 Nginx, HAProxy, AWS ALB가 존재하는 환경에서는 %h에 사용자의 실제 IP가 아닌 프록시 서버의 내부 IP(예: 10.0.0.1 또는 127.0.0.1)만 기록되는 치명적인 문제가 발생합니다.
이를 해결하기 위해 AccessLogValve 바로 위에 **RemoteIpValve**를 반드시 선언해야 합니다.
<!-- 클라이언트 원천 IP 복원을 위한 RemoteIpValve -->
<Valve className="org.apache.catalina.valves.RemoteIpValve"
internalProxies="10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|127\.0\.0\.1"
remoteIpHeader="x-forwarded-for"
protocolHeader="x-forwarded-proto" />
이 설정을 추가하면 Tomcat은 X-Forwarded-For 헤더를 신뢰하여 %h뿐만 아니라 request.getRemoteAddr() 자바 코드에서도 실제 사용자의 퍼블릭 IP를 올바르게 인식하게 됩니다.
6. 현대 클라우드 환경을 위한 JSON 포맷 로깅
ELK 스택(Elasticsearch, Logstash, Kibana)이나 Grafana Loki, AWS CloudWatch Logs Insights로 로그를 수집할 계획이라면, 정규표현식 파싱 오버헤드가 없는 구조화된 JSON 포맷으로 출력하는 것이 최선입니다.
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="access_json" suffix=".log"
rotatable="true" fileDateFormat="yyyy-MM-dd" maxDays="14"
pattern="{"client_ip":"%h","time":"%t","method":"%m","uri":"%U","query":"%q","status":%s,"bytes":%b,"response_time_ms":%D,"user_agent":"%{User-Agent}i","forwarded_for":"%{X-Forwarded-For}i"}" />
7. 리눅스 CLI를 활용한 초고속 실전 로그 분석
접근 로그 파일이 준비되었다면, 별도의 복잡한 도구 없이도 리눅스 표준 유틸리티(awk, sort, uniq)만으로 10초 만에 장애 원인을 진단할 수 있습니다.
1) 응답 속도가 가장 느린 상위 10개 API 탐색 (슬로우 API 추적)
# 로그의 마지막에서 3번째 필드가 %D인 경우 (1초 = 1000ms 초과 건 검색)
awk '$(NF-2) > 1000 {print $(NF-2) "ms", $6, $7}' localhost_access_log.2026-08-19.log | sort -nr | head -10
2) 비정상적인 대량 요청을 발생시키는 상위 IP 10개 (DDoS / 크롤러 탐색)
awk '{print $1}' localhost_access_log.2026-08-19.log | sort | uniq -c | sort -nr | head -10
3) 분당 HTTP 5xx 서버 내부 오류 발생 추이 확인
grep ' 50[0-9] ' localhost_access_log.2026-08-19.log | awk '{print substr($4, 14, 5)}' | uniq -c
8. 결론
로그는 단순한 텍스트 기록이 아니라, 서비스의 헬스체크와 사용자 경험을 모니터링하는 가장 객관적인 계측기입니다.
Tomcat의 기본 로그 설정에 안주하지 말고, **%D (응답 처리 시간)**와 RemoteIpValve, 그리고 maxDays="30" 자동 롤링 옵션을 반드시 활성화하여 운영 효율과 장애 분석 속도를 극대화하시기 바랍니다.