Tomcat 서버 요청 로그와 디버깅 방법
1. 기본 로그 확인
Tomcat은 logs 디렉터리에 다양한 로그를 남깁니다. 요청 내역은 보통 Access Log에 기록됩니다.
- Access 로그:
localhost_access_log.YYYY-MM-DD.txt - Catalina 로그: 서버 동작 및 에러 관련 메시지
- 실시간 모니터링:
tail -f logs/localhost_access_log.*
2. 헤더와 바디까지 확인하기
Access Log만으로는 부족합니다. 요청의 HTTP Header와 Body Payload를 확인하려면 다음 방법을 사용합니다.
- RequestDumperValve 설정
- Filter 구현하여
HttpServletRequest에서 직접 읽기 - 프록시 서버(Nginx, Apache)에서 로깅
- 디버깅 툴 (Wireshark, Fiddler, Postman)
3. RequestDumperValve가 없을 때
대안으로는 Custom Filter와 RequestWrapper를 활용합니다.
Map<String, String[]> params = request.getParameterMap();
for (String key : params.keySet()) {
System.out.println(key + " = " + Arrays.toString(params.get(key)));
}
4. HttpServletRequestWrapper 사용법
요청 바디를 캐싱하여 여러 번 읽을 수 있도록 만드는 클래스입니다.
public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
private byte[] cachedBody;
public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException {
super(request);
InputStream requestInputStream = request.getInputStream();
this.cachedBody = requestInputStream.readAllBytes(); // Java 9 이상
}
@Override
public ServletInputStream getInputStream() {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedBody);
return new ServletInputStream() {
@Override
public int read() {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return byteArrayInputStream.available() == 0;
}
@Override
public boolean isReady() { return true; }
@Override
public void setReadListener(ReadListener readListener) {}
};
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
5. JSON 요청 로깅 필터 예시
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
CachedBodyHttpServletRequest wrappedRequest = new CachedBodyHttpServletRequest(httpRequest);
// Content-Type 확인
System.out.println("Content-Type: " + httpRequest.getContentType());
// 요청 바디 출력
String body = wrappedRequest.getReader().lines().collect(Collectors.joining("\n"));
System.out.println("Request Body: " + body);
// 파라미터 출력
Map<String, String[]> params = wrappedRequest.getParameterMap();
params.forEach((key, value) -> System.out.println(key + " = " + Arrays.toString(value)));
chain.doFilter(wrappedRequest, response);
}
}
6. 버전 관련 참고
InputStream.readAllBytes(): Java 9 이상에서 사용 가능ReadListener: Servlet 3.1 (Java EE 7, Tomcat 8.0 이상)부터 지원
7. 필터 적용 문제 해결
필터가 적용되지 않는 경우는 보통 등록 문제입니다.
- web.xml에
<filter>와<filter-mapping>확인 - Spring Boot에서는
FilterRegistrationBean으로 등록 - URL 매핑:
/*로 지정해야 전체 요청에 적용 - chain.doFilter() 호출 누락 여부 확인
마무리
Tomcat에서 요청 파라미터와 바디를 디버깅하려면 RequestWrapper + LoggingFilter 조합이 가장 일반적입니다. 운영 환경에서는 보안과 성능을 고려해 제한적으로 사용하는 것이 좋습니다.
