오봉이와 함께하는 개발 블로그

스프링 핵심 원리 - 고급편_로그 추적기(V1 적용) 본문

BE/Spring

스프링 핵심 원리 - 고급편_로그 추적기(V1 적용)

오봉봉이 2024. 3. 17. 23:31
728x90

로그 추적기 V1 - 적용

OrderControllerV1

@RestController
@RequiredArgsConstructor
public class OrderControllerV1 {
    private final OrderServiceV1 orderService;
    private final HelloTraceV1 trace;

    @GetMapping("/v1/request")
    public String request(@RequestParam("itemId") String itemId) {
        TraceStatus status = null;
        try {
            status = trace.begin("OrderController.request()");
            orderService.orderItem(itemId);
            trace.end(status);
            return "ok";
        } catch (Exception e) {
            trace.exception(status, e);
            throw e; // 꼭 예외를 다시 던져야 함
        }
    }
}
  • begin, end만 처리하면 되는 것이 아니라 예외까지 처리해줘야 한다.
  • begin으로 받은 값을 end, exception에 넘겨야함
  • throw e를 꼭 다시 던져야 함.
    • 그렇지 않으면 catch에서 예외를 먹어버려서 예외 로그만 발생하고 실제 예외가 발생하지 않아 정상 흐름으로 처리된다.

OrderServiceV1

@Service
@RequiredArgsConstructor
public class OrderServiceV1 {
    private final OrderRepositoryV1 orderRepository;
    private final HelloTraceV1 trace;

    public void orderItem(String itemId) {
        TraceStatus status = trace.begin("OrderService.save()");
        try {
            orderRepository.save(itemId);
            trace.end(status);
        } catch (Exception e) {
            trace.exception(status, e);
            throw e;
        }
    }
}

OrderRepositoryV1

@Repository
@RequiredArgsConstructor
public class OrderRepositoryV1 {
    private final HelloTraceV1 trace;

    public void save(String itemId) {
        TraceStatus status = trace.begin("OrderRepositoryV1");
        try {
            if (itemId.equals("ex")) {
                throw new IllegalStateException("예외 발생");
            }
            sleep(1000);
            trace.end(status);
        } catch (Exception e) {
            trace.exception(status, e);
            throw e;
        }
    }

    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

로그

  • 정상 처리
  • [a62df6b0] OrderController.request() [1a80ad36] OrderService.orderItem() [850ca570] OrderRepository.save() [850ca570] OrderRepository.save() time=1001ms [1a80ad36] OrderService.orderItem() time=1001ms [a62df6b0] OrderController.request() time=1002ms
  • 예외 상황
  • [e177fccf] OrderController.request() [1de01dd2] OrderService.orderItem() [a21d166b] OrderRepository.save() [a21d166b] OrderRepository.save() time=0ms ex=java.lang.IllegalStateException: 예외 발생 [1de01dd2] OrderService.orderItem() time=0ms ex=java.lang.IllegalStateException: 예외 발생 [e177fccf] OrderController.request() time=1ms ex=java.lang.IllegalStateException: 예외 발생 Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.IllegalStateException: 예외 발생] with root cause

java.lang.IllegalStateException: 예외 발생

~

  • 현재 트랜잭션 ID가 다른 부분과 level 관련한 부분은 개발되지 않아 각 메서드끼리만 ID가 같고, 모든 메서드의 레벨이 같은 상태

요구사항

완성된 요구사항은 아래와 같다.

  • 모든 Public 메서드의 호출과 응답을 로그로 출력
  • 애플리케이션의 흐름을 방해햐면 안됨
    • 로그를 남긴다고 해서 비즈니스 로직 동작에 영향을 주면 안된다.
  • 기능
    • 메서드 호출에 걸린 시간
    • 정상 흐름과 예외 흐름 구분
      • 예외 발생 시 예외 정보가 남아야 함
    • 메서드 호출의 깊이 표현
    • HTTP 요청을 구분
      • HTTP 요청 단위로 특정 ID를 남겨서 어떤 HTTP 요청에서 시작된 것인지 명확하게 구분 가능해야 함
      • 트랜잭션 ID (DB 트랜잭션이 아님)를 통해 구분한다.
        • HTTP 요청이 시작해서 끝날 때 까지 하나의 트랜잭션

 

출처: 김영한 지식공유자의 스프링 핵심 원리 고급편

728x90
Comments