[Spring Boot] 로그 설정(Logback) 초보자 가이드: 더 이상 println 찍지 마세요

[Spring Boot] 로그 설정(Logback) 초보자 가이드: 더 이상 println 찍지 마세요 이미지 1

안녕하세요. IT 기술 블로거입니다.

신입 개발자 코드를 리뷰할 때 가장 많이 지적하는 부분 중 하나가 바로 System.out.println() 사용입니다.
“로그 찍어서 확인해봤는데요?” 라고 하지만, 운영 서버에서는 콘솔을 실시간으로 보고 있을 수 없습니다. 파일로 남겨야 하고, 에러만 골라서 봐야 하고, 며칠 지난 로그는 지워야 합니다. println은 이 모든 것이 불가능합니다.

Spring Boot는 기본적으로 Logback이라는 강력한 로깅 라이브러리를 내장하고 있습니다. 오늘은 이 Logback을 활용해 제대로 된 로그 시스템을 구축하는 방법을 알아보겠습니다.


1. Spring Boot의 기본 로깅 구조

Spring Boot는 내부적으로 Commons Logging을 사용하지만, 구현체로는 Logback을 기본으로 채택하고 있습니다. 별도의 의존성 추가 없이 spring-boot-starter-web만 있어도 바로 로그를 사용할 수 있습니다.

로그 레벨 (Log Levels)

중요도 순서는 다음과 같습니다. 설정한 레벨보다 높거나 같은 중요도의 로그만 출력됩니다.

  1. TRACE: 가장 상세한 로그. 디버깅 초기에만 사용.
  2. DEBUG: 디버깅용 정보. 개발 단계에서 주로 사용.
  3. INFO: 일반적인 정보. 애플리케이션 상태 변경, 시작/종료 등. (기본값)
  4. WARN: 에러는 아니지만 잠재적 문제가 있는 상황.
  5. ERROR: 요청 처리 실패, 예외 발생 등 심각한 오류.

2. application.yml로 로그 제어하기

가장 간편한 설정 방법입니다. logging 네임스페이스를 사용합니다.

2.1. 패키지별 로그 레벨 설정

전체는 INFO로 찍되, 내가 개발 중인 패키지와 SQL 로그는 DEBUG로 보고 싶다면?

logging:
  level:
    root: info # 전체 기본 레벨
    com.codecamp.myservice: debug # 내 프로젝트 패키지
    org.hibernate.SQL: debug      # 실제 실행되는 쿼리 확인
    org.hibernate.type.descriptor.sql: trace # 쿼리 파라미터 바인딩 확인 (?)

2.2. 로그 파일로 저장하기

콘솔에만 찍으면 서버 재시작 시 날아갑니다. 파일로 남겨야 합니다.

logging:
  file:
    name: logs/application.log # 저장될 파일 경로 및 이름
  # 또는 path만 지정할 수도 있음 (이 경우 spring.log로 생성됨)
  # path: logs/ 

3. Logback 상세 설정 (logback-spring.xml)

application.yml만으로는 “하루에 하나씩 파일 생성”, “30일 지나면 삭제” 같은 디테일한 설정이 어렵습니다. 이때는 src/main/resources/logback-spring.xml 파일을 생성하여 XML 설정을 해야 합니다.

Spring Boot는 logback.xml보다 logback-spring.xml을 더 권장합니다. (Spring의 프로파일 기능을 XML 안에서 쓸 수 있기 때문입니다.)

실무용 Logback 설정 예제

아래 설정은 다음 기능을 포함합니다.
1. 콘솔에는 컬러풀하게 출력.
2. 파일은 날짜별로 app-2023-10-01.log 형태로 롤링(Rolling).
3. 최근 30일치만 보관하고 이전 로그는 자동 삭제.
4. 파일 하나가 10MB를 넘으면 분할.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 로그 패턴 변수 정의 -->
    <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"/>

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

    <!-- 2. 파일 어펜더 (Rolling) -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application.log</file> <!-- 현재 기록 중인 파일 -->

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 날짜별 파일명 패턴 -->
            <fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log</fileNamePattern>

            <!-- 보관 기간: 30일 -->
            <maxHistory>30</maxHistory>

            <!-- 파일 크기 제한 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>

        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- 3. 적용 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

4. 코드에서 로그 사용하기 (@Slf4j)

Lombok 라이브러리를 사용한다면 @Slf4j 어노테이션 하나로 끝납니다.

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j // 자동으로 'log' 객체를 생성해줌
@Service
public class UserService {

    public void login(String username) {
        log.info("로그인 시도: {}", username); // 문자열 연산(+) 대신 {} 사용 권장

        try {
            // 로직...
        } catch (Exception e) {
            log.error("로그인 실패 - 유저: {}", username, e); // 예외 스택트레이스 출력
        }
    }
}

Tip: log.info("msg: " + data) 처럼 문자열 더하기를 쓰지 마세요. 로그 레벨이 비활성화되어 있어도 문자열 연산은 수행되어 메모리를 낭비합니다. log.info("msg: {}", data) 방식을 쓰면 실제 로그가 찍힐 때만 치환되므로 성능상 유리합니다.


[Spring Boot] 로그 설정(Logback) 초보자 가이드: 더 이상 println 찍지 마세요 이미지 2

결론

로그는 “과거를 기록하여 미래의 문제를 해결하는 데이터”입니다.

  1. 개발할 때는 DEBUG 레벨로 흐름을 파악하고,
  2. 운영할 때는 INFO 레벨로 중요한 이벤트만 남기며,
  3. logback-spring.xml을 통해 로그 로테이션(기간/용량 제한) 정책을 반드시 적용하세요. (그렇지 않으면 로그 파일 하나가 수십 기가바이트가 되어 서버가 멈출 수도 있습니다!)

이제 println과는 작별하고, 우아한 로깅 생활을 시작해 보세요.

다음 글에서는 마지막 주제인 “환경 변수로 민감 정보를 안전하게 관리하는 방법”에 대해 알아보겠습니다. DB 비밀번호를 코드에 박아두는 건 이제 그만!

관련 글 보기