관측성
masterror는 텔레메트리를 오류 수명 주기의 일부로 취급합니다. 각 AppError는
더티 플래그를 추적하며, 텔레메트리는 상태 변화당 한 번 발행됩니다 — 생성 시,
변경 후, 또는 오류가 전송 경계(Axum IntoResponse, Actix
error_response(), tonic Status 변환)를 넘을 때. 수동으로 호출할 일은
거의 없습니다.
기능 플래그
| 기능 | 추가 내용 |
|---|---|
tracing | 오류당 구조화된 tracing 이벤트, log-mdc를 통한 trace_id |
metrics | metrics 크레이트를 통한 error_total{code,category} 카운터 |
backtrace | RUST_BACKTRACE로 제어되는 지연 std::backtrace::Backtrace 캡처 |
colored | TTY 감지가 포함된 ANSI 컬러 터미널 스타일링 |
[dependencies]
masterror = { version = "0.28", features = ["tracing", "metrics", "backtrace"] }
Tracing
tracing이 활성화되면 각 오류는 타깃 masterror::error로 ERROR 레벨
이벤트를 하나 발행합니다:
| 필드 | 내용 |
|---|---|
code | AppCode 문자열, 예: NOT_FOUND |
category | AppErrorKind 레이블, 예: Database |
message | 공개 메시지 (있는 경우) |
retry_seconds | 재시도 힌트 (설정된 경우) |
redactable | 전송 경계에서 메시지가 리덕션되는지 여부 |
metadata_len | 첨부된 메타데이터 필드 수 |
www_authenticate | 인증 챌린지 (설정된 경우) |
trace_id | log-mdc 컨텍스트 키 trace_id에서 가져옴 (존재하는 경우) |
발행은 subscriber를 인식합니다: 해당 타깃의 ERROR 레벨 이벤트에 관심 있는 subscriber가 없으면 이벤트는 보류 상태로 남아 다음 플러시에서 재시도되므로, subscriber가 늦게 설치되어도 아무것도 손실되지 않습니다.
오류를 요청과 연관시키려면 요청 미들웨어에서 MDC에 trace ID를 저장하세요:
log_mdc::insert("trace_id", request_id);
키가 설정된 동안 생성된 모든 오류는 이벤트에 해당 값을 포함합니다.
메트릭
metrics가 활성화되면 새로 더티 상태가 된 각 오류는 다음을 증가시킵니다:
error_total{code="NOT_FOUND", category="NotFound"}
두 레이블 모두 안정적인 문자열(AppCode::as_str()과 AppErrorKind
레이블)이므로, 도메인 타입을 리팩터링해도 대시보드와 알림이 유지됩니다.
metrics 레코더(Prometheus, StatsD 등)는 평소처럼 연결하면 됩니다.
masterror는 metrics::counter!만 사용합니다.
백트레이스
backtrace가 활성화되면 Backtrace 스냅샷은 텔레메트리가 플러시될 때
지연 캡처됩니다 — 생성할 때마다 캡처되지 않습니다. 캡처는
RUST_BACKTRACE로 제어됩니다: 미설정, 빈 값, 0, off, false는
비활성화하고, 그 외 값은 활성화합니다. 이 설정은 한 번 읽혀 프로세스별로
캐시됩니다.
#[cfg(feature = "backtrace")] {
use masterror::AppError;
let err = AppError::internal("db down");
if let Some(bt) = err.backtrace() {
eprintln!("{bt}");
}
}
AppError::with_backtrace(backtrace)로 미리 캡처한 트레이스를 첨부할 수도
있으며, 이는 지연 캡처보다 우선합니다.
.log()를 통한 수동 플러시
생성자와 변환은 텔레메트리를 자동으로 발행합니다. 오류를 변경한 후(필드 추가, 재시도 힌트 변경) 재발행을 강제할 수 있습니다:
use masterror::{AppError, field};
let err = AppError::service("upstream degraded")
.with_field(field::str("upstream", "billing"));
err.log();
log()는 상태별로 멱등합니다: 마지막 발행 이후 변경된 것이 없으면 아무것도
하지 않습니다. HTTP/gRPC 어댑터도 경계에서 같은 방식으로 플러시하므로,
생성되고 보강된 뒤 Axum 핸들러에서 반환되는 오류는 상태당 한 번 —
생성 시 한 번, 보강된 상태에 대해 경계에서 한 번 — 발행되며, 같은 상태에 대해
두 번 발행되는 일은 없습니다.
체인 검사
기능과 무관하게 AppError는 로그 파이프라인에 필요한 도구를 노출합니다:
#[cfg(feature = "std")] {
use std::io::Error as IoError;
use masterror::AppError;
let err = AppError::internal("db down").with_context(IoError::other("disk offline"));
assert_eq!(err.chain().count(), 2);
let _root = err.root_cause();
assert!(err.metadata().is_empty());
}
metadata().iter_with_redaction()은 (key, value, policy) 트리플을
산출하므로 로깅 계층이 필드 리덕션을 존중할 수 있습니다 —
컨텍스트와 메타데이터를 참조하세요.
컬러 터미널 출력
colored 기능은 CLI 도구를 위한 masterror::colored::style을 추가합니다.
색상은 stderr가 TTY이고, NO_COLOR가 설정되지 않았으며, TERM이 dumb가
아니고, 터미널이 ANSI를 지원할 때만 적용됩니다. 그렇지 않으면 텍스트가
그대로 통과합니다. 감지 결과는 프로세스별로 캐시됩니다.
| 함수 | 스타일 | 용도 |
|---|---|---|
error_kind_critical | 빨간색 | 치명적 실패 종류 |
error_kind_warning | 노란색 | 복구 가능/경고 종류 |
error_code | 청록색 | 기계 코드 |
error_message | 밝은 흰색 | 메인 메시지 |
source_context | 흐리게 | 보조/소스 정보 |
metadata_key | 초록색 | 구조화된 필드 이름 |
#[cfg(feature = "colored")] {
use masterror::colored::style;
eprintln!(
"{}: {}",
style::error_code("ERR_DB_001"),
style::error_message("Database connection failed")
);
}
실행 가능한 데모는
examples/colored_cli.rs를
참조하세요.
함께 보기: 기능 플래그 · 컨텍스트와 메타데이터 · 웹 프레임워크 · 모범 사례