Merge pull request #239 from plastic-labs/rajat/centralize-sentry-config

feat: filter validation error from sentry. centralize config
This commit is contained in:
Rajat Ahuja 2025-10-15 16:43:51 -04:00 committed by GitHub
commit 3ba63edad2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 79 additions and 36 deletions

View File

@ -28,6 +28,7 @@ from src.dreamer.dream_scheduler import (
set_dream_scheduler,
)
from src.models import QueueItem
from src.sentry import initialize_sentry
from src.utils.work_unit import parse_work_unit_key
from src.webhooks.events import (
QueueEmptyEvent,
@ -68,15 +69,7 @@ class QueueManager:
# Initialize Sentry if enabled, using settings
if settings.SENTRY.ENABLED:
sentry_sdk.init(
dsn=settings.SENTRY.DSN,
enable_tracing=True,
release=settings.SENTRY.RELEASE,
environment=settings.SENTRY.ENVIRONMENT,
traces_sample_rate=settings.SENTRY.TRACES_SAMPLE_RATE,
profiles_sample_rate=settings.SENTRY.PROFILES_SAMPLE_RATE,
integrations=[AsyncioIntegration()],
)
initialize_sentry(integrations=[AsyncioIntegration()])
def add_task(self, task: asyncio.Task[None]) -> None:
"""Track a new task"""

View File

@ -7,18 +7,15 @@ from typing import TYPE_CHECKING
import sentry_sdk
from fastapi import FastAPI, Request, Response
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi_pagination import add_pagination
from src import prometheus
from src.utils.logging import get_route_template
if TYPE_CHECKING:
from sentry_sdk._types import Event, Hint
from pydantic import ValidationError
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.starlette import StarletteIntegration
from src import prometheus
from src.config import settings
from src.db import engine, request_context
from src.exceptions import HonchoException
@ -31,6 +28,11 @@ from src.routers import (
workspaces,
)
from src.security import create_admin_jwt
from src.sentry import initialize_sentry
from src.utils.logging import get_route_template
if TYPE_CHECKING:
from sentry_sdk._types import Event, Hint
def get_log_level() -> int:
@ -68,30 +70,31 @@ async def setup_admin_jwt():
print(f"\n ADMIN JWT: {token}\n")
def before_send(event: "Event", hint: "Hint | None") -> "Event | None":
"""Filter out events raised from known non-actionable exceptions before Sentry sees them."""
if not hint:
return event
exc_info = hint.get("exc_info")
if not exc_info:
return event
_, exc_value, _ = exc_info
if isinstance(exc_value, HonchoException):
return None
# Filters out ValidationErrors and RequestValidationErrors (typically coming from Pydantic)
if isinstance(exc_value, ValidationError | RequestValidationError):
logger.info(f"Filtering out validation error from Sentry: {exc_value}")
return None
return event
# Sentry Setup
SENTRY_ENABLED = settings.SENTRY.ENABLED
if SENTRY_ENABLED:
def before_send(event: "Event", hint: "Hint") -> "Event | None":
if "exc_info" in hint:
_, exc_value, _ = hint["exc_info"]
# Filter out HonchoExceptions from being sent to Sentry
if isinstance(exc_value, HonchoException):
return None
return event
# Sentry SDK's default behavior:
# - Captures INFO+ level logs as breadcrumbs
# - Captures ERROR+ level logs as Sentry events
#
# For custom log levels, use the LoggingIntegration class:
# sentry_sdk.init(..., integrations=[LoggingIntegration(level=logging.INFO, event_level=logging.ERROR)])
sentry_sdk.init(
dsn=settings.SENTRY.DSN,
traces_sample_rate=settings.SENTRY.TRACES_SAMPLE_RATE,
profiles_sample_rate=settings.SENTRY.PROFILES_SAMPLE_RATE,
before_send=before_send,
initialize_sentry(
integrations=[
StarletteIntegration(
transaction_style="endpoint",
@ -100,6 +103,7 @@ if SENTRY_ENABLED:
transaction_style="endpoint",
),
],
before_send=before_send,
)

46
src/sentry.py Normal file
View File

@ -0,0 +1,46 @@
"""Sentry initialization and configuration."""
from __future__ import annotations
import logging
from collections.abc import Sequence
from typing import TYPE_CHECKING
import sentry_sdk
from src.config import settings
if TYPE_CHECKING:
from sentry_sdk._types import EventProcessor
from sentry_sdk.integrations import Integration
logger = logging.getLogger(__name__)
# Sentry SDK's default behavior:
# - Captures INFO+ level logs as breadcrumbs
# - Captures ERROR+ level logs as Sentry events
#
# For custom log levels, use the LoggingIntegration class:
# sentry_sdk.init(..., integrations=[LoggingIntegration(level=logging.INFO, event_level=logging.ERROR)])
def initialize_sentry(
*,
integrations: Sequence[Integration],
before_send: EventProcessor | None = None,
) -> None:
"""Initialize Sentry SDK with project settings.
Args:
integrations: Sentry SDK integrations to enable (e.g., Starlette, FastAPI).
before_send: Optional event filter callback to suppress specific exceptions.
"""
sentry_sdk.init(
dsn=settings.SENTRY.DSN,
enable_tracing=True,
release=settings.SENTRY.RELEASE,
environment=settings.SENTRY.ENVIRONMENT,
traces_sample_rate=settings.SENTRY.TRACES_SAMPLE_RATE,
profiles_sample_rate=settings.SENTRY.PROFILES_SAMPLE_RATE,
before_send=before_send,
integrations=integrations,
)