@Slf4j
public class ThreadLocalLogTrace implements LogTrace{
private static final String START_PREFIX = "-->";
private static final String COMPLETE_PREFIX = "<--";
private static final String EX_PREFIX = "<X-";
// private TraceId traceIdHolder;
private ThreadLocal<TraceId> traceIdHolder = new ThreadLocal<>();
@Override
public TraceStatus begin(String message) {
syncTraceId();
TraceId traceId = traceIdHolder.get();
Long startTimeMs = System.currentTimeMillis();
log.info("[{}] {}{}", traceId.getId(), addSpace(START_PREFIX, traceId.getLevel()), message);
return new TraceStatus(traceId, startTimeMs, message);
}
private void syncTraceId(){
TraceId traceId = traceIdHolder.get();
if(traceId == null){
traceIdHolder.set(new TraceId());
}else{
traceIdHolder.set(traceId.createNextId());
}
}
@Override
public void end(TraceStatus status) {
complete(status, null);
}
@Override
public void exception(TraceStatus status, Exception e) {
complete(status, e);
}
private void complete(TraceStatus status, Exception e){
Long stopTimeMs = System.currentTimeMillis();
long resultTimeMs = stopTimeMs - status.getStartTimeMs();
TraceId traceId = status.getTraceId();
if(e == null){
log.info("[{}] {}{} time={}ms", traceId.getId(), addSpace(COMPLETE_PREFIX, traceId.getLevel()), status.getMessage(), resultTimeMs);
}else{
log.info("[{}] {}{} time={}ms ex={}", traceId.getId(), addSpace(EX_PREFIX, traceId.getLevel()), status.getMessage(), resultTimeMs, e.toString());
}
releaseTraceId();
}
private void releaseTraceId() {
TraceId traceId = traceIdHolder.get();
if(traceId.isFirstLevel()){
traceIdHolder.remove();
}else{
traceIdHolder.set(traceId.createPreviousId());
}
}
private static String addSpace(String prefix, int level){
StringBuilder sb = new StringBuilder();
for(int i = 0; i< level; i++){
sb.append((i==level - 1) ? "|" + prefix : "| ");
}
return sb.toString();
}
}
비슷하다.
다른 점은, 그저 기본타입 대신 쓰레드로컬 객체로 바뀌었고, 그에 따라 쓰레드로컬을 이용하는 걸로 바뀌었다.
get(), set()은 쓰면 되고,
private void releaseTraceId() {
TraceId traceId = traceIdHolder.get();
if(traceId.isFirstLevel()){
traceIdHolder.remove();
}else{
traceIdHolder.set(traceId.createPreviousId());
}
}
여기 보면 remove()를 한다.
release, 즉 로그추적을 끝내는 로직에서, 만약 현재 TraceId의 레벨이 맨 처음이라면, 내부 로직을 다 돌고 마지막으로 온거니까, remove()해서 삭제를 해 준다.
보통은 쓰레드를 끝낼 때 알아서 처리를 해 줄줄 알았는데, 수동으로 해 줘야 하는 것 같다.
메모리 누수가 발생할 수 있다.
테스트 잘 된다.
'스프링 > 스프링 핵심 원리 - 고급편' 카테고리의 다른 글
17. 템플릿 메서드 패턴 (0) | 2024.01.14 |
---|---|
16. 쓰레드로컬 주의사항 (0) | 2024.01.14 |
14. 쓰레드로컬 예시 (0) | 2024.01.14 |
13. 쓰레드 로컬 소개 (0) | 2024.01.14 |
12. 동시성 문제 예시 (0) | 2024.01.14 |