FastAPI에서 Sentry APM 비용 절감: 중요한 것만 전송하기
Source: Dev.to
번역을 진행하려면 번역하고자 하는 전체 텍스트(마크다운 형식 포함)를 제공해 주시겠어요? 코드 블록과 URL은 그대로 유지하고, 나머지 내용을 한국어로 번역해 드리겠습니다.
기본 APM의 실제 문제
기본적으로, Sentry APM은 매우 관대합니다:
- 모든 요청이 트랜잭션이 됩니다
- 서브초 수준의 성공적인 호출도 기록됩니다
- 문서 및 스키마 엔드포인트도 추적됩니다
트래픽이 많은 API에서는 이것이 빠르게 다음과 같이 변합니다:
- 대량의 트랜잭션 양
- 더 빠른 할당량 소진
- 인사이트 대신 잡음에 비용을 지불하게 됨
실제로 저는 다음에만 가시성이 필요했습니다:
- 실패하는 요청(5xx)
- 느린 요청
- 비정상적이거나 위험한 모든 것
그 외의 모든 것은 배경 잡음에 불과했습니다.
비용 절감 전략
항상 Sentry에 전송
- 5xx를 반환하는 모든 요청
- 5초 이상 걸리는 모든 요청
Sentry에서 제외
- 빠른
GET / POST / PUT요청 - 3초 이하에 완료되는 성공적인 요청
/docs및/openapi.json엔드포인트
이는 Sentry가 트래픽 양이 아니라 문제에 집중하도록 합니다.
왜 두 개의 미들웨어가 필요한가
SentryAsgiMiddleware – APM 활성화
SentryAsgiMiddleware는 실제로:
- Sentry 트랜잭션을 시작하고 종료합니다
- ASGI 요청 라이프사이클에 연결합니다
- 성능 데이터를 Sentry에 전송합니다
이 미들웨어가 없으면:
- 트랜잭션이 생성되지 않습니다
before_send_transaction이 호출되지 않습니다- APM이 작동하지 않습니다
요약: SentryAsgiMiddleware가 없으면 APM도 없습니다
TimingMiddleware – 인텔리전스 추가
두 번째 미들웨어는 커스텀입니다. 각 요청의 실제 실행 시간을 측정하고 이를 Sentry 스코프에 첨부합니다.
class TimingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start_time = time.time()
response = await call_next(request)
duration = time.time() - start_time
with sentry_sdk.configure_scope() as scope:
scope.set_extra("duration", duration)
return response
필요한 이유:
- 실행 시간은 요청이 “중요한지” 판단하는 데 필요합니다
- Sentry 내부 타이밍은 필터링에 쉽게 활용할 수 없습니다
- 이것이 없으면 비용 제어 로직이 추측에 의존하게 됩니다
이렇게 생각해 보세요:
SentryAsgiMiddleware는 파이프라인입니다TimingMiddleware는 두뇌입니다
전송 전 트랜잭션 필터링
Sentry는 before_send_transaction이라는 훅을 제공합니다. 이 훅은 트랜잭션이 Sentry에 전송되기 직전에 실행되며, 트랜잭션을 삭제할 수 있게 해줍니다.
def before_send_transaction(event, hint):
transaction_name = event.get("transaction", "")
request_method = event.get("request", {}).get("method", "")
status_code = event.get("contexts", {}).get("response", {}).get("status_code", 0)
duration = event.get("extra", {}).get("duration")
# Ignore docs and schema
if "/docs" in transaction_name or "/openapi.json" in transaction_name:
return None
# Always send server errors
if status_code >= 500:
return event
# Drop fast successful requests
if (
request_method in ["GET", "POST", "PUT"]
and 200 <= status_code < 400
and duration
and duration < 3
):
return None
return event
event반환 → 트랜잭션이 전송됩니다None반환 → 트랜잭션이 삭제됩니다
간단하고 예측 가능하며 완전히 여러분의 제어 하에 있습니다.
사용자 지정 필터링을 통한 Sentry 초기화
sentry_sdk.init(
dsn="SENTRY_DSN",
send_default_pii=True,
traces_sample_rate=1.0,
before_send_transaction=before_send_transaction,
)
무작위 샘플링에 의존하는 대신, 이 접근 방식은 실제 동작을 기반으로 한 결정론적 필터링을 제공합니다.
무엇이 바뀌었나요
비용 절감
거래량이 급격히 감소했고, Sentry 사용량도 즉시 감소했습니다.
더 깔끔한 대시보드
느리거나 실패한 요청만 표시되어 디버깅이 쉬워졌습니다.
더 나은 신호
Sentry의 모든 트랜잭션이 이제 “이것은 살펴볼 가치가 있다.” 를 의미합니다.
When This Approach Makes Sense
- API 트래픽이 많음
- 대부분의 요청이 성공적이고 빠름
- 원시 메트릭보다 이슈에 더 신경씀
모든 요청을 영원히 추적하고 싶다면 이 접근 방식은 적합하지 않습니다. 비용을 많이 들이지 않고 유용한 가시성을 원한다면 바로 이 방법입니다.
최종 생각
APM은 청구 대시보드에서 새로운 문제를 만들지 않고, 문제를 찾는 데 도움이 되어야 합니다.
다음 요소들을 결합함으로써:
SentryAsgiMiddleware- 간단한 타이밍 미들웨어
before_send_transaction
Sentry를 **“모두 수집”**에서 **“실제로 중요한 것만 수집”**으로 바꿉니다. 이 작은 변화가 실제 운영 시스템에서 큰 차이를 만들습니다.