배경
기존엔 콘솔과 파일 위주의 단순한 로깅만으로 운영했다.
하지만 모니터링 스택(Loki, Tempo, Prometheus) 을 도입하면서, 단순 로그 수집만으로는 부족하다는 문제가 발생했다.
특히 로그와 트레이스 간의 상관관계를 보장해야 장애 분석과 성능 모니터링이 수월해진다.
이를 위해 로깅 프레임워크와 MDC 전략을 정비했다.
기존의 Logback ADR
- 로깅 프레임워크는 Logback 채택 : https://github.com/f-lab-edu/point-live-young/blob/main/decisions/ADR-006%20%EB%A1%9C%EA%B9%85%20%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%20%EC%84%A0%ED%83%9D%20-%20Logback.md
- 요청 단위 식별은 MDC 기반 추적 : https://github.com/f-lab-edu/point-live-young/blob/main/decisions/ADR-007%20%EC%9A%94%EC%B2%AD%20%EB%8B%A8%EC%9C%84%20%EC%8B%9D%EB%B3%84%EC%9D%84%20%EC%9C%84%ED%95%9C%20MDC%20%EB%A1%9C%EA%B9%85%20%EC%A0%81%EC%9A%A9.md
기존 로깅 설정의 한계
기존의 loback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOGS_ABSOLUTE_PATH" value="./logs"/>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %clr(%-5level) %cyan(%logger) - %msg%n</pattern>
</encoder>
</appender>
<appender name="LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS_ABSOLUTE_PATH}/resource.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>utf8</charset>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %thread [%X{traceId}] %-5level %logger - %msg%n</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOGS_ABSOLUTE_PATH}/%d{yyyy-MM-dd}/resource.%i.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>180</maxHistory>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="LOG"/>
</root>
</configuration>
- %X{traceId}를 활용한 MDC 기반 요청 추적
- 콘솔 + Rolling FileAppender 조합
- 단순 회전 정책 (TimeBasedRollingPolicy + size)
이 방식은 개발 환경에서 로깅 가독성은 확보할 수 있지만, 운영 환경에서는 아래와 같은 한계가 있었다.
- MDC 키 표준화 미비로 인해 트레이스-로그 연계 불안정
- 회전 정 책이 단순하여서 디스크가 늘어날 가능성 존재
- 환경별(개발/운영) 요구사항에 따른 로깅 전략 분리가 미흡
개선 목표
- OTel 에이전트가 자동 주입하는 표준 MDC 키(trace_id, span_id) 활용
- 로그 보존 정책 및 회전 정책 강화로 운영 안정성 확보
- Spring profile(local/prod)에 따라 로깅 전략을 분리해 가독성과 안정성을 모두 챙김
개선된 Logback 설정
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<conversionRule conversionWord="clr"
converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<springProfile name="local">
<property name="LOG_DIR" value="./logs"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %clr(%-5level) %logger
traceId=%X{trace_id:-} spanId=%X{span_id:-} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/app.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger
traceId=%X{trace_id:-} spanId=%X{span_id:-} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/app-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>14</maxHistory>
<totalSizeCap>2GB</totalSizeCap>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</springProfile>
<springProfile name="prod">
<property name="LOG_DIR" value="/opt/app/logs"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/app.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<charset>UTF-8</charset>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger
traceId=%X{trace_id:-} spanId=%X{span_id:-} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/app-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</springProfile>
</configuration>
1. MDC 키 동일 (trace_id, span_id)
OpenTelemetry Java 에이전트는 요청이 들어오면 자동으로 trace_id / span_id를 MDC에 주입 한다.
기존 수동으로 관리하던 %X{traceId} 대신 %X{trace_id}를 그대로 사용하면 로그와 트레이스 간의 상관관계가 자동으로 연결 된다.
%X{trace_id:-} %X{span_id:-}
- :-는 값이 없을 경우 공백으로 처리
- Tempo나 Grafana에서 검색할 때 trace_id 기준으로 손쉽게 조회 가능
2. 회전 및 보존 정책
- 시간 + 크기 기반 회전
- totalSizeCap 설정으로 디스크 용량
- maxHistory로 로그 보관 기간 관리
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/app-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>14</maxHistory>
<totalSizeCap>2GB</totalSizeCap>
</rollingPolicy>
3. Profile 기반 로깅 전략 분리
- local 환경에서는 콘솔 가독성을 위해 컬러 로그를 유지
- prod 환경에서는 파일 로그만 남기고 운영 서버 디스크 정책에 맞춘 회전 설정을 적용
'모니터링 환경 구축하기' 카테고리의 다른 글
| 오픈소스로 모니터링 환경 구축하기(7) - 전체 아키텍처, 흐름도 (0) | 2025.10.11 |
|---|---|
| 오픈소스로 모니터링 환경 구축하기(6) - Grafana (0) | 2025.10.11 |
| 오픈소스로 모니터링 환경 구축하기(5) - Loki + Tempo + Prometheus 조합 (0) | 2025.10.11 |
| 오픈소스로 모니터링 환경 구축하기(4) - Loki & Tempo (0) | 2025.10.11 |
| 오픈소스로 모니터링 환경 구축하기(2) - OpenTelemetry (0) | 2025.10.11 |