Spring Boot에서 SLF4J를 활용해 로그를 남기도록 설정하는 방법을 정리해보았습니다.
로그는 어플리케이션 상태를 모니터링하고 디버깅에 활용할 수 있는 개념입니다. 어플리케이션의 동작 상태, 이벤트 발생, 에러 등을 기록할 수 있습니다.
💡 WARN vs ERROR
비즈니스 요구사항이나 서비스의 맥락에 따라 레벨을 결정해야 하지만 대체로 아래처럼 나눌 수 있습니다.
🔸 경고(warn): 예상 가능한 상황에 적절합니다. 시스템 자체는 정상적으로 작동하고 있는 상태에서 발생한 비정상적적인 상황을 문제로 정의합니다.
🔸 오류(error): 예상 가능한 상황이나, 비즈니스 로직에 큰 영향을 미치거나 반드시 즉각적으로 조치가 필요한 문제라면 오류가 더 적절합니다.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// 로거의 예시
public class ExampleService {
private static final Logger log = LoggerFactory.getLogger(ExampleService.class);
public void exampleMethod() {
log.info("This is an informational message");
log.debug("This is a debug message");
log.error("This is an error message");
}
}
Spring Boot에서는 기본적으로 Logback을 포함하고 있기 때문에 아래 사용법을 통해 logback을 사용할 수 있습니다. Logback은 SLF4J라는 인터페이스를 사용해서 직접 로그를 기록하고 관리하는 프레임워크입니다.
Lombok이 제공하는 어노테이션을 사용하면 해당 클래스에서 로거 객체를 생성할 필요 없이 로거를 바로 사용할 수 있습니다.
import lombok.extern.slf4j.Slf4j;
@Slf4j // 클래스 이름 위에 어노테이션 사용
public class ExampleService {
public void exampleMethod() {
log.info("information message");
log.debug("debug message");
log.error("error message");
}
}
로그의 저장 위치나 형식을 직접 설정하고 싶다면 설정 파일을 통해 로그 관리 정책을 세부적으로 지정하는 것도 가능합니다.
해당 설정 파일의 내용을 작성해 줍니다. logback-spring.xml 이라는 파일을 resource 폴더 아래 생성한 후 아래처럼 작성할 수 있습니다.
<?xml version="1.0" encoding="UTF-8"?> // 반드시 첫 줄에 작성
<configuration>
<!-- 1. 프로퍼티(변수값) 설정 -->
<property name="LOGS_PATH" value="./logs"/>
<property name="LOGS_LEVEL" value="INFO"/>
<!-- 2. Console Appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 출력 패턴 설정 -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{HH:mm} %-5level %logger{36} - %msg%n</pattern>
</layout>
</appender>
<!-- 3. File Appender -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 로그 파일 경로 설정 -->
<file>${LOGS_PATH}/log_file.log</file>
<!-- 로그 출력 형식 설정 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 롤링 정책 설정 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 로그 파일 이름 패턴 설정 -->
<fileNamePattern>${LOGS_PATH}/%d{yyyy-MM-dd}_%i.log</fileNamePattern>
<!-- 로그 파일의 최대 크기 설정 -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 최대 로그 보관 기간 설정 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
</appender>
<!-- 4. Error Appender -->
<appender name="Error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 로그 파일 경로 설정 -->
<file>${LOGS_PATH}/error_file.log</file>
<!-- 로그 출력 형식 설정 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 롤링 정책 설정 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 로그 파일 이름 패턴 설정 -->
<fileNamePattern>${LOGS_PATH}/%d{yyyy-MM-dd}_%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- threshold filter 를 넣어서 error 이상의 로그만 걸러지도록 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
<!-- 5. 루트 로거 설정 -->
<root level="${LOGS_LEVEL}">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR"/>
</root>
</configuration>
프로퍼티(변수 값) 설정:로그 파일 경로(저장될 디렉토리)와 로그 레벨(로그 중요도) 등 필요한 내용을 변수로 지정합니다.
Console Appender: 로그를 콘솔에 출력할 형식을 지정합니다.
File Appender: 로그를 파일에 저장할 때 필요한 내용을 설정합니다. 파일 경로, 출력 형식, 롤링 정책 등을 지정할 수 있습니다. 여기서 롤링 정책은 파일 크기나 날짜에 따라 새 로그 파일로 교체하는 정책을 의미합니다.
💡 롤링 정책이란?
로그 파일이 일정 크기를 넘어가거나 (크기 기반 롤링) 일정 시간이 지났을 때 (시간 기반 롤링), 새로운 파일로 교체되도록 설정하는 방식입니다. 관리하기 쉽도록 파일을 자동 교체합니다. 로그 파일의 최대 크기, 최대 보관 기간, 파일의 이름 형식 등을 직접 설정할 수 있습니다.
Error Appender: 에러 로그만 분리해서 파일에 저장하는 설정을 할 수 있습니다. 에러 로그는 중요도가 높기 때문에 따로 이렇게 필터를 설정하면 놓치지 않고 관리하는 데 도움이 됩니다.
루트 로거 설정: 루트 로거의 로그 레벨을 설정하고, 로그를 콘설과 파일에 출력하도록 설정합니다. 위 코드에서는 <root level="${LOGS_LEVEL}">로 설정되어 있고, 코드의 가장 상단에 <property name="LOGS_LEVEL" value="INFO"/>로 지정했기 때문에, INFO 이상의 중요도를 가진 로그만 기록되고, DEBUG와 TRACE 메시지는 무시됩니다. 중요한 로그만 남겨서 분석을 쉽게 하도록 하기 위해 이런 필터링을 사용할 수 있습니다.
💡 루트 로거란?
모든 로거의 최상위 로거로서 어플리케이션에서 발생하는 모든 로그 이벤트를 처리합니다. 루트 로거의 로그 레벨이 곧 어플리케이션 전체의 로그 레벨이 됩니다.
properties 파일에서 classpath를 명시하지 않아도 logback-spring.xml이라는 이름으로 파일을 생성했다면 문제가 없지만, 파일명이 다른 경우 아래와 같은 포맷으로 직접 명시해줍니다.
logging.config=classpath:logback-spring.xml
log.info("Application started");
try {
// 에러가 발생할 가능성이 있는 코드
} catch (Exception e) {
log.error("An error occurred", e);
}
log.info("User {} logged in", username);