[Spring] SLF4J로 log 설정하기

jina·2024년 6월 2일

Spring

목록 보기
1/8

Spring Boot에서 SLF4J를 활용해 로그를 남기도록 설정하는 방법을 정리해보았습니다.

📌로그(log)란?

로그는 어플리케이션 상태를 모니터링하고 디버깅에 활용할 수 있는 개념입니다. 어플리케이션의 동작 상태, 이벤트 발생, 에러 등을 기록할 수 있습니다.

  • 로그 레벨(Log Level): TRACE, DEBUG, INFO, WARN, ERROR, FATAL 순으로 심각도가 높아지며, 레벨을 통해 해당 로그의 중요도를 알 수 있습니다.

    💡 WARN vs ERROR
    비즈니스 요구사항이나 서비스의 맥락에 따라 레벨을 결정해야 하지만 대체로 아래처럼 나눌 수 있습니다.
    🔸 경고(warn): 예상 가능한 상황에 적절합니다. 시스템 자체는 정상적으로 작동하고 있는 상태에서 발생한 비정상적적인 상황을 문제로 정의합니다.
    🔸 오류(error): 예상 가능한 상황이나, 비즈니스 로직에 큰 영향을 미치거나 반드시 즉각적으로 조치가 필요한 문제라면 오류가 더 적절합니다.

  • 로거(Loger): 로그 메시지를 생성하는 객체입니다. 로그를 남기기 위해 사용하는 인터페이스나 클래스로 생성한 객체를 의미합니다.
  • 로그 핸들러(Log Handler): 로그가 보여지는 위치를 결정하는 역할을 합니다. 코드에 명시적으로 나타나지는 않지만, 로그가 로그 메시지를 생성하면 보여질 위치를 콘솔이나 원격 서버 등으로 지정할 수 있습니다.
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라는 인터페이스를 사용해서 직접 로그를 기록하고 관리하는 프레임워크입니다.

✅ @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 설정하기

로그의 저장 위치나 형식을 직접 설정하고 싶다면 설정 파일을 통해 로그 관리 정책을 세부적으로 지정하는 것도 가능합니다.

해당 설정 파일의 내용을 작성해 줍니다. 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>
  1. 프로퍼티(변수 값) 설정:로그 파일 경로(저장될 디렉토리)와 로그 레벨(로그 중요도) 등 필요한 내용을 변수로 지정합니다.

  2. Console Appender: 로그를 콘솔에 출력할 형식을 지정합니다.

  3. File Appender: 로그를 파일에 저장할 때 필요한 내용을 설정합니다. 파일 경로, 출력 형식, 롤링 정책 등을 지정할 수 있습니다. 여기서 롤링 정책은 파일 크기나 날짜에 따라 새 로그 파일로 교체하는 정책을 의미합니다.

    💡 롤링 정책이란?
    로그 파일이 일정 크기를 넘어가거나 (크기 기반 롤링) 일정 시간이 지났을 때 (시간 기반 롤링), 새로운 파일로 교체되도록 설정하는 방식입니다. 관리하기 쉽도록 파일을 자동 교체합니다. 로그 파일의 최대 크기, 최대 보관 기간, 파일의 이름 형식 등을 직접 설정할 수 있습니다.

  4. Error Appender: 에러 로그만 분리해서 파일에 저장하는 설정을 할 수 있습니다. 에러 로그는 중요도가 높기 때문에 따로 이렇게 필터를 설정하면 놓치지 않고 관리하는 데 도움이 됩니다.

  5. 루트 로거 설정: 루트 로거의 로그 레벨을 설정하고, 로그를 콘설과 파일에 출력하도록 설정합니다. 위 코드에서는 <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");
  • 에러 발생 안내: 에러가 발생하게 된 원인과 스택 트레이스를 기록합니다. 스택 트레이스는 Exception이나 Error 발생시 문제 발생 원인을 추적하도록 도와주는 정보를 의미합니다.
try {
    // 에러가 발생할 가능성이 있는 코드
} catch (Exception e) {
    log.error("An error occurred", e);
}
  • 중요한 비즈니스 로직 처리 표기: 중요한 데이터 변동이나 처리를 기록합니다. {}안에 데이터가 표기됩니다.
log.info("User {} logged in", username);
profile
오늘의 기록은 내일의 보물

0개의 댓글