Logback을 통한 Spring boot 로그 관리

코린이·2025년 2월 20일

로그 관리

목록 보기
1/3

문제 인식

현재 학점가방이라는 앱 서비스를 제작 중이며 나는 스프링 부트로 백엔드 개발을 맡고 있다. 지금까지 프론트엔드 개발자들이 API 연결과정에서 로그를 확인해야 할 때 직접 서버에 접속하여 docker logs 명령을 통해 콘솔로만 확인해왔다. 하지만 이 방식은 다음과 같은 문제점이 있었다.

  • 콘솔을 통해서만 확인이 가능하다.
  • 이전의 로그를 파악하기 힘들다.
  • 어플리케이션이 재시작되면 기존의 로그들이 삭제된다.
  • 프론트엔드 팀원이 api 연결하는 과정에서 발생하는 에러를 파악하기 힘들었다.

이러한 이유들로 우리 팀은 좀 더 효율적인 방식으로 로그를 관리하기로 결정하였다.

로그?

로그(log)란 프로그램 또는 시스템에서 발생하는 이벤트, 정보, 상태, 오류 등을 기록한 것을 말하고, 이러한 로그를 생성하고 저장하는 것을 로깅(logging)이라 한다.

로그는 프로그램의 동작을 추적해 문제를 해결하거나 성능을 분석하기 위한 목적으로 활용된다. 이 때문에 로그 관리는 프로그램 개발과 운영에서 아주 중요한 역할을 한다.

사용할 프레임워크

로그를 관리하기 위한 여러 도구들을 찾아보았고 Logback, java.tuil.logging, Log4j2와 같은 같은 선택지가 있었다. 그리고 챗지피티를 활용하여 이들의 장단점을 비교해보았다.

나는 이 중에서는 스프링 부트에서 기본적으로 제공하고 있으며 권장하고 있는 Logback을 사용하기로 결정하였다.

Logback?

Logback은 Java에서 가장 널리 사용되는 로깅 프레임워크 중 하나로, Log4j의 창시자인 Ceki Gülcü가 개발했다. 또한 오랫동안 검증된 Log4j의 아키텍쳐 기반으로 작성되었다.

특징

  • Spring Boot에서 기본 로깅 프레임워크로 사용된다.
  • SLF4J와 함께 동작한다.
  • 로깅을 비동기적으로 처리할 수 있다.
  • 다양한 출력 대상(Appender) 지원한다.
    • 콘솔(Console)
    • 파일(File)
    • 데이터베이스(DB)
    • SMTP(이메일)
    • Syslog(시스템 로그)

로그 레벨

로그라고 해서 모두 다 같은 로그는 아니다. API 요청을 했다는 정보성 로그가 있고, 예상치 못한 오류로 인해 발생한 로그도 있을 것이다. Logback에서는 이러한 로그들을 5단계로 분류하여 출력한다.

분류

Logback에서는 다음과 같은 방식으로 로그 레벨을 분류한다.

Error : 애플리케이션 오류(예외 발생, 장애 감지)

Warn : 예외는 아니지만 문제 가능성이 있는 경우(오래 걸리는 요청, 메모리 부족 경고)

Info : 정상적인 시스템 동작 로그(API 요청, 중요한 비즈니스 이벤트)

Debug : 개발용 상세 로그(서비스 내부 로직)

Trace : 상세한 디버깅용(DB 쿼리 상세 로그)

심각도

심각도는 오른쪽으로 갈수록 높아진다.

Trace > Debug > Info > Warn > Error

출력

모든 로그를 출력하면 로그 파일의 용량이 빠르게 증가하고 서버의 저장공간 부족문제가 발생할 수도 있다. 그래서 일반적으로 특정 레벨 이상의 로그만 출력하도록 설정한다.
예를 들어 로그 레벨을 Info로 설정 시, Info 레벨 이상의 로그레벨(Info, Warn, Error)이 출력된다.

로그 설정 관리

스프링 부트에서는 logback-spring.xml 혹은 application.properties 을 사용하여 로그를 관리할 수 있다. 나는 이 중에서 profile에 따라 다양한 출력 방식을 지정할 수 있는 logback-spring.xml 방식을 사용하기로 결정했다.

먼저 resoures폴더 아래에 logback-spring.xml을 만들어준다.

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <!-- base.xml default.xml 에 존재하는 Log 메시지의 Color 설정 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>

    <!-- 콘솔 로그 패턴 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %clr(%5level) %cyan(%logger) - %msg%n"/>
    <!-- 파일 로그 패턴 -->
    <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger - %msg%n"/>

    <!-- 콘솔 로그 Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- 파일 로그 Appender -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
        <!-- RollingPocliy: 로그가 길어지면 가독성이 떨어지므로 로그를 나눠서 기록하기위한 규칙 -->
        <!-- 로그파일을 크기, 시간 기반으로 관리하기 위한 SizeAndTimeBasedRollingPolicy -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 로그파일명 패턴 -->
            <!-- 날짜별로 기록되며 maxFileSize를 넘기면 인덱스(i)를 증가시켜 새로운 이름의 로그파일에 기록을 이어간다 -->
            <fileNamePattern>./log/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 로그파일 최대사이즈 -->
            <maxFileSize>100MB</maxFileSize>
            <!-- 생성한 로그파일 관리 일수 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>

    <!-- local Profile에서의 로그 설정 -->
    <springProfile name="local">
        <!-- 전체적인 로그는 INFO 레벨 부터 출력 -->
        <root level="INFO">
            <!-- CONSOLE 로그 Appender를 로그 Appender로 등록 -->
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>
    <!-- dev Profile에서의 로그 설정 -->
    <springProfile name="dev">
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>
    <!-- prod Profile에서의 로그 설정 -->
    <springProfile name="prod">
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>

</configuration>

xml 파일 설명

Color 설정

<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
  • 로그 메시지에서 특정 부분을 색상으로 강조하기 위한 설정이다.
  • %clr(...) 패턴을 사용할 때 색상을 지정할 수 있도록 해준다.
  • 콘솔 로그에서 색상을 지원하는 터미널에서만 동작한다.

로그 패턴

<property name="CONSOLE_LOG_PATTERN"
          value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %clr(%5level) %cyan(%logger) - %msg%n"/>
<property name="FILE_LOG_PATTERN" 
          value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger - %msg%n"/>

${CONSOLE_LOG_PATTERN}

  • 콘솔에 출력될 로그 형식을 지정한다.
  • %d{yyyy-MM-dd HH:mm:ss.SSS} → 로그의 날짜 및 시간 (밀리초 단위 포함)
  • [%thread] → 해당 로그를 출력한 스레드명
  • %clr(%5level) → 로그 레벨 (INFO, DEBUG, ERROR 등), 색상을 적용
  • %cyan(%logger) → 로그를 출력한 클래스명을 파란색으로 표시
  • %msg%n → 로그 메시지를 출력하고 개행

${FILE_LOG_PATTERN}

  • 로그 파일에 기록될 형식을 지정한다.
  • 콘솔과 동일하지만 색상 적용이 없다.

콘솔 로그 Appender

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>${CONSOLE_LOG_PATTERN}</pattern>
    </encoder>
</appender>
  • 콘솔(stdout)에 로그를 출력하는 ConsoleAppender를 설정한다.
  • 로그 패턴으로 ${CONSOLE_LOG_PATTERN}을 사용한다.

파일 로그 Appender

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <encoder>
        <pattern>${FILE_LOG_PATTERN}</pattern>
    </encoder>
    <!-- RollingPocliy: 로그가 길어지면 가독성이 떨어지므로 로그를 나눠서 기록하기위한 규칙 -->
    <!-- 로그파일을 크기, 시간 기반으로 관리하기 위한 SizeAndTimeBasedRollingPolicy -->
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <!-- 로그파일명 패턴 -->
        <!-- 날짜별로 기록되며 maxFileSize를 넘기면 인덱스(i)를 증가시켜 새로운 이름의 로그파일에 기록을 이어간다 -->
        <fileNamePattern>./log/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <!-- 로그파일 최대사이즈 -->
        <maxFileSize>100MB</maxFileSize>
        <!-- 생성한 로그파일 관리 일수 -->
        <maxHistory>30</maxHistory>
    </rollingPolicy>
</appender>
  • 로그를 파일로 저장하는 RollingFileAppender를 설정한다.
  • 로그 패턴으로 ${FILE_LOG_PATTERN}을 사용한다.
  • 로그 파일을 자동으로 관리하는 Rolling Policy를 설정한다.
  • fileNamePattern
    • ./log/%d{yyyy-MM-dd}.%i.log
    • 날짜별로 로그 파일을 생성하고, 파일 크기가 maxFileSize를 초과하면 인덱스(%i)를 증가시켜 새 파일을 만든다.
  • maxFileSize
    • 하나의 로그 파일 크기가 100MB를 초과하면 새 파일을 생성한다.
  • maxHistory
    • 로그 파일을 최대 30일간 유지한다.

환경별 로그 관리

<springProfile name="dev">
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</springProfile>
  • dev 프로파일을 사용할 때 로그 설정이다.
  • INFO 이상의 레벨에 대한 로그를 출력한다.
  • 콘솔과 파일에 로그를 출력한다.

실제 사용

스프링부트 앱 메인함수를 다음과 같이 작성하고 실행해보았다.

@SpringBootApplication
public class UniBagSpringBootAppApplication {
    private static final Logger logger = LoggerFactory.getLogger(UniBagSpringBootAppApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(UniBagSpringBootAppApplication.class, args);


        logger.info("애플리케이션이 시작되었습니다.");
        logger.debug("디버그 로그입니다.");
        logger.error("에러 로그입니다.");
    }

}


로컬 환경에서 실행을 하였기 때문에 INFO 이상의 레벨에 해당하는 로그들이 잘 출력되는 것을 알 수 있다.

참고자료

profile
호기심이 많고, 문제를 끝까지 해결하려는 집념이 강한 개발자입니다.

0개의 댓글