feat(observability): add Sentry error and performance monitoring integration
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
"""
|
||||
Sentry integration utilities for DocuElevate.
|
||||
|
||||
Call ``init_sentry()`` early in your application entry point (before any
|
||||
request handling) to enable error tracking and performance monitoring. The
|
||||
function is a no-op when ``SENTRY_DSN`` is not configured, so it is safe to
|
||||
call unconditionally in all environments.
|
||||
|
||||
Example (FastAPI)::
|
||||
|
||||
from app.utils.sentry import init_sentry
|
||||
init_sentry()
|
||||
|
||||
Example (Celery worker)::
|
||||
|
||||
from app.utils.sentry import init_sentry
|
||||
init_sentry(integrations_extra=["celery"])
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from app.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def init_sentry(*, integrations_extra: list[str] | None = None) -> bool:
|
||||
"""
|
||||
Initialise the Sentry SDK if ``SENTRY_DSN`` is configured.
|
||||
|
||||
Args:
|
||||
integrations_extra: Optional list of additional integration names to
|
||||
activate. Currently recognised values: ``"celery"``. The
|
||||
``FastApiIntegration``, ``SqlalchemyIntegration``, and
|
||||
``LoggingIntegration`` are always included when the SDK is
|
||||
initialised.
|
||||
|
||||
Returns:
|
||||
``True`` when Sentry was successfully initialised, ``False`` otherwise
|
||||
(e.g. DSN not configured or SDK not installed).
|
||||
"""
|
||||
dsn = settings.sentry_dsn
|
||||
if not dsn:
|
||||
logger.debug("Sentry DSN not configured – error monitoring disabled")
|
||||
return False
|
||||
|
||||
try:
|
||||
import sentry_sdk
|
||||
from sentry_sdk.integrations.fastapi import FastApiIntegration
|
||||
from sentry_sdk.integrations.logging import LoggingIntegration
|
||||
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
|
||||
from sentry_sdk.integrations.starlette import StarletteIntegration
|
||||
except ImportError:
|
||||
logger.warning(
|
||||
"sentry-sdk is not installed. Install it with: pip install 'sentry-sdk[fastapi,celery,sqlalchemy]'"
|
||||
)
|
||||
return False
|
||||
|
||||
integrations = [
|
||||
StarletteIntegration(transaction_style="url"),
|
||||
FastApiIntegration(transaction_style="url"),
|
||||
SqlalchemyIntegration(),
|
||||
LoggingIntegration(
|
||||
level=logging.INFO, # Breadcrumbs from INFO+
|
||||
event_level=logging.ERROR, # Send Sentry events for ERROR+
|
||||
),
|
||||
]
|
||||
|
||||
if integrations_extra and "celery" in integrations_extra:
|
||||
try:
|
||||
from sentry_sdk.integrations.celery import CeleryIntegration
|
||||
|
||||
integrations.append(CeleryIntegration(monitor_beat_tasks=True))
|
||||
except ImportError:
|
||||
logger.warning("CeleryIntegration not available – skipping")
|
||||
|
||||
# Clamp sample rates to [0.0, 1.0]
|
||||
traces_rate = max(0.0, min(1.0, settings.sentry_traces_sample_rate))
|
||||
profiles_rate = max(0.0, min(1.0, settings.sentry_profiles_sample_rate))
|
||||
|
||||
version = _get_app_version()
|
||||
|
||||
sentry_sdk.init(
|
||||
dsn=dsn,
|
||||
environment=settings.sentry_environment,
|
||||
release=version,
|
||||
integrations=integrations,
|
||||
traces_sample_rate=traces_rate,
|
||||
profiles_sample_rate=profiles_rate,
|
||||
send_default_pii=settings.sentry_send_default_pii,
|
||||
# Attach a request body snapshot to every event (helps debugging)
|
||||
max_request_body_size="medium",
|
||||
# Keep the SDK from attaching local variable values to stack frames
|
||||
# by default; enable explicitly if needed for deeper debugging.
|
||||
attach_stacktrace=True,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"Sentry initialised (environment=%s, traces_sample_rate=%s)",
|
||||
settings.sentry_environment,
|
||||
traces_rate,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def _get_app_version() -> str | None:
|
||||
"""Return the application version string for Sentry release tracking."""
|
||||
try:
|
||||
return settings.version or None
|
||||
except AttributeError: # pragma: no cover
|
||||
return None
|
||||
@@ -2264,6 +2264,64 @@ SETTING_METADATA = {
|
||||
"required": False,
|
||||
"restart_required": False,
|
||||
},
|
||||
# Observability – Sentry
|
||||
"sentry_dsn": {
|
||||
"category": "Observability",
|
||||
"description": (
|
||||
"Sentry DSN (Data Source Name) URL. When set, runtime errors and "
|
||||
"performance traces are automatically sent to Sentry. "
|
||||
"Leave blank to disable Sentry entirely."
|
||||
),
|
||||
"type": "string",
|
||||
"sensitive": True,
|
||||
"required": False,
|
||||
"restart_required": True,
|
||||
},
|
||||
"sentry_environment": {
|
||||
"category": "Observability",
|
||||
"description": (
|
||||
"Environment label attached to every Sentry event "
|
||||
"(e.g. 'development', 'staging', 'production'). "
|
||||
"Helps you filter events in the Sentry dashboard. Default: 'production'."
|
||||
),
|
||||
"type": "string",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": True,
|
||||
},
|
||||
"sentry_traces_sample_rate": {
|
||||
"category": "Observability",
|
||||
"description": (
|
||||
"Fraction of transactions captured for Sentry performance monitoring (0.0–1.0). "
|
||||
"0.0 disables tracing; 1.0 captures every request. Default: 0.1 (10%)."
|
||||
),
|
||||
"type": "float",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": True,
|
||||
},
|
||||
"sentry_profiles_sample_rate": {
|
||||
"category": "Observability",
|
||||
"description": (
|
||||
"Fraction of profiled transactions sent to Sentry (0.0–1.0). "
|
||||
"Only active when sentry_traces_sample_rate > 0. Default: 0.0 (disabled)."
|
||||
),
|
||||
"type": "float",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": True,
|
||||
},
|
||||
"sentry_send_default_pii": {
|
||||
"category": "Observability",
|
||||
"description": (
|
||||
"Attach personally identifiable information (PII) such as IP addresses "
|
||||
"to Sentry events. Disabled by default for GDPR/CCPA compliance."
|
||||
),
|
||||
"type": "boolean",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": True,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user