자바 백엔드 입문 36편 — Logback SLF4J 로깅

2026-05-17자바 백엔드 입문

자바 백엔드 입문 36편. log.info 한 줄 뒷단에 SLF4J·Logback이 어떻게 동작하고 로그 레벨·파일 분리·MDC 트레이스 ID까지 풀어쓴 학습 노트.

📚 자바 백엔드 입문 · 36편 — Logback SLF4J 로깅

이 글은 자바 백엔드 입문 시리즈 59편 중 36편이에요. 시리즈 거의 모든 글에 log.info(...) 가 박혔는데 정작 로깅 자체는 안 다뤘어요. 이번 36편이 그 보강.

로깅이 헷갈리는 이유

자바 진영의 로깅 도구가 너무 많아요 — System.out.println·java.util.logging·Log4j·Log4j2·SLF4J·Logback. 무엇이 무엇의 후속이고, 어느 걸 쓸지 안 잡혀요.

이 글에서는 콘서트 사운드 시스템 비유로 풀어요. SLF4J = "표준 마이크 잭", Logback = "실제 스피커 시스템". 우리 코드는 마이크 잭 하나만 알면 됩니다.

자바 로깅의 표준 — SLF4J + Logback

SLF4J(Simple Logging Facade for Java) = "로깅 라이브러리 표준 인터페이스". 우리 코드는 SLF4J만 쓰고, 실제 구현체는 갈아끼움.

Logback = SLF4J의 가장 대표적 구현체. Spring Boot 기본 포함. 별도 의존성 X.

[우리 코드]
   ↓ log.info("...")  ← SLF4J API
[SLF4J]
   ↓ 위임
[Logback]            ← 실제로 콘솔·파일에 출력

다른 구현체 = Log4j2·java.util.logging. Spring Boot의 기본이 Logback이라 — 별도 설정 안 해도 바로 동작.

log.info 한 줄 사용법

Lombok @Slf4j 가 가장 흔한 패턴.

@Service
@Slf4j                                  // ← log 변수 자동 생성
@RequiredArgsConstructor
public class OrderService {

    public Order placeOrder(OrderRequest req) {
        log.info("주문 생성 시작 — userId={}", req.getUserId());

        try {
            Order order = ...;
            log.info("주문 생성 완료 — id={}, amount={}", order.getId(), order.getAmount());
            return order;
        } catch (Exception e) {
            log.error("주문 생성 실패", e);    // 마지막 인자가 Throwable이면 스택 자동
            throw e;
        }
    }
}

@Slf4j Lombok이 — 자동으로 private static final Logger log = LoggerFactory.getLogger(OrderService.class) 코드를 생성. 우리는 log.info(...) 만 박으면 끝.

로그 레벨 5단계

log.X() 의 X는 5단계.

레벨 의미 사용 시점
ERROR 시스템 오류·예외 예외 발생·복구 불가
WARN 경고 — 문제 가능성 잠재적 이슈
INFO 일반 정보 — 정상 흐름 주요 비즈니스 이벤트
DEBUG 디버그 — 개발 환경 변수값·상세 흐름
TRACE 가장 상세 — 거의 안 씀 깊은 추적

계층 관계 — 운영 환경에 INFO 설정하면 — INFO·WARN·ERROR만 출력, DEBUG·TRACE는 숨김. "INFO 이상만 보여줘" 흐름.

출력 파라미터 — {} placeholder

문자열 연결 "..." + var 대신 {} placeholder 사용.

// ❌ 비효율 (DEBUG 비활성화돼도 문자열 연결 발생)
log.debug("사용자 " + user.getId() + " 처리 중");

// ✓ 효율 (DEBUG 비활성화면 연결 자체가 안 일어남)
log.debug("사용자 {} 처리 중", user.getId());

운영 환경에서 DEBUG 끄면 — 두 번째 방식은 문자열 생성 비용 0. 성능 차이.

application.yml — 로그 레벨 설정

logging:
  level:
    root: INFO                                  # 전체 기본
    com.example.myshop: DEBUG                   # 우리 패키지만 DEBUG
    org.springframework.web: DEBUG              # Spring 웹 로그
    org.hibernate.SQL: DEBUG                    # JPA SQL 보기
    org.hibernate.orm.jdbc.bind: TRACE          # JPA 바인딩 파라미터까지

패키지 단위로 로그 레벨 분기 가능. 개발 환경에서 "우리 코드는 DEBUG, 라이브러리는 INFO" 식 자주 쓰여요.

로그 파일로 출력

기본은 콘솔만. 파일도 같이 출력하려면.

logging:
  file:
    name: logs/myshop.log                      # 단일 파일
    # 또는
    path: logs                                  # 디렉토리 (spring.log 생성)
  logback:
    rollingpolicy:
      max-file-size: 10MB                       # 한 파일 최대
      max-history: 30                            # 보관 일수
      total-size-cap: 1GB

날짜별로 자동 분리 + 오래된 파일 자동 삭제 (롤링). 운영 환경 표준.

logback-spring.xml — 고급 설정

application.yml 이상의 세밀한 설정은 src/main/resources/logback-spring.xml.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/myshop.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/myshop.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d %level [%X{traceId}] %logger - %msg%n</pattern>
        </encoder>
    </appender>

    <springProfile name="prod">
        <root level="INFO">
            <appender-ref ref="FILE"/>
        </root>
    </springProfile>

    <springProfile name="dev">
        <root level="DEBUG">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>
</configuration>

<springProfile> 로 dev·prod 환경 분기. 42편 Profiles 에서 깊이.

MDC — 요청별 추적 ID

여러 요청이 동시에 도는 서버에서 — "이 로그가 어느 요청 거?" 가 헷갈려요. MDC(Mapped Diagnostic Context) 가 답.

@Component
public class TraceIdFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
        String traceId = UUID.randomUUID().toString().substring(0, 8);
        MDC.put("traceId", traceId);

        try {
            chain.doFilter(req, res);
        } finally {
            MDC.clear();                            // 요청 끝나면 정리 필수
        }
    }
}

로그 패턴에 %X{traceId} 박으면 — 모든 로그 줄에 자동으로 traceId 등장. 한 요청의 모든 로그를 검색으로 모을 수 있어요.

2026-05-17 12:30:45 INFO [a3f7b2c1] OrderController - 주문 생성 요청
2026-05-17 12:30:45 INFO [a3f7b2c1] OrderService - 주문 생성 시작 userId=42
2026-05-17 12:30:46 INFO [a3f7b2c1] OrderRepository - INSERT INTO orders
2026-05-17 12:30:46 INFO [a3f7b2c1] OrderController - 응답 완료

a3f7b2c1 한 ID로 "이 요청이 한 묶음" 임을 알 수 있어요. 운영 트러블슈팅의 핵심.

⚠️ 절대 로그에 박으면 안 되는 것

비밀번호·신용카드 번호·주민번호·API 키·JWT 토큰. 한 번 로그에 박히면 수 개월 보관·검색·외부 유출 위험. 마스킹(`****-****-****-1234`) 또는 아예 생략. 한국 회사 보안 사고의 대표 원인.

한 줄 정리 — SLF4J = 자바 로깅 표준 인터페이스, Logback = Spring Boot 기본 구현체. @Slf4j + log.info("{}", var) + 패키지별 레벨 설정. MDC로 요청 추적 ID 표준.

시험 직전 한 번 더 — 로깅 입문자가 매번 헷갈리는 것

  • SLF4J = 자바 로깅 표준 인터페이스 (Facade)
  • Logback = Spring Boot 기본 구현체
  • 다른 구현체 = Log4j2·java.util.logging
  • Spring Boot = 별도 의존성 없이 Logback 자동 포함
  • Lombok @Slf4j = private static final Logger log = ... 자동 생성
  • 로그 레벨 5단계 = ERROR > WARN > INFO > DEBUG > TRACE
  • 운영 = INFO 이상, 개발 = DEBUG
  • {} placeholder 사용 — 문자열 연결보다 효율
  • log.error("...", exception) = 마지막 인자가 Throwable이면 스택 자동
  • application.ymllogging.level.<패키지> = 패키지별 레벨
  • 파일 출력 = logging.file.name 또는 path
  • 롤링 = max-file-size·max-history 자동
  • logback-spring.xml = 세밀한 설정·환경 분기
  • <springProfile> 로 dev·prod 분기
  • MDC = 요청별 컨텍스트 (traceId·userId 등)
  • %X{key} 로 로그 패턴에 박기
  • MDC는 요청 끝나면 MDC.clear() 필수
  • 민감 정보 로그 금지 = 비밀번호·카드·주민번호·토큰
  • 마스킹 필수 또는 아예 생략
  • System.out.println 절대 X — 우리 코드 = log.info
  • 운영 = 파일 + JSON 포맷 + ELK·Datadog 같은 중앙 로그

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!