targetId 추출 위치에 따라 유연하게 작동하는 로그 설계 패턴(AOP 로깅 실전)

KUN·2025년 6월 16일

계기

@LogWrite(type = COMMENT_CREATED)와 같이 로그 타입을 명시하면,
AOP 기반으로 로그를 가로채어 DB에 저장하는 구조를 도입하려 했다.


위 이미지처럼 userId는 token 내부에서 추출하도록 설계했다.
하지만 targetId의 경우는 상황에 따라 응답, 요청, 또는 토큰에서 가져와야 할 수 있다.

예를 들어,
targetId 를 응답으로 받아야 할수도.

Path로 받아야할 수도 있다.

즉,targetId의 위치는 로그 타입(LogType)에 따라 달라지고,
그에 따라 효율적인 추출 방식도 달라질 수 있다.

그렇다면 이런 분기 처리를 어떤 방식으로 설계하면 가장 효율적일까?


어떤 방법을 써야할까.

Enum 마다 IF 문으로 분기를 처리한다.

가장 먼저 떠올릴 수 있는 방식은
LogType을 기준으로 분기문을 작성해 각각의 ID 추출 위치를 지정하는 것이다.


한계와 목표 재설정

하지만 이 방법에는 분명한 한계가 있다.

  • 로그를 추가할 때마다 분기문을 수정해야 한다.
  • 로직이 길어지고, 응집도가 떨어진다.
  • 실수로 분기를 누락하면, 로그가 기록되지 않는 버그가 발생할 수 있다.

다음과 같이 한번 목표를 재설정하기로 했다.
1. 유지보수가 쉬워야 한다. - AOP 로직이 복잡하지 않고, 변경이 적어야 한다.
2. 확장이 쉬워야 한다. - 새로운 로그 타입을 추가할 때, enum 한 줄만으로 기능을 확장할 수 있어야 한다.

이러한 기준을 바탕으로 구조를 설계하면,
기능을 추가하거나 변경할 때도 유연하고 안정적인 시스템을 만들 수 있다고 생각했다.


전략 만들기

아래와 같은 조건을 바탕으로 로그 처리 전략을 설계하고자 한다:

  1. [Token, Request, Response, 없음] 네 가지 출처는 고정적이다.
    • targetId는 이 네 가지 중 하나에서만 추출된다.
  2. 기존 코드를 변경하지 않는다.
    • 현재 사용 중인 @LogWrite(type = ...) 형식을 그대로 유지한다.
  3. 로직의 흐름이 분기 없이 동작하도록 설계해야 한다.
    • 로그 타입(LogType)만 보고 동작 방식을 유추할 수 있도록 해야 한다.

그렇게 고민을 계속해서 나온 결론은 해당 Id 를 받기 위한 Enum을 새롭게 제작하는 방식이였다.

이렇게 만들고 기존 LogType은

다음과 같이 작성해준다면?
로그를 새롭게 추가할 때 Enum에 추가만 하면된다.


테스트

Response ( 응답에서 targetId 가져오기 )

public class LogResponseTest implements LoggableResponse {
    @Override
    public int getTargetId() {
        return 3;
    }
}

PathVariable ( 요청 Path 에서 특정 값 가져오기 )

모든 값들이 정상적으로 저장됨을 알 수 있다.


아쉬운 점

  1. 더 좋은 방법이 있을 것 같으나, 찾지 못했다. ( 좋은 방법이 있다면 댓글로 알려주세요. )
  2. Response에서 값을 추출하기 위해 DTO가 반드시 LoggableResponse 인터페이스를 구현해야 하는 제약이 있다.
  3. Enum 기반 설계는 분기문을 없애고 확장성은 좋아졌지만, 직관성에서는 다소 불리할 수 있다.

마무리

하지만 그럼에도 이번 설계는 다음과 같은 장점이 있다고 생각한다.

  1. 새로운 로그 타입이 추가되더라도 AOP 로직을 수정할 필요 없이 Enum 한 줄만으로 확장 가능하다.

  2. LogType 자체에 필요한 정보를 명확히 명시함으로써, 로그 설계의 명세화와 문서화가 동시에 이루어졌다.

  3. 테스트를 통해 실제 응답 및 요청으로부터 targetId안정적으로 추출할 수 있음이 검증되었다.

profile
배우노라, 실험하노라, 기록하노라

0개의 댓글