1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2025-12-20 10:28:45 +00:00
Files
supervisor/supervisor/utils/sentry.py
Stefan Agner deac85bddb Scrub WiFi fields from Sentry events (#6048)
Make sure WiFi fields are scrubbed from Sentry events to prevent
accidental exposure of sensitive information.
2025-07-29 17:42:43 +02:00

89 lines
3.1 KiB
Python

"""Utilities for sentry."""
import asyncio
from functools import partial
import logging
from aiohttp.web_exceptions import HTTPBadGateway, HTTPServiceUnavailable
import sentry_sdk
from sentry_sdk.integrations.aiohttp import AioHttpIntegration
from sentry_sdk.integrations.atexit import AtexitIntegration
from sentry_sdk.integrations.dedupe import DedupeIntegration
from sentry_sdk.integrations.excepthook import ExcepthookIntegration
from sentry_sdk.integrations.logging import LoggingIntegration
from sentry_sdk.integrations.threading import ThreadingIntegration
from sentry_sdk.scrubber import DEFAULT_DENYLIST, EventScrubber
from ..const import SUPERVISOR_VERSION
from ..coresys import CoreSys
from ..misc.filter import filter_data
_LOGGER: logging.Logger = logging.getLogger(__name__)
only_once_events: set[str] = set()
def init_sentry(coresys: CoreSys) -> None:
"""Initialize sentry client."""
if not sentry_sdk.is_initialized():
_LOGGER.info("Initializing Supervisor Sentry")
denylist = DEFAULT_DENYLIST + ["psk", "ssid"]
# Don't use AsyncioIntegration(). We commonly handle task exceptions
# outside of tasks. This would cause exception we gracefully handle to
# be captured by sentry.
sentry_sdk.init(
dsn="https://9c6ea70f49234442b4746e447b24747e@o427061.ingest.sentry.io/5370612",
before_send=partial(filter_data, coresys),
auto_enabling_integrations=False,
default_integrations=False,
event_scrubber=EventScrubber(denylist=denylist),
integrations=[
AioHttpIntegration(
failed_request_status_codes=frozenset(range(500, 600))
- set(
{
HTTPBadGateway.status_code,
HTTPServiceUnavailable.status_code,
}
)
),
ExcepthookIntegration(),
DedupeIntegration(),
AtexitIntegration(),
ThreadingIntegration(),
LoggingIntegration(level=logging.INFO, event_level=logging.CRITICAL),
],
release=SUPERVISOR_VERSION,
max_breadcrumbs=30,
)
def capture_exception(err: BaseException) -> None:
"""Capture an exception and send to sentry.
Must be called in executor.
"""
if sentry_sdk.is_initialized():
sentry_sdk.capture_exception(err)
async def async_capture_exception(err: BaseException) -> None:
"""Capture an exception and send to sentry.
Safe to call in event loop.
"""
if sentry_sdk.is_initialized():
await asyncio.get_running_loop().run_in_executor(
None, sentry_sdk.capture_exception, err
)
def close_sentry() -> None:
"""Close the current sentry client.
This method is irreversible. A new client will have to be initialized to re-open connetion.
"""
if sentry_sdk.is_initialized():
_LOGGER.info("Closing connection to Supervisor Sentry")
sentry_sdk.get_client().close()