에러에 상태에 따라서 로깅 레벨을 조절해보자
TL; DR
선호하진 않을 방식일순 있으나, 에러에 대한 익셉션이 하나로 결정되어진 경우 ControllerAdvicer의 로그레벨을 무조건 한 가지로 고정해버리면 간혹 이 에러에 대한 오류를 지정하기가 힘들어진다. 차라리 이럴때는 Exception에 로그레벨을 넣고, Sl4fj에서 제공하는 makerLoggingEventBuilder기능을 활용하면 좋다. 익셉션에 로그레벨을 프로퍼티로 넣고, 꺼내서 해당하는 어드바이저의 레벨과 상관없이 자동으로 출력하자
1. 이런 상황이 만들어지게된 배경
에러 로그를 Exception별로 만들게 되면, 로깅을 우리팀에서는 ControllerAdvicer에서 처리하는 방식으로 구현했었다. 근데 이렇게 하면 문제가 되는 지점이 공통분모로 묶어둔 익셉션이 자주 에러를 발생해서 가끔 에러가 과하게 모니터링 되는 경우가 있다.
관제상 오류를 우리는 error로 레벨링을 하고 있는데, 단순 오류로 판단하던 것들이 간혹 사용자의 오류를 통해서 많이 발생하는 경우가 생길 수 있다. 그럴때 이걸 또 Exception을 쪼개서 나누면 ControllerAdvicer의 코드가 늘어나고 관리 포인트가 늘어난다고 생각해서, 해당하는 관리 포인트를 내가 익셉션 자체에 Logging Level을 추가하고 그 로깅레벨에 따라서 컨트롤러 어드바이저에서 셋업을 하면 좋겠다 생각했다.
2. 예제 상황
다음 처럼 Exception과 Advicer를 구성하면 화면처럼 나오게 된다.
@Slf4j
@ControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(BaseException.class)
public ResponseEntity<String> handlerBaseException(BaseException be) {
log.error("error {}", be.getMessage());
return ResponseEntity.ok("오류");
}
}
public class BaseException extends RuntimeException {
public BaseException(String number) {
super(number);
}
}
에러가 발생하게 되면 굉장히 모니터링시 오류가 많이 발생할 수 있다.
물론 당연히 케이스바이케이스겠지만, 해당하는 상황이 너무 잦아서 혹시 오류가 많이 난다면 오류의 빈번함은 가끔 관제를 너무 쉽게 본다는 지점이 생기는게 문제다.
즉, 이러면 해당하는 Exception을 분리하는것도 방법이겠지만, Slf4j에서 제공하는 함수를 통해서 해결하는 것도 좋은 방법이다.
3. log.makeLoggingEventBuilder를 사용해보자
@Sl4fj
의 기능에는 makerLoggingEventBuilder기능이 존재하는데, 해당하는 빌더는 Builder params에는 로그레벨이... 뒤에는 어떤 로깅을 할지에 대해서 적혀있는 터라, 해당하는 로깅 레벨을 우리가 어플단에서 조정이 가능하다.
즉, 이렇게 수정이 가능하면 Exception에 가볍게 logging level만 넣어준다면 해당하는 오류 조정을 어플리케이션단에서만 할 수 있기 때문에 굳이 불필요한 Exception을 구성하지 않아도 된다는점이 편하다.
물론 혹자는 Exception을 만드는 편이 나을 수도 있다고 보지만, 사실 우리가 전반적인 시스템에서 나눌 수 없는 혹은 너무 평범해서 이걸 쪼개 놓는게 맞는지 헛갈리는 순가이 있을 수도 있어서 해당하는 방식을 한번 고려해볼만한 대상이라고도 본다
아래 예제처럼 builder를 만들어주면log.makeLoggingEventBuilder(Level.DEBUG).log("error level control :: {}", be.getMessage());
아래처럼 Debug 레벨의 로깅이 찍힌것을 볼 수 있다.
4. 결론?
그럼 BaseException과 같은 Custom Exception Class에 Logging Level을 넣어주기만 하면되는데, 해당하는 makerLoggingEventBuilder
의 경우는 Level Class를 사용하면 된다. 물론 이경우 SL4FJ에 너무 종속된다는 점이 있긴하지만, 기본적으로 로거 클래스를 바꿀일은 크게 없다고 본다. (물론 엄청 엄근진 하게 보자면 꼭 좋은건 아니지만...)
다음처럼 코드를 구성해보자!
//실제 오류가 나는 부분
public void makeException() {
throw new BaseException("1134", Level.TRACE);
}
@Getter
public class BaseException extends RuntimeException {
private Level level = Level.ERROR;
public BaseException(String number) {
super(number);
}
public BaseException(String number, Level level) {
super(number);
this.level = level;
}
}
/// 오류가 나는 부분을 이렇게 수정하면?
@ExceptionHandler(BaseException.class)
public ResponseEntity<String> handlerBaseException(BaseException be) {
log.makeLoggingEventBuilder(be.getLevel()).log("error level control :: {}", be.getMessage());
return ResponseEntity.ok("오류");
}
짜잔 다음과 같이 오류가 내가 설정한 Exception별로 오류가 나오게 됩니다~
또한 기본값으로 Error를 정해두고, 해당하는 에러값이 아닌 경우 생성자를 통해서 넣어주기만 하면 되므로 해당하는 로깅을 강제할 수도 있습니다.
'Spring' 카테고리의 다른 글
@AuthenticationPrincipal과 getAuthentication()에서 가져온 principal의 다른점은 있을까? (1) | 2024.10.27 |
---|---|
Transactional의 Self Injection이 올바른가 (0) | 2024.06.22 |
@JsonInclude란? (0) | 2024.02.04 |
부모 - 자식 관계에 있는 DTO를 효과적으로 표현하는 JsonTypeInfo Deduction기능을 알아보자. (1) | 2024.01.21 |
테스트 코드를 짜고는 싶은데, 테스트 실패시 빌드 실패가 걱정된다면? (0) | 2023.09.02 |