MDC
란 로깅 시스템에서 로그 레코드에 정보를 추가로 입력하여 로그를 더욱 의미 있고 편하게 사용 할 수 있게 해주는 메커니즘이다.
MDC는 주로 로깅 시 각 쓰레드마다 로그에 연관된 컨텍스트 정보를 제공하기 위해 사용한다.
MDC는 내부적으로 Map을 관리하고 있어 Key, Value 형태로 값을 저장할 수 있다. 메타 정보를 쓰레드 별로 관리하기 위해 쓰레드 로컬
을 사용한다.
쓰레드 로컬(Thread Local)
쓰레드 로컬은 간단하게 말하자면 쓰레드 마다 고유의 값을 저장할 수 있는 공간이다. 즉, 멀티 쓰레드 환경에서도 변수 명은 같아도 쓰레드 별로 고유한 값을 사용 할 수 있다는 말이다.
주로 로깅을 위해 쓰레드에 정보를 추가할 땐 Filter에서 사용한다.
@GetMapping("/")
public void test(){
//logback 사용
log.info("테스트 시작");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("테스트 끝");
}
위 코드는 로그 사이에 5초를 기다리게 하는 코드다. 이걸 연속으로 실행해서 쓰레드가 섞여 로그를 섞이게 찍도록 만들어보자.
먼저 MDC가 적용이 안된 로그의 모습이다.
아무것도 추가 안한 spring boot가 기본으로 제공해주는 로그를 봐도 어떤 쓰레드가 실행 됐는지 아주 구분을 못할 정도는 아니다. 하지만 이건 단순히 2개 쓰레드만 놓고 봐서 그렇지 많은 쓰레드가 섞인다면 구분하기가 여간 힘든게 아닐 것이다.
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MDCFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final UUID uuid = UUID.randomUUID();
MDC.put("request_id", uuid.toString());
chain.doFilter(request, response);
MDC.clear();
}
}
위 코드는 쓰레드에 request_id = UUID 값을 필터에 추가해준다. 코드를 추가하고 다시 실행 하면 로그에 UUID값이 추가로 나오는 걸 볼 수 있다.
이렇게 원하는 값을 로그에 추가한다면 여러 쓰레드의 많은 로그들이 쌓여도 추척하는데 편리성을 줄 수 있다.
logback.xml
사실 위 필터만 추가한다고 나오는건 아니다 resources/logback.xml을 만들고 안에 로그 패턴을 정의 해줘야한다. logback.xml파일 설정법은 구글링을 추천한다.
파일을 만들고 패턴을 추가했다면 우리가 추가한 request_id의 값도 보여줘야하니[%X{request_id:-startup}]
을 원하는 위치에 추가로 넣어보자.
한 줄평 : 멀티 쓰레드 환경에서 로그 추척을 위해서는 반드시 MDC를 적용하는게 좋다.