MSA 환경으로 오면서, 특정 사용자가 어떤 행동을 했는지 파악해서 대응하기 어렵습니다
어려운 이유는 여러 가지가 있을 수 있는데요
1. 로그가 각 서비스마다 흩어져있다
2. 하나의 API 호출에서 발생한 로그들을 묶어서 볼 수 없다
1을 해결하기 위해서 보통 로그를 중앙에서 모아서 관리하게 되는데요
이를 위해 현재 제가 일하고 있는 곳에서는 하나(이중화는 고려하지 않겠습니다)의 거대한 Elastic Search 클러스터를 구성해 두고, 그 클러스터에서 모든 로그를 모아서 관리하고 있습니다
2번째 문제를 해결하기 위해서 API Gateway에서 eventId를 만들어 요청에 헤더에 포함시킨 후 릴레잉 해줍니다.
그 eventId를 로그에 포함시켜서, 이벤트 id 기준으로 묶어서 로그를 확인하고 있습니다. 더 자세한 내용은 영상을 확인해 주세요
이때, eventId를 로그에 까먹고 안 남길 수도 있잖아요?
그 부분을 신경 쓰지 않아도 되도록 해주는 것이 MDC입니다.
Mapped Diagnostic Context으로,
여기서 ThreadLocal을 사용한다는 점이 장점이자 단점이 되는데요
한 스레드에서 많은 요청이 처리되는 Netty에서는 이 부분을 관리하기 위해서 Reactor을 잘 다뤄야 하는 부분이 있습니다.
하지만 Spring MVC의 Request Per Thread 모델에서는 정말 편리하게 사용할 수 있습니다하나의 request 가 하나의 스레드에서만 관리되기에 MDC에서 정보를 꺼내면 같은 요청이라는 것은 명확해지니까요그렇다면 실제 구현을 해볼까요?
구현을 간단하게 만든 부분은 다음과 같습니다
HandlerInterceptor를 구현해, requestHeader에서 eventId 나, userId 같은 로그를 묶어서 볼 때 필요한 것들을 mdc에 넣어둡니다.
@Component
class MdcInterceptor : HandlerInterceptor {
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
val eventId = request.getHeader("key-event-id") ?: UUID.randomUUID().toString()
val userId = request.getHeader("key-user-id")
MDC.put("eventId", eventId)
MDC.put("userId", userId)
return true
}
}
@Configuration
class WebConfig(private val mdcInterceptor: MdcInterceptor) : WebMvcConfigurer {
override fun addInterceptors(registry: InterceptorRegistry) {
registry.addInterceptor(mdcInterceptor)
}
}
컨트롤러에서는 평범하게 로그만 남기면 됩니다.
@RestController
class TestController {
@GetMapping("/test")
fun test(): String {
log.info("test")
return "test"
}
private companion object {
private val log = getLogger(this::class.java)
}
}
logback.xml 은 다음과 같이 두었습니다
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
이렇게 시작을 하고 나서 http://localhost:8080/test에 요청을 보내면 아래와 같이 로그가 남습니다
열심히 만든 MDC 가 보이지 않는 것을 확인할 수 있습니다.
logback의 기본 설정에서 콘솔에 남길 때 MDC를 남기지 않는 것 때문인데요
콘솔에 남길 때도 MDC를 남기도록 해보겠습니다.
logback.xml 에서
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg[%X{eventId}]%n</pattern>
</encoder>
부분을 추가해 두었습니다
이렇게 로그를 남기게 되면
뒷줄에 이벤트 id 가 남게 되는 것을 볼 수 있습니다
이렇게 eventId를 남겨두게 되면, 추후에 검색을 했을 때 eventId를 기준으로 묶어볼 수 있습니다
추후에 이 MDC 정보를 활용해서 비트를 활용해 ElasticSearch 에 적재를 하게 된다면 검색하기 정말 편한 상태가 됩니다
오늘은 간단하게 MDC에 대해서 알아보았습니다
짧은 글 읽어주셔서 감사합니다
'Spring' 카테고리의 다른 글
Java Dto 를 Kotlin Dto로 변경하면 생기는 문제 (0) | 2024.01.07 |
---|---|
여러분들은 동적 쿼리 어떻게 쓰시나요? (우리 팀에서Jpa Criteria 를 선택한 이유) (2) | 2023.12.24 |
테이블을 병합할 때, Auto Increment를 주의하자 (4) | 2023.10.08 |
공유 자원을 관리하는 bulk head에 대해서 알아보자 (8) | 2023.10.02 |
스프링에서 발생한 에러 로그를 슬랙으로 모니터링하는 방법 (1) | 2023.07.08 |