v1패키지 생성 후 OrderControllerV1 파일 생성
package study.advanced.app.v1;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
import study.advanced.trace.TraceStatus;
import study.advanced.trace.hellotrace.HelloTraceV1;
@RestController
@RequiredArgsConstructor
public class OrderControllerV1 {
private final OrderServiceV1 orderService;
private final HelloTraceV1 trace;
@GetMapping("/v1/request") //요청이 오면 아래 메서드가 호출
public String request(String itemId) {
TraceStatus status = null;
//예외가 되더라도 로그가 되게끔 try처리
try {
status = trace.begin("OrderController.request()");
orderService.orderItem(itemId);
trace.end(status);
return "ok";
}catch (Exception e) {
trace.exception(status, e);
throw e; // 예외를꼭 다시 던져주어야 한다.
}
}
}
HelloTraceV1 trace : HelloTraceV1을 주입 받는다.
참고로 HelloTraceV1어노테이션을 가지고 있기 때문에 컴포넌트 스캔의 대상이 된다.
따라서 자동으로 스프링 빈으로 등록된다.
trace.begin("OrderController.request()") : 로그를 시작할 때 메시지 이름으로 컨트롤러 이름 + 메서드 이름을 주었다. 이렇게 하면 어떤 컨트롤러와 메서드가 호출되었는지 로그로 편리하게 확인할 수 있다.
단순하게 trace.begin(), trace.end() 코드 두 줄만 적용하면 될 줄 알았지만 예외처리까지 처리해야 하므로 try, catch 코드가 추가된다.
begin() 의 결과 값으로 받은 TraceStatus status 값을 end(), exception()에 넘겨야 한다. 결국 try, catch 블록 모두에게 이 값을 넘겨야 한다. 따라서 try상위에 TraceStatus status 코드를 선언해야 한다. 만약 try안에서 TraceStatus status 를 선언하면 try 블록안에서만 해당 변수가 유효하기 때문에 catch 블록에 넘길 수 없다.
throw e : 예외를 꼭 다시 던져주어야 한다. 그렇지 않으면 여기서 예외를 먹어버리고, 이후에 정상 흐름으로 동작한다. 로그는 애플리케이션에 흐름에 영향을 주면 안된다. 로그 때문에 예외가 사라지면 안된다.
예외처리 발생 로그 처리 잘 된다.
package study.advanced.app.v1;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import study.advanced.trace.TraceStatus;
import study.advanced.trace.hellotrace.HelloTraceV1;
@Service
@RequiredArgsConstructor
public class OrderServiceV1 {
private final OrderRepositoryV1 orderRepository;
private final HelloTraceV1 trace;
public void orderItem(String itemId) {
TraceStatus status = null;
// 예외가 되더라도 로그가 되게끔 try처리
try {
status = trace.begin("OrderService.orderItem()");
orderRepository.save(itemId);
trace.end(status);
} catch (Exception e) {
trace.exception(status, e);
throw e;
}
}
}
package study.advanced.app.v1;
import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;
import study.advanced.trace.TraceStatus;
import study.advanced.trace.hellotrace.HelloTraceV1;
@Repository
@RequiredArgsConstructor
public class OrderRepositoryV1 {
private final HelloTraceV1 trace;
public void save(String itemId) {
TraceStatus status = null;
try {
status = trace.begin("OrderRepository.save()");
//저장로직
if(itemId.equals("ex")) {
throw new IllegalStateException("예외발생");
}
//상품저장에 1초
sleep(1000);
trace.end(status);
}catch(Exception e) {
trace.exception(status, e);
throw e;
}
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
정상처리 됐을 때 로그처리
예외처리로 로그처리
HelloTraceV1 덕분에 직접 로그를 하나하나 남기는 것보다는 편하게 여러가지 로그를 남길 수 있다.
하지만 로그를 남기기 위한 코드가 너무 복잡하지만 일단 나중에 정리하는걸로
아직 구현하지 못한 요구사항은 메서드 호출의 깊이를 표현하고 같은 HTTP요쳥이면 같은 트랜잭션 ID를 남기는 것.
이 기능은 직전 로그의 깊이와 트랜잭션 ID가 무엇인지 알아야 할 수 있는 일
예를 들어서 OrderController.request()에서 로그를 남길때 어떤 깊이와 어떤 트랜잭션 ID를 사용했는지를 그 다음에 로그를 남기는 OrderService.orderItem()에서 로그를 남길 때 알아야한다.
결국 현재 로그의 상태정보인 트랜잭션ID 와 level이 다음으로 전달되어야 한다.
로그에 대한 Context 정보가 필요하다.