4. Trace/Span 생성 로직
전체 흐름
Instrumented method
-> Interceptor.before(...)
-> TraceContext.currentTraceObject()
-> Trace.traceBlockBegin()
-> SpanEventRecorder 기록
-> Interceptor.after(...)
-> Trace.traceBlockEnd()
-> DefaultTrace.storage.store(spanEvent)
-> root request 종료 시 Trace.close()
-> DefaultTrace.storage.store(span)
4.1 Interceptor가 TraceContext를 쓰는 방식
파일:
agent-module/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SpanEventSimpleAroundInterceptorForPlugin.javaagent-module/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/BasicMethodInterceptor.javaagent-module/plugins/jackson/src/main/java/com/navercorp/pinpoint/plugin/jackson/interceptor/ReadValueInterceptor.java
대부분의 plugin interceptor는 공통 base interceptor를 상속한다. 예를 들어 Jackson의 ReadValueInterceptor는 SpanEventSimpleAroundInterceptorForPlugin을 상속하고, doInBeforeTrace(...), doInAfterTrace(...)에서 service type, api, exception, annotation을 기록한다.
ReadValueInterceptor
-> constructor(TraceContext, MethodDescriptor)
-> doInBeforeTrace(recorder, ...)
-> doInAfterTrace(recorder, ...)
공통 base interceptor는 현재 thread의 trace를 얻고 span event block을 연다.
before(...)
-> traceContext.currentTraceObject()
-> trace.traceBlockBegin()
-> doInBeforeTrace(...)
after(...)
-> traceContext.currentTraceObject()
-> doInAfterTrace(...)
-> trace.traceBlockEnd()
4.2 TraceContext와 ThreadLocal Trace
파일:
agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTraceContext.javaagent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTraceFactory.javaagent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultBaseTraceFactory.java
DefaultTraceContext는 plugin interceptor가 보는 facade다. 실제 current trace 관리는 DefaultTraceFactory가 한다.
DefaultTraceContext.currentTraceObject()
-> traceFactory.currentTraceObject()
-> threadLocalBinder.get()
-> sampled trace이면 반환, 아니면 null
새 request 진입점 interceptor는 newTraceObject() 또는 continueTraceObject(traceId)를 호출한다.
newTraceObject()
-> DefaultTraceFactory.checkAndGet()
-> DefaultBaseTraceFactory.newTraceObject()
-> traceSampler.isNewSampled()
-> newDefaultTrace(...) or newLocalTrace(...)
-> threadLocalBinder에 bind
upstream trace header가 있으면 continueTraceObject(traceId)가 같은 방식으로 DefaultTrace를 만든다.
4.3 DefaultTrace에서 span event 저장
파일:
agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.javaagent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorage.java
DefaultTrace.traceBlockBegin()은 SpanEvent를 만들고 call stack에 push한다.
traceBlockBegin()
-> traceBlockBegin0(DEFAULT_STACKID)
-> newSpanEvent(...)
-> callStack.push(spanEvent)
-> WrappedSpanEventRecorder가 spanEvent를 감쌈
traceBlockEnd()는 call stack에서 pop하고 elapsed time을 찍은 뒤 저장소로 넘긴다.
traceBlockEnd()
-> callStack.pop()
-> spanEvent.markAfterTime()
-> storage.store(spanEvent)
-> recorder를 이전 spanEvent로 복원
root trace가 끝나면 close()에서 root span을 저장한다.
close()
-> span.markAfterTime(...)
-> storage.store(span)
-> wrappedSpanEventRecorder.close()
-> storage.close()
-> closeListener.close(...)
BufferedStorage는 span event를 메모리 buffer에 모았다가 chunk로 보내고, root span 저장 시 남은 event를 span에 붙인다.
store(SpanEvent)
-> buffer.put(spanEvent)
-> overflow이면 sendSpanChunk(...)
store(Span)
-> buffer.drain()
-> span.setSpanEventList(...)
-> span.finish()
-> dataSender.send(span)
flush()
-> buffer.drain()
-> sendSpanChunk(...)'개발 메모' 카테고리의 다른 글
| Pinpoint 분석 #7 (0) | 2026.08.04 |
|---|---|
| Pinpoint 분석 #5 (0) | 2026.08.04 |
| Pinpoint 분석 #4 (0) | 2026.08.04 |
| Pinpoint 분석 #3 (0) | 2026.08.04 |
| Pinpoint 분석 #2 (0) | 2026.08.04 |