서비스 운영 단계에서는 "무슨 일이 일어났는가"를 빠르게 파악할 수 있는 로깅과 모니터링 체계가 필수입니다. 로깅은 코드가 남긴 사건 기록이고, 모니터링은 그 기록과 지표를 한눈에 보는 대시보드입니다. OpenTelemetry는 로그·메트릭·트레이스를 표준 형식으로 보내는 프로토콜입니다. 이번 편에서는 구조화된 로그, OpenTelemetry 기반 메트릭/트레이스, 사용자 친화적 오류 응답을 구성합니다.
준비: 관측성을 쉬운 말로 이해하기
- 로그는 "발생한 일을 시간순으로 적은 일기"입니다.
- 모니터링은 "이 일기와 숫자를 그래프로 보여주는 게시판"입니다.
- 관측성(observability)은 "문제가 생겼을 때 일기와 게시판만 보고도 원인을 찾을 수 있게 설계하는 것"입니다.
이렇게 기억해 두고 아래 실습을 보면 각 라이브러리가 맡은 역할이 확실히 구분됩니다.
이번 글에서 새로 나오는 용어
- 구조화 로그: 로그를 JSON 같은 일정한 형식으로 남겨 분석 도구가 쉽게 검색·집계할 수 있도록 만든 기록 방식입니다.
- OpenTelemetry(OTel): 로그·메트릭·트레이스를 표준 포맷으로 수집하고 전송하는 개방형 규격으로, Grafana Tempo·Jaeger 같은 백엔드와 연동됩니다.
- structlog: 파이썬 로그를 구조화하기 쉽게 도와주는 라이브러리로, 타임스탬프·레벨·필드를 자동으로 붙입니다.
- JSONResponse: FastAPI가 반환하는 JSON 응답 래퍼로, 사용자 친화적인 오류 메시지를 일정한 형태로 돌려줄 때 사용합니다.
- Prometheus/OTLP: Prometheus는 메트릭을 긁어 가는 모니터링 시스템이고, OTLP(OpenTelemetry Protocol)는 트레이스·로그를 외부 수집기로 보낼 때 사용하는 전송 규격입니다.
실습 카드
- 예상 소요 시간: 55분 (핵심) / +30분 (선택 확장)
- 사전 준비: 18편 성능 코드, 기본 로깅 모듈 사용 경험
- 실습 목표: 구조화 로그와 요청/오류 핸들러를 적용한 뒤, 시간이 남으면 OpenTelemetry·메트릭·알림을 확장한다
핵심 실습: 구조화 로그 + 오류 응답
이번 세션의 필수 범위는 JSON 로그, 요청 로깅 미들웨어, 사용자 친화적 오류 응답입니다. 나머지 모니터링 스택은 선택 확장으로 분리합니다.
구조화 로그(structured log)
structlog를 사용하면 로그를 JSON 형태로 출력해 로그 수집 시스템(ELK, Loki 등)이 분석하기 쉽습니다.
structlog.configure(
processors=[
structlog.processors.TimeStamper(fmt="ISO"),
structlog.processors.add_log_level,
structlog.processors.dict_tracebacks,
structlog.processors.JSONRenderer(),
]
)
logger = structlog.get_logger()
@app.get("/health")
async def health():
logger.info("health_check", status="ok")
return {"status": "ok"}
dict_tracebacks는 예외가 발생했을 때 스택 트레이스를 JSON으로 변환합니다.
요청/응답 로깅 미들웨어
@app.middleware("http")
async def log_requests(request: Request, call_next):
logger.info("request_started", method=request.method, path=request.url.path)
response = await call_next(request)
logger.info(
"request_finished",
method=request.method,
path=request.url.path,
status=response.status_code,
)
return response
민감한 본문을 그대로 기록하면 안 되므로 필요한 메타데이터만 남깁니다.
오류 응답 통일
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
logger.warning("validation_failed", errors=exc.errors())
return JSONResponse(
status_code=422,
content={
"detail": "요청 형식이 올바르지 않습니다.",
"errors": exc.errors(),
},
)
사용자에게는 친절한 메시지를 전달하고, 로그에는 세부 정보를 남깁니다.
(선택) 관측성 스택
핵심 실습이 끝났다면 OpenTelemetry, Prometheus, 대시보드, 알림을 붙여 봅니다. 운영 환경에서만 필요하다면 이후 세션으로 빼도 좋습니다.
(선택) OpenTelemetry 연동
pip install opentelemetry-sdk opentelemetry-instrumentation-fastapi opentelemetry-exporter-otlp
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
provider = TracerProvider()
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint=settings.otel_endpoint))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
app = FastAPI()
FastAPIInstrumentor.instrument_app(app)
OTLP(OpenTelemetry Protocol)은 다양한 백엔드(Tempo, Jaeger, Datadog 등)로 트레이스를 전송할 수 있는 표준입니다.
(선택) 메트릭 노출
prometheus-fastapi-instrumentator를 사용하면 엔드포인트 호출 수, 응답 시간 등을 쉽게 노출할 수 있습니다.
from prometheus_fastapi_instrumentator import Instrumentator
Instrumentator().instrument(app).expose(app)
이렇게 하면 /metrics 엔드포인트에서 Prometheus 형식 데이터를 볼 수 있습니다.
(선택) 운영 대시보드 D2
로그, 메트릭, 트레이스를 하나의 대시보드(Grafana)로 묶으면 장애 상황을 더 빨리 이해할 수 있습니다.
(선택) 에러 알림
- Sentry, Honeybadger, Airbrake 등 SaaS를 연결하면 스택 트레이스를 즉시 알림으로 받을 수 있습니다.
- Slack/Teams 웹훅으로
critical로그가 발생했을 때 메시지를 보내도록 구성합니다.
관찰 가능성(observability)을 구축하면 장애 복구 시간이 크게 단축됩니다. 다음 마지막 편에서는 지금까지 만든 요소를 묶어 미니 서비스를 마무리합니다.
실습
- 따라 하기:
structlog또는 기본 로깅으로 JSON 로그를 남기고 요청/응답 미들웨어와 검증 예외 핸들러를 등록한다. - 확장하기: 선택 섹션을 참고해 OpenTelemetry 또는 Prometheus 노출을 붙이고 간단한 대시보드 흐름을 그림으로 정리한다.
- 디버깅: 오류를 의도적으로 발생시켜 로그/알림 채널에 어떤 필드가 남는지 확인하고 민감 데이터가 노출되지 않도록 필드를 조정한다.
- 완료 기준: 로그 한 줄로 요청 ID·상태를 추적할 수 있고 최소 한 개의 관측성 확장 포인트를 실험했다.
마무리
로그와 모니터링을 코드 단계에서 설계하면 장애 대응 속도가 빨라집니다. 지금 정리한 JSON 로그, 미들웨어, 오류 응답 패턴을 기본값으로 삼고 필요할 때 OpenTelemetry 같은 확장을 더해 보세요.
💬 댓글
이 글에 대한 의견을 남겨주세요