mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			97 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			97 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from typing import TYPE_CHECKING, Optional
 | 
						|
 | 
						|
import sentry_sdk
 | 
						|
from django.utils.translation import override as override_language
 | 
						|
from sentry_sdk.integrations import Integration
 | 
						|
from sentry_sdk.integrations.django import DjangoIntegration
 | 
						|
from sentry_sdk.integrations.logging import ignore_logger
 | 
						|
from sentry_sdk.integrations.redis import RedisIntegration
 | 
						|
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
 | 
						|
from sentry_sdk.utils import capture_internal_exceptions
 | 
						|
 | 
						|
from version import ZULIP_VERSION
 | 
						|
 | 
						|
from .config import PRODUCTION
 | 
						|
 | 
						|
if TYPE_CHECKING:
 | 
						|
    from sentry_sdk._types import Event, Hint
 | 
						|
 | 
						|
 | 
						|
def add_context(event: "Event", hint: "Hint") -> Optional["Event"]:
 | 
						|
    if "exc_info" in hint:
 | 
						|
        _, exc_value, _ = hint["exc_info"]
 | 
						|
        # Ignore GeneratorExit, KeyboardInterrupt, and SystemExit exceptions
 | 
						|
        if not isinstance(exc_value, Exception):
 | 
						|
            return None
 | 
						|
    from django.conf import settings
 | 
						|
 | 
						|
    from zerver.lib.request import get_current_request
 | 
						|
    from zerver.models import get_user_profile_by_id
 | 
						|
 | 
						|
    with capture_internal_exceptions():
 | 
						|
        # event.user is the user context, from Sentry, which is
 | 
						|
        # pre-populated with some keys via its Django integration:
 | 
						|
        # https://docs.sentry.io/platforms/python/guides/django/enriching-error-data/additional-data/identify-user/
 | 
						|
        event.setdefault("tags", {})
 | 
						|
        user_info = event.get("user", {})
 | 
						|
        if user_info.get("id"):
 | 
						|
            user_profile = get_user_profile_by_id(user_info["id"])
 | 
						|
            event["tags"]["realm"] = user_info["realm"] = user_profile.realm.string_id or "root"
 | 
						|
            with override_language(settings.LANGUAGE_CODE):
 | 
						|
                # str() to force the lazy-translation to apply now,
 | 
						|
                # since it won't serialize into json for Sentry otherwise
 | 
						|
                user_info["role"] = str(user_profile.get_role_name())
 | 
						|
 | 
						|
        # These are PII, and should be scrubbed
 | 
						|
        if "username" in user_info:
 | 
						|
            del user_info["username"]
 | 
						|
        if "email" in user_info:
 | 
						|
            del user_info["email"]
 | 
						|
 | 
						|
        request = get_current_request()
 | 
						|
        if request:
 | 
						|
            if hasattr(request, "client"):
 | 
						|
                event["tags"]["client"] = request.client.name
 | 
						|
            if hasattr(request, "realm"):
 | 
						|
                event["tags"].setdefault("realm", request.realm.string_id)
 | 
						|
    return event
 | 
						|
 | 
						|
 | 
						|
def setup_sentry(dsn: Optional[str], *integrations: Integration) -> None:
 | 
						|
    if not dsn:
 | 
						|
        return
 | 
						|
    sentry_sdk.init(
 | 
						|
        dsn=dsn,
 | 
						|
        environment="production" if PRODUCTION else "development",
 | 
						|
        release=ZULIP_VERSION,
 | 
						|
        integrations=[
 | 
						|
            DjangoIntegration(),
 | 
						|
            RedisIntegration(),
 | 
						|
            SqlalchemyIntegration(),
 | 
						|
            *integrations,
 | 
						|
        ],
 | 
						|
        before_send=add_context,
 | 
						|
        # Because we strip the email/username from the Sentry data
 | 
						|
        # above, the effect of this flag is that the requests/users
 | 
						|
        # involved in exceptions will be identified in Sentry only by
 | 
						|
        # their IP address, user ID, realm, and role.  We consider
 | 
						|
        # this an appropriate balance between avoiding Sentry getting
 | 
						|
        # PII while having the identifiers needed to determine that an
 | 
						|
        # exception only affects a small subset of users or realms.
 | 
						|
        send_default_pii=True,
 | 
						|
    )
 | 
						|
 | 
						|
    # Ignore all of the loggers from django.security that are for user
 | 
						|
    # errors; see https://docs.djangoproject.com/en/3.0/ref/exceptions/#suspiciousoperation
 | 
						|
    ignore_logger("django.security.SuspiciousOperation")
 | 
						|
    ignore_logger("django.security.DisallowedHost")
 | 
						|
    ignore_logger("django.security.DisallowedModelAdminLookup")
 | 
						|
    ignore_logger("django.security.DisallowedModelAdminToField")
 | 
						|
    ignore_logger("django.security.DisallowedRedirect")
 | 
						|
    ignore_logger("django.security.InvalidSessionKey")
 | 
						|
    ignore_logger("django.security.RequestDataTooBig")
 | 
						|
    ignore_logger("django.security.SuspiciousFileOperation")
 | 
						|
    ignore_logger("django.security.SuspiciousMultipartForm")
 | 
						|
    ignore_logger("django.security.SuspiciousSession")
 | 
						|
    ignore_logger("django.security.TooManyFieldsSent")
 |