1. MDC 사용 이유
1) 스레드 별 로깅 컨텍스트
다중 스레드 환경에서 각 스레드는 독립적으로 실행되며 서로 다른 작업을 수행함
MDC를 사용하면 각 스레드에게 고유한 로깅 컨텍스트를 제공하여 스레드 간 로그를 구분할 수 있음
2) 트랜잭션 추적
웹 애플리케이션 환경에서는 하나의 요청이 여러 스레드를 통과할 수 있음
MDC를 사용하면 요청을 추적하고 해당 요청과 관련된 로그를 모아서 볼 수 있으므로 트랜잭션 춪거 및 디버깅에 유용
3) 디버깅 및 로깅 수준 설정
디버깅 시 특정 스레드나 작업에 대한 로그를 쉽게 필터링 할 수 있음
특정 작업에 대한 로그를 필요한 경우에만 출력하도록 로깅 수준을 동적으로 설정할 수 있음
4) 추가 정보 제공
로그에 정보를 쉽게 추가할 수 있음
예를 들어 요청 ID, 세션 ID, 사용자 이름 등의 정보를 MDC에 저장하면 해당 정보가 로그에 자동으로 추가되어 디버깅과 모니터링을 용이하게 함
5) 로그 형식 향상
로그 메시지에 동적인 정보를 추가하면 로그의 가독성을 향상시킬 수 있음
분산시스템에서 여러 서비스 간의 트랜잭션 추적이 필요한 경우 중요한 역할을 함
6) 내가 선택한 이유
기존 로깅 구현은 스레드는 확인할 수 있지만 다중 스레드 환경에서 로그가 뒤섞여 요청 별 파악이 어려웠음
요청의 흐름별로 로깅 파악하는 것이 문제를 파악하는데 중요하게 작용할 것 같아 MDC 적용
▼ 기존로깅 구현
2. MDC 적용 시점
필터(Filter), 인터셉터(Interceptor), 컨트롤러(AOP 적용) 시점 정도를 고려해 볼 수 있는데 웹 애플리케이션의 요청이 가장 처음 만나는 부분이기 때문에 필터에 가장 앞 부분에 설정하여 요청의 시작과 끝 확인
3. MDC 적용
1) 의존성 추가
로깅 구현체로 logback을 사용하는데 logback은 SLF4j 의 구현체이며 Spring Boot 환경이라면 spring-boot-starter-web > spring-boot-starter-logging에 logback 구현체가 포함되어 있어 별도의 dependency 추가 없이 사용할 수 있음
2) 필터 구현체 만들기
package com.example.queueproject.common;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.util.UUID;
/*
@Component: 스프링 컨텍스트에서 클래스를 빈으로 등록, Filter를 구현한 이 클래스를 스프링 빈으로 관리
@Order: 빈의 우선순위 설정
Ordered.HIGHEST_PRECEDENCE: 가장 높은 우선 순위
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MDCRequestLoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 필요에 따라 초기화 코드 작성
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
// 랜덤한 uuid 값을 생성하여 MDC 저장소에 request_id를 키, uuid를 value로 저장
UUID uuid = UUID.randomUUID();
MDC.put("request_id", uuid.toString());
// 다음 필터로 제어 전달, 실제 요청이 로직이 실행되는 지점
chain.doFilter(request, response);
} finally {
// 실제 요청이 완료되면 MDC 저장소를 초기화
MDC.clear();
}
}
@Override
public void destroy() {
// 필요에 따라 소멸 코드 작성
}
}
cf) MDC 메소드
put(String key, String val) | 현재 스레드의 MDC에 key-value 쌍 추가 |
get(String key) | 현재 스레드의 MDC에 주어진 key의 value 가져오기 |
remove(String key) | 현재 스레드의 MDC에 주어진 key의 value 삭제 |
clear() | 현재 스레드 MDC 초기화 |
3) logback.xml 파일 설정 수정
- 패턴
<property name="LOG_PATTERN" value="[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] %clr(%-5level) %clr(${PID:-}){magenta} %clr(---){faint} %clr([%15.15thread]){faint} [%clr(%X{request_id}){faint}] %clr(%-40.40logger{36}){cyan} %clr(:){faint} %msg%n"/>
- 로그 확인
실행된 스레드는 같지만 요청 id가 다르게 들어오는 것을 확인할 수 있음
에러
다른 프로젝트에 적용하려고 하니까 아래와 같이 java.servelet이 인식되지 않음
의존성 추가
compileOnly 'javax.servlet:javax.servlet-api:4.0.1'
https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/4.0.1
의존성을 추가해서 해결
저렇게 적용하고 로컬에서는 잘 돌아갔는데 빌드하고 vm 서버에서 실행시키니까 에러 발생
application run failed
org.springframework.beans.factory.BeanDefinitionStoreException: I/O failure while processing configuration class [cohttp://m.example.syncproject.common.log.MDCRequestLoggingFilter]
Caused by: java.io.IOException: Failed to load class [javax.servlet.Filter]
Caused by: java.lang.ClassNotFoundException: javax.servlet.Filter
-> javax.servlet.Filter 클래스를 찾지 못하고 있음
MDC 실습했던 프로젝트는 스프링부트 2버전 대 이고, 이걸 적용한 프로젝트는 스프링부트3버전이라
버전 문제인가 생각하면서 찾은게 기존에 javaEE를 사용했는데, 부트 3부터는 JakartaEE를 지원한다는 것
javaEE에서 제공하는 Java Servlet(javax.servlet)이 Jakarta Servlet(jakarta.servlet)으로 변경 됐다는 것을 보게됨
외부라이브러리 확인
부트2 프로젝트 javax
부트3 프로젝트 jakarta
import 부분을 javax에서 jakrata로 변경했더니 로컬환경에서도 서버에 올린 환경에서도 모두 실행 잘 되었음!
'Spring > Springboot' 카테고리의 다른 글
[Springboot] Redis 데이터 삭제 스케줄러 구현 (0) | 2024.01.23 |
---|---|
[Springboot] Redis를 In-memory DB로 사용하기(1) (0) | 2024.01.23 |
[Springboot] MDC(Mapped Diagnostic Context) 개념 (0) | 2024.01.06 |
[Springboot] 그라파나(grafana) 공유 대시보드 활용 (0) | 2024.01.05 |
[Springboot] 그라파나(grafana) 대시보드 만들기 (0) | 2024.01.05 |