17-4. 로깅과 트레이싱: 현대적인 시스템 진단법 🟡
학습 목표:
- Rust의 2계층 로깅 아키텍처(파사드와 백엔드)를 이해합니다.
- 단순 텍스트 로그를 넘어 구조화된 데이터를 추적하는
log및tracing생태계를 배웁니다.- C++의
printf나syslog디버깅이 Rust에서 어떻게 더 강력한 관측성(Observability) 도구로 진화했는지 알아봅니다.- 비동기 환경에서의 컨텍스트 추적 기법과 운영 서버용 로깅 전략을 익힙니다.
1. Rust의 2계층 로깅 아키텍처
Rust의 로깅은 크게 **API 정의(Facade)**와 **실제 출력(Backend)**으로 역할이 분리되어 있습니다.
- 파사드(Facade):
log또는tracing크레이트.info!,error!같은 매크로 인터페이스만 제공합니다. 라이브러리 개발자라면 이것만 사용하면 됩니다. - 백엔드(Backend):
env_logger,tracing-subscriber등. 기록된 로그를 콘솔, 파일, 혹은 네트워크로 보낼지 결정합니다. 실행(Binary) 파일에서 한 번만 설정합니다.
use log::{info, warn, error}; fn main() { // 1. 백엔드 초기화 (실행 파일에서 한 번만 수행) env_logger::init(); // 2. 파사드 매크로 사용 (어디서나 호출 가능) info!("시스템 시작"); warn!("센서 응답 지연 발생: 200ms"); error!("치명적 장치 오류!"); }
2. log 크레이트: 가볍고 표준적인 선택
Syslog와 유사한 5단계 레벨(error, warn, info, debug, trace)을 제공하며, 대부분의 오픈소스 라이브러리에서 표준으로 사용합니다.
- 제어:
RUST_LOG환경 변수를 통해 재컴파일 없이 로그 레벨을 실시간으로 조정할 수 있습니다. - 예:
RUST_LOG=debug cargo run(디버그 로그까지 모두 출력)
3. tracing: 구조화된 로그와 스팬(Span)
단순 텍스트 로그는 기계가 분석하기 어렵고 맥락(Context)이 부족한 경우가 많습니다. tracing은 이를 획기적으로 개선합니다.
- 구조화된 필드:
info!(user_id = 42, temp = 75.5, "상태 보고")와 같이 키-값 쌍으로 기록합니다. - 스팬(Span): 특정 실행 구간에 이름을 붙여, 그 안에서 발생하는 모든 로그에 자동으로 컨텍스트(예:
request_id)를 부여합니다. #[instrument]: 함수 위에 붙이기만 하면 호출 인자와 실행 시간을 자동으로 추적하여 기록해 줍니다.
#![allow(unused)] fn main() { use tracing::{info, instrument}; #[instrument] // 함수 호출 시 인자값들을 자동으로 로그 컨텍스트에 포함 fn process_request(id: u32, payload: &str) { info!("데이터 처리 시작"); // 이 로그에는 id가 자동으로 따라붙습니다. } }
💡 실무 운영 전략: 환경별 로깅
- 개발 환경:
RUST_LOG=debug로 상세히 보며 버그를 잡으세요. - 운영 환경:
RUST_LOG=warn으로 설정하여 저장 공간을 절약하고 중요한 경고만 수집하세요. - 분석 시스템 연동:
tracing-subscriber를 JSON 포맷으로 설정하면 Splunk나 ELK 같은 분석 시스템으로 로그를 즉시 전송하여 시각화할 수 있습니다.
📌 요약
- 파사드와 백엔드를 분리하여 유연한 로깅 시스템을 구축하세요.
- 라이브러리 제작 시엔 오직 **
log**나tracingAPI만 사용하세요. - 비동기 앱이나 복잡한 비즈니스 로직에는 **
tracing**의 스팬(Span) 기능을 적극 활용하세요. - 환경 변수 **
RUST_LOG**를 활용해 런타임에 로그 상세도를 제어하세요.