본문 바로가기

IT

[Java] MDC를 활용한 로그 추적

728x90

MDC란 Mapped Diagnostic Context 의 약자로 일부 특징의 데이터를 Map 형태로 저장하는 메커니즘으로 흔히 사용하는 slf4j, logback, log4j2 등 Logger에서 MDC를 제공해준다.

MDC : 현재 실행중인 쓰레드에 메타 정보를 넣고 관리하는 공간

MDC는 로그에 메타데이터를 맵으로 관리할 수 있게 해준다. 쉽게 말하자면 MDC 는 로그에 컨텍스트를 남기는 용도라고 생각하면 된다. 그렇다면 멀티 쓰레드 환경에서 요청 쓰레드 별로 식별가능한 로그를 남기는 것이 가능하다. 

 

MDC.put(k,v) , MDC.get(k) 를 이용하여 저장하고 읽을수가 있다. map과 같은데 특징은 이 map이 쓰레드 단위로 생성된다.

 

Filter, Interceptor, AOP 등을 이용하여 Map형태의 MDC에 put을 한다면 로그를 추적하거나 메타정보를 관리할 수 있는 것이다. 

 

Filter를 활용한 간단한 예시를 들어보자. 

public class MDCFilter implements Filter {
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
		MDC.set("tran_id", random());
		chain.dofilter(req, res);
		MDC.clear();
	}
}

Filter를 통해 뒷단에 모든 레이어(Controller, Service, Repository 등)에서 get 하여 사용할 수 있다.

log.info(MDC.get("tran_id"))

여기서 주의할 점은 doFilter가 끝나서 나오면 clear를 해준다는 것이다. Spring MVC는 쓰레드 풀에 쓰레드들을 만들어 두고, 요청이 오면 쓰레드를 사용해 요청을 처리하고 반납한다. 그런데 MDC는 쓰레드 별로 저장되는 쓰레드 로컬을 사용하므로, 요청이 완료될 때 Clear를 해주지 않으면 다른 요청이 이 쓰레드를 재사용할 때 이전 데이터가 남아있을 수 있다.

그러므로 반드시 Clear 해주어야 한다.

 

더 간단한 예시를 들어보자. 

public class MDCExam 

{
    private static Logger log = LoggerFactory.getLogger(MDCExam.class);
    public static void main( String[] args )
    {
    	log.info("pre MDC")ㅣ
        
    	MDC.put("username", "lee_seunghun");
    	MDC.put("transactionId", "970901");
    	log.info("pro MDC");
    	MDC.clear();
        
    	log.info("post MDC");

    }

}
{
  "timestamp" : "2023-07-30T08:44:19.112Z",
  "level" : "INFO",
  "message" : "pre MDC",
  ...
}
{
  "timestamp" : "2023-07-30T08:44:19.129Z",
  "level" : "INFO",
  "message" : "pro MDC",
  "mdc" : {
    "username" : "lee_seunghun",
    "transactionId" : "970901"
  },
  ...
}
{
  "timestamp" : "2023-07-30T08:44:19.131Z",
  "level" : "INFO",
  "message" : "post MDC",
  ...
}

MDC를 활용한 부분의 차이를 확인할 수 있다. 

 

 

 

 

 

MDC는 ThreadLocal을 공부해보도록 하자. ThreadLocal은 쓰레드 단위로 어떠한 작업이 필요할 때 사용된다. 생소하다면 아래 블로그를 참고하도록 하자.

2023.08.05 - [Java] - [Java] ThreadLocal

 

 

'IT' 카테고리의 다른 글

Aurora Failover에 대한 WAS 전략  (1) 2023.10.27
[SpringBoot] 에러 처리 Errorcontroller(@ExceptionHandler)  (1) 2023.08.11
[Java] ThreadLocal  (0) 2023.07.31
CQRS ? AbstractRoutingDatasource  (0) 2023.07.29
JPA N+1 문제 응용 사례  (2) 2023.06.17