This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/authentik/lib/sentry.py

114 lines
3.6 KiB
Python
Raw Normal View History

2020-12-05 21:08:42 +00:00
"""authentik sentry integration"""
from typing import Optional
2020-11-11 21:35:40 +00:00
from aioredis.errors import ConnectionClosedError, ReplyError
from billiard.exceptions import SoftTimeLimitExceeded, WorkerLostError
2020-09-15 09:29:43 +00:00
from celery.exceptions import CeleryError
from channels.middleware import BaseMiddleware
2020-09-30 13:55:59 +00:00
from channels_redis.core import ChannelFull
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation, ValidationError
2020-02-23 18:48:14 +00:00
from django.db import InternalError, OperationalError, ProgrammingError
from django.http.response import Http404
2020-02-23 18:48:14 +00:00
from django_redis.exceptions import ConnectionInterrupted
from docker.errors import DockerException
from h11 import LocalProtocolError
from ldap3.core.exceptions import LDAPException
from redis.exceptions import ConnectionError as RedisConnectionError
2020-10-28 18:00:11 +00:00
from redis.exceptions import RedisError, ResponseError
2020-02-23 18:48:14 +00:00
from rest_framework.exceptions import APIException
from sentry_sdk import Hub
from sentry_sdk.tracing import Transaction
from structlog.stdlib import get_logger
2020-09-30 13:55:59 +00:00
from websockets.exceptions import WebSocketException
from authentik.lib.utils.reflection import class_to_path
LOGGER = get_logger()
class SentryWSMiddleware(BaseMiddleware):
"""Sentry Websocket middleweare to set the transaction name based on
consumer class path"""
async def __call__(self, scope, receive, send):
transaction: Optional[Transaction] = Hub.current.scope.transaction
class_path = class_to_path(self.inner.consumer_class)
if transaction:
transaction.name = class_path
return await self.inner(scope, receive, send)
class SentryIgnoredException(Exception):
"""Base Class for all errors that are suppressed, and not sent to sentry."""
def before_send(event: dict, hint: dict) -> Optional[dict]:
"""Check if error is database error, and ignore if so"""
# pylint: disable=no-name-in-module
from psycopg2.errors import Error
ignored_classes = (
2020-10-28 18:00:11 +00:00
# Inbuilt types
KeyboardInterrupt,
ConnectionResetError,
OSError,
PermissionError,
# Django Errors
Error,
ImproperlyConfigured,
OperationalError,
2020-02-23 18:48:14 +00:00
InternalError,
ProgrammingError,
SuspiciousOperation,
2020-10-28 18:00:11 +00:00
ValidationError,
# Redis errors
RedisConnectionError,
ConnectionInterrupted,
2020-10-28 18:00:11 +00:00
RedisError,
ResponseError,
ReplyError,
ConnectionClosedError,
2020-10-28 18:00:11 +00:00
# websocket errors
ChannelFull,
WebSocketException,
LocalProtocolError,
2020-10-28 18:00:11 +00:00
# rest_framework error
APIException,
2020-10-28 18:00:11 +00:00
# celery errors
WorkerLostError,
2020-10-28 18:00:11 +00:00
CeleryError,
SoftTimeLimitExceeded,
2020-10-28 18:00:11 +00:00
# custom baseclass
SentryIgnoredException,
2020-10-28 18:00:11 +00:00
# ldap errors
LDAPException,
# Docker errors
DockerException,
# End-user errors
Http404,
)
exc_value = None
2019-12-31 11:51:16 +00:00
if "exc_info" in hint:
2020-07-07 12:02:20 +00:00
_, exc_value, _ = hint["exc_info"]
if isinstance(exc_value, ignored_classes):
LOGGER.debug("dropping exception", exc=exc_value)
return None
if "logger" in event:
if event["logger"] in [
"kombu",
"asyncio",
"multiprocessing",
"django_redis",
"django.security.DisallowedHost",
"django_redis.cache",
"celery.backends.redis",
"celery.worker",
"paramiko.transport",
]:
return None
LOGGER.debug("sending event to sentry", exc=exc_value, source_logger=event.get("logger", None))
if settings.DEBUG or settings.TEST:
return None
return event