오봉이와 함께하는 개발 블로그
스프링 핵심 원리 - 고급편_로그 추적기(V2 파라미터로 동기화 개발) 본문
728x90
로그 추적기 V2 - 파라미터로 동기화 개발
- 트랜잭션 ID와 메서드 호출의 깊이를 표현하는 가장 단순한 방법은 첫 로그에서 사용한 ID와 level을 다음 로그에 넘겨주는 것이다.
- 현재 로그 상태 정보인 ID와 level은 TraceId에 있다.
- 따라서 TraceId를 다음 로그로 넘기면 된다.
HelloTraceV2
@Slf4j
@Component
public class HelloTraceV2 {
private static final String START_PREFIX = "--->";
private static final String COMPLETE_PREFIX = "<---";
private static final String EX_PREFIX = "<X-";
public TraceStatus begin(String message) {
TraceId traceId = new TraceId();
long startTimeMs = System.currentTimeMillis();
log.info("[{}] {}{}", traceId.getId(), addSpace(START_PREFIX, traceId.getLevel()), message);
return new TraceStatus(traceId, startTimeMs, message);
}
public TraceStatus beginSync(TraceId beforeTraceId, String message) {
TraceId nextId = beforeTraceId.createNextId();
long startTimeMs = System.currentTimeMillis();
log.info("[{}] {}{}", nextId.getId(), addSpace(START_PREFIX, nextId.getLevel()), message);
return new TraceStatus(nextId, startTimeMs, message);
}
public void end(TraceStatus status) {
complete(status, null);
}
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());
}
}
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();
}
}
- Request를 받는 첫 요청에는
begin()
을 사용하고 이후 요청부터beginSync()
를 사용하면 된다.
테스트 코드
public class HelloTraceV2Test {
@Test
void begin_enc() {
HelloTraceV2 trace = new HelloTraceV2();
TraceStatus status1 = trace.begin("hello1");
TraceStatus status2 = trace.beginSync(status1.getTraceId(), "hello2");
trace.end(status2);
trace.end(status1);
}
@Test
void begin_exception() {
HelloTraceV2 trace = new HelloTraceV2();
TraceStatus status1 = trace.begin("hello1");
TraceStatus status2 = trace.beginSync(status1.getTraceId(), "hello2");
trace.exception(status2, new IllegalStateException());
trace.exception(status1, new IllegalStateException());
}
}
로그
[29cbc39a] hello1
[29cbc39a] |--->hello2
[29cbc39a] |<---hello2 time=0ms
[29cbc39a] hello1 time=1ms
[1547c884] hello1
[1547c884] |--->hello2
[1547c884] |<X-hello2 time=1ms ex=java.lang.IllegalStateException
[1547c884] hello1 time=8ms ex=java.lang.IllegalStateException
요구사항
완성된 요구사항은 아래와 같다.
모든 Public 메서드의 호출과 응답을 로그로 출력애플리케이션의 흐름을 방해햐면 안됨로그를 남긴다고 해서 비즈니스 로직 동작에 영향을 주면 안된다.
- 기능
메서드 호출에 걸린 시간정상 흐름과 예외 흐름 구분예외 발생 시 예외 정보가 남아야 함
메서드 호출의 깊이 표현HTTP 요청을 구분HTTP 요청 단위로 특정 ID를 남겨서 어떤 HTTP 요청에서 시작된 것인지 명확하게 구분 가능해야 함트랜잭션 ID (DB 트랜잭션이 아님)를 통해 구분한다.HTTP 요청이 시작해서 끝날 때 까지 하나의 트랜잭션
출처: 김영한 지식공유자의 스프링 핵심 원리 고급편
728x90
'BE > Spring' 카테고리의 다른 글
스프링 핵심 원리 - 고급편_쓰레드 로컬(필드 동기화 - 개발) (0) | 2024.03.17 |
---|---|
스프링 핵심 원리 - 고급편_로그 추적기(V2 적용) (1) | 2024.03.17 |
스프링 핵심 원리 - 고급편_로그 추적기(V1 적용) (0) | 2024.03.17 |
스프링 핵심 원리 - 고급편_로그 추적기(요구사항 분석, 프로토타입 개발 V1) (0) | 2024.03.17 |
Spring Framework - STOMP (convertAndSend vs convertAndSendToUser) (0) | 2024.02.22 |
Comments