Back-End/Spring Advance & Boot
스프링 고급편 - 로그 추적기
Meluu_
2024. 8. 16. 16:36
✔️ 로그 추적
[TraceId] 깊이 ->(방향) (호출 메서드) (종료시간) (예외)
로그를 남김으로써 어떤 부분에서 문제가 있는지, 예외가 발생하는지 빠르게 확인이 가능하다.
TraceId 와 TraceStatus 클래스를 만들어서
트랜잭션 ID(DB 트랜잭션X) 와 level(깊이), 메세지를 로그로 남긴다.
public class TraceId {
private String id;
private int level;
public TraceId() {
this.id = createId();
this.level = 0;
}
private TraceId(String id, int level) {
this.id = id;
this.level = level;
}
// ab99e16f-3cde-4d24-8241-256108c203a2 //생성된 UUID
// ab99e16f //앞 8자리만 사용
private String createId() {
return UUID.randomUUID().toString().substring(0, 8);
}
public TraceId createNextId() {
return new TraceId(id, level + 1);
}
}
TraceId, 시작 시간, 메세지를 갖는다.
메세지에는 로그를 남길 메서드 명 등등이다.
public class TraceStatus {
private TraceId traceId;
private Long startTimeMs;
private String message;
}
@Slf4j
@Component
public class HelloTraceV2 {
// 처음 시작
public TraceStatus begin(String message);
// 동기화
public TraceStatus beginSync(TraceId beforeTraceId, String message);
// 로그 정상 종료
public void end(TraceStatus status);
// 로그를 예외상황으로 종료
public void exception(TraceStatus status, Exception e);
// 실질적인 로그 종료 처리
private void complete(TraceStatus status, Exception e);
처음 begin은 TraceId를 만들고 시작 시간을 만든 후 로그를 남긴다.
그리고 TraceStatus를 새로 생성하여 반환한다. 이때 traceId, 시작 시간, 메세지를 생성자 파라미터에 넣는다.
public TraceStatus begin(String message);
파라미터로 TraceId를 넘겨서 동기화한다.
// TraceId 동기화
public TraceStatus beginSync(TraceId beforeTraceId, String message);
종료 시간을 측정한 다음 status의 시작시간을 빼서 총 걸린 시간을 얻고
traceId, 로그정보, 걸린 시간을 로그에 출력한다.
private void complete(TraceStatus status, Exception e);
사용
@RequiredArgsConstructor
public class OrderControllerV2 {
private final OrderServiceV2 orderService;
private final HelloTraceV2 trace;
@GetMapping("/v2/request")
public String request(String itemId) {
// 초기화 과정에서 예외가 발생할 수 있기 때문에 여기서 선언
TraceStatus status = null;
try {
status = trace.begin("OrderController.request()");
orderService.orderItem(status.getTraceId(), itemId);
trace.end(status);
return "ok";
} catch (Exception e) {
trace.exception(status, e);
throw e; // 예외를 꼭 다시 던져주어야 한다.
}
}
}
@Service
@RequiredArgsConstructor
public class OrderServiceV2 {
private final OrderRepositoryV2 orderRepository;
private final HelloTraceV2 trace;
public void orderItem(TraceId traceId, String itemId) {
TraceStatus status = null;
try {
status = trace.beginSync(traceId, "OrderService.orderItem()");
orderRepository.save(status.getTraceId(), itemId);
trace.end(status);
} catch (Exception e) {
trace.exception(status, e);
throw e; // 예외를 꼭 다시 던져주어야 한다.
}
}
}
이런식으로 로그를 남기고 TraceId를 파라미터로 넘겨 동기화한다.
문제점
- 사용하기에는 복잡하다.
- 파라미터를 통한 TraceId 동기화로 인한 메서드 수정
- 로그 사용 구분
- 로그 처음 시작 begin(), 이후 beginSync() 호출
- 다른 곳에서 service를 처음 호출하는 상황 발생시 넘길 TraceId가 없음(beginSync()를 호출하는 Service)