어드민 프로젝트

어드민 프로젝트 사용자 행동 로그파일 저장(AOP) - 2

꾸준2 2025. 6. 6. 22:36
 

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">

    <!-- 로그 파일 저장 경로 지정 -->
    <property name="LOG_PATH" value="C:\log" />

    <!-- 로그 패턴 정의 -->
    <property name="LOG_PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />

    <!-- 콘솔 출력 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- USER_ACTION 로그 파일 -->
    <appender name="USER_ACTION_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/user-action.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/user-action.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- USER_ACTION 전용 로거 -->
    <logger name="USER_ACTION" level="INFO" additivity="false">
        <appender-ref ref="USER_ACTION_FILE" />
    </logger>

    <!-- 로그 레벨: 루트 로거는 INFO 이상만 기록 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>

</configuration>

AOP

@Aspect
@Component
public class UserLoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger("USER_ACTION");

    @Pointcut("execution(* com.example.admin_project..controller..*(..))")
    public void userLoggerPointCut() {}

    @Around("userLoggerPointCut()")
    public Object methodUserLogger(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = request.getRemoteAddr();
        String uri = request.getRequestURI();
        String httpMethod = request.getMethod();
        LocalDateTime currentTime = LocalDateTime.now();

        logger.info("URI={}, IP={}, httpMethod={}, currentTime={}", uri, ip, httpMethod, currentTime);

        // 실제 메서드 실행
        return joinPoint.proceed();
    }
}

Logger 직접 생성  VS @Slf4j

1. 로그 분리 목적에 최적화된 명시적 로거 이름 부여

  • LoggerFactory.getLogger("USER_ACTION") 는 "USER_ACTION"이라는 명확한 로거 이름을 직접 지정하는 방식
  • 이를 통해 logback 설정에서 "USER_ACTION" 이름에 대한 별도 로그 파일과 로그 레벨 정책을 독립적으로 관리할 수 있음
  • 반면 @Slf4j는 기본적으로 클래스 이름 기반 로거를 생성하기 때문에
    특정 이름으로 로그 분리 및 별도 관리가 어렵거나 복잡해질 수밖에 없어서 Logger 직접 생성 선택

2. logback 설정에서 손쉬운 로그 경로 및 형식 관리

  • logback.xml에서 "USER_ACTION" 로거에 대해 다음처럼 설정
<logger name="USER_ACTION" level="INFO" additivity="false">
  <appender-ref ref="USER_ACTION_FILE" />
</logger>
  • 이를 통해 사용자 행동 로그를 전용 파일(user-action.log) 에 저장하며
    일반 정보 로그(info.log)와 분리하여 가독성과 관리 편의성을 극대화

결과물