Skip to content

Conversation

hyungkishin
Copy link
Collaborator

feat: api 요청 성공/실패 응답값에 모니터링 및 추적이 용이 하도록 traceId 추가

@hyungkishin hyungkishin changed the base branch from feat/fds-doamin-apply to develop August 29, 2025 08:11
Copy link
Collaborator

@flab-true flab-true left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tracerId 관련 코멘트 남깁니다. :-)

override fun doFilterInternal(req: HttpServletRequest, res: HttpServletResponse, chain: FilterChain) {
val traceId = TraceId.generate()
try {
TraceId.put(traceId)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TraceId 객체에는 다른 traceId도 존재하게 되나요?
MDC 객체의 내부 동작 방식을 설명해 주시면 좋겠습니다.

Copy link
Collaborator Author

@hyungkishin hyungkishin Aug 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재는 경량 UUID 기반 TraceId만 지원하지만, 외부 APM 연동 시에는 traceparent/spanId를 수용할 수 있게 확장해야 되는것으로 파악하였습니다.

MDC는 ThreadLocal 기반 Map 입니다.

같은 스레드 안에서만 유효한 Map<String,String>, 요청별 traceId를 로그에 자동으로 붙일 수 있지만, 스레드풀 재사용/비동기에서 오염이나, 유실 위험이 있어 clear/TaskDecorator 적용이 필요 한것으로 확인하였습니다.

추가적으로 아래 method 들도 확인하였습니다.

MDC.put(key, value) = 현재 스레드의 맵에 값 저장

MDC.get(key) = 현재 스레드에서 값 조회

MDC.remove(key) = 특정 key만 제거

MDC.clear() = 현재 스레드의 모든 key-value를 초기화

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MDC는 ThreadLocal을 사용한다고 답을 하셨는데요. api 요청에 대한 thread는 비즈니스 로직을 수행하고 즉시 종료될 것 같습니다. 그런데 MDC.remove(key), MDC.clear() 을 사용하는 이유는 무엇일까요?

@Component
class TraceIdFilter : OncePerRequestFilter() {
override fun doFilterInternal(req: HttpServletRequest, res: HttpServletResponse, chain: FilterChain) {
val traceId = TraceId.generate()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요청에서 매번 traceId를 생성하고 있습니다.
tranceId의 정의는 무엇이고 어떻게 활용되는지 조사를 해주시면 좋겠습니다.
표준 스펙이 있는 것일까요?

import org.slf4j.MDC
import java.util.*

object TraceId {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spring 진영에서 traceId를 관리하는 프로젝트가 존재하는지 조사해 주시면 좋겠습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍 👍

Spring 진영의 traceId 관리 프로젝트에,
Spring Cloud Sleuth 가 존재하는데요, 이부분을 조금더 확인해보니,

과거에는 Spring Cloud Sleuth가 표준처럼 쓰였으나
현재는 Micrometer Tracing(+OpenTelemetry) 로 가는 추세임을 확인하였습니다 :)

예전엔, 프로젝트에서 직접, 경량화된 custom TraceId 방식을 사용하는것을 어렴풋이 보았던것 같아 적용해보았으나, 모니터링 툴을 붙일때 Micrometer Tracing(+OpenTelemetry) 를 권장하는것을 확인하였어요 ( 지속적인 유지보수성 + 관측성 통합 측면 )

백로그에 추가하도록 하겠습니다 !

https://spring-guides.marcuschiu.com/spring-cloud/cloud-sleuth/cloud-sleuth.html?utm_source=chatgpt.com

https://medium.com/dev-spring/why-spring-cloud-sleuth-was-deprecated-and-what-to-use-instead-e98cecd70c86

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 확인 감사합니다. 로그 추적과 분산 트랜잭션의 추적을 위한 구성을 조금 더 개선하면 좋겠습니다.
커스텀한 traceId 설정에서 Micrometer Tracing으로 적용되면 좋겠습니다.

val detail: String? = null,
val additionalInfo: Map<String, Any?>? = null
val additionalInfo: Map<String, Any?>? = null,
val traceId: String? = null,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

traceId를 body에 넣은 이유가 있을까요? 일반적으로는 헤더를 사용하는 것으로 이해하고 있어요.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

트레이싱 ID는 표준적으로 헤더가 맞는 방향이라, 응답 헤더에 X-Trace-Id를 항상 포함하도록 수정하겠습니다 :)

다만, 에러 응답 바디에는 개발 편의를 위해 traceId를 한 번 더 노출하였습니다.

(성공 응답에는 포함하지 않아도 될것 같아요 삭제하도록 하겠습니다)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 감사합니다. 표준 스펙에서는 헤더에 어떤 Key를 사용하는지 같이 정리되면 좋겠습니다.
W3C Trace Spec을 조사해 주시면 좋겠어요.

Copy link
Collaborator Author

@hyungkishin hyungkishin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

매번 감사합니다 :)

val detail: String? = null,
val additionalInfo: Map<String, Any?>? = null
val additionalInfo: Map<String, Any?>? = null,
val traceId: String? = null,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

트레이싱 ID는 표준적으로 헤더가 맞는 방향이라, 응답 헤더에 X-Trace-Id를 항상 포함하도록 수정하겠습니다 :)

다만, 에러 응답 바디에는 개발 편의를 위해 traceId를 한 번 더 노출하였습니다.

(성공 응답에는 포함하지 않아도 될것 같아요 삭제하도록 하겠습니다)

import org.slf4j.MDC
import java.util.*

object TraceId {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍 👍

Spring 진영의 traceId 관리 프로젝트에,
Spring Cloud Sleuth 가 존재하는데요, 이부분을 조금더 확인해보니,

과거에는 Spring Cloud Sleuth가 표준처럼 쓰였으나
현재는 Micrometer Tracing(+OpenTelemetry) 로 가는 추세임을 확인하였습니다 :)

예전엔, 프로젝트에서 직접, 경량화된 custom TraceId 방식을 사용하는것을 어렴풋이 보았던것 같아 적용해보았으나, 모니터링 툴을 붙일때 Micrometer Tracing(+OpenTelemetry) 를 권장하는것을 확인하였어요 ( 지속적인 유지보수성 + 관측성 통합 측면 )

백로그에 추가하도록 하겠습니다 !

https://spring-guides.marcuschiu.com/spring-cloud/cloud-sleuth/cloud-sleuth.html?utm_source=chatgpt.com

https://medium.com/dev-spring/why-spring-cloud-sleuth-was-deprecated-and-what-to-use-instead-e98cecd70c86

override fun doFilterInternal(req: HttpServletRequest, res: HttpServletResponse, chain: FilterChain) {
val traceId = TraceId.generate()
try {
TraceId.put(traceId)
Copy link
Collaborator Author

@hyungkishin hyungkishin Aug 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재는 경량 UUID 기반 TraceId만 지원하지만, 외부 APM 연동 시에는 traceparent/spanId를 수용할 수 있게 확장해야 되는것으로 파악하였습니다.

MDC는 ThreadLocal 기반 Map 입니다.

같은 스레드 안에서만 유효한 Map<String,String>, 요청별 traceId를 로그에 자동으로 붙일 수 있지만, 스레드풀 재사용/비동기에서 오염이나, 유실 위험이 있어 clear/TaskDecorator 적용이 필요 한것으로 확인하였습니다.

추가적으로 아래 method 들도 확인하였습니다.

MDC.put(key, value) = 현재 스레드의 맵에 값 저장

MDC.get(key) = 현재 스레드에서 값 조회

MDC.remove(key) = 특정 key만 제거

MDC.clear() = 현재 스레드의 모든 key-value를 초기화

Copy link
Collaborator

@flab-true flab-true left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍
traceId, spanId는 이후 줌에서 최종 온도감을 맞춰봅시다. Micrometer Tracing를 적용하면 좋겠습니다.
PR 승인을 깜빡하고 못했네요. 지금 승인하였습니다.

@hyungkishin hyungkishin merged commit 123053b into develop Sep 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants