# System documented in https://zulip.readthedocs.io/en/latest/subsystems/logging.html

import logging
import platform
import traceback
from typing import Any, Dict, Optional

from django.conf import settings
from django.core import mail
from django.http import HttpRequest
from django.utils.log import AdminEmailHandler
from django.views.debug import ExceptionReporter, get_exception_reporter_filter

from zerver.lib.queue import queue_json_publish

def add_request_metadata(report: Dict[str, Any], request: HttpRequest) -> None:
    report['path'] = request.path
    report['method'] = request.method
    report['remote_addr'] = request.META.get('REMOTE_ADDR', None),
    report['query_string'] = request.META.get('QUERY_STRING', None),
    report['server_name'] = request.META.get('SERVER_NAME', None),
    try:
        from django.contrib.auth.models import AnonymousUser
        user_profile = request.user
        if isinstance(user_profile, AnonymousUser):
            user_full_name = None
            user_email = None
        else:
            user_full_name = user_profile.full_name
            user_email = user_profile.email
    except Exception:
        # Unexpected exceptions here should be handled gracefully
        traceback.print_exc()
        user_full_name = None
        user_email = None
    report['user_email'] = user_email
    report['user_full_name'] = user_full_name

    exception_filter = get_exception_reporter_filter(request)
    try:
        report['data'] = request.GET if request.method == 'GET' else \
            exception_filter.get_post_parameters(request)
    except Exception:
        # exception_filter.get_post_parameters will throw
        # RequestDataTooBig if there's a really big file uploaded
        report['data'] = {}

    try:
        report['host'] = request.get_host().split(':')[0]
    except Exception:
        # request.get_host() will throw a DisallowedHost
        # exception if the host is invalid
        report['host'] = platform.node()

class AdminNotifyHandler(logging.Handler):
    """An logging handler that sends the log/exception to the queue to be
       turned into an email and/or a Zulip message for the server admins.
    """

    # adapted in part from django/utils/log.py

    def __init__(self) -> None:
        logging.Handler.__init__(self)

    def emit(self, record: logging.LogRecord) -> None:
        try:
            if record.exc_info:
                stack_trace = ''.join(traceback.format_exception(*record.exc_info))  # type: Optional[str]
                message = str(record.exc_info[1])
            else:
                stack_trace = None
                message = record.getMessage()
                if '\n' in message:
                    # Some exception code paths in queue processors
                    # seem to result in super-long messages
                    stack_trace = message
                    message = message.split('\n')[0]

            report = dict(
                node = platform.node(),
                host = platform.node(),
                message = message,
                stack_trace = stack_trace,
            )
            if hasattr(record, "request"):
                add_request_metadata(report, record.request)  # type: ignore  # record.request is added dynamically
        except Exception:
            traceback.print_exc()
            report = dict(
                node = platform.node(),
                host = platform.node(),
                message = record.getMessage(),
                stack_trace = "See /var/log/zulip/errors.log",
            )

        try:
            if settings.STAGING_ERROR_NOTIFICATIONS:
                # On staging, process the report directly so it can happen inside this
                # try/except to prevent looping
                from zerver.lib.error_notify import notify_server_error
                notify_server_error(report)
            else:
                queue_json_publish('error_reports', dict(
                    type = "server",
                    report = report,
                ))
        except Exception:
            # If this breaks, complain loudly but don't pass the traceback up the stream
            # However, we *don't* want to use logging.exception since that could trigger a loop.
            logging.warning("Reporting an exception triggered an exception!", exc_info=True)

@@ -2370,36 +2370,179 @@
 %3E None:%0A        
-try:
+report = %7B%7D%0A%0A        try:%0A            report%5B'node'%5D = platform.node()%0A            report%5B'host'%5D = platform.node()%0A%0A            stack_trace = None
 %0A            if 
@@ -2645,31 +2645,8 @@
 fo))
-  # type: Optional%5Bstr%5D
 %0A   
@@ -2714,43 +2714,8 @@
 se:%0A
-                stack_trace = None%0A
     
@@ -3015,17 +3015,16 @@
 %5Cn')%5B0%5D%0A
-%0A
         
@@ -3037,120 +3037,67 @@
 port
- = dict(%0A                node = platform.node(),%0A                host = platform.node(),%0A                
+%5B'stack_trace'%5D = stack_trace%0A            report%5B'
 message
+'%5D
  = m
@@ -3106,66 +3106,9 @@
 sage
-,%0A                stack_trace = stack_trace,%0A            )
+%0A
 %0A   
@@ -3259,24 +3259,25 @@
 dynamically%0A
+%0A
         exce
@@ -3306,183 +3306,132 @@
     
-traceback.print_exc()%0A            report = dict(%0A                node = platform.node(),%0A                host = platform.node(),%0A                message = record.getMessage(),
+report%5B'message'%5D = %22Exception in preparing exception report!%22%0A            logging.warning(report%5B'message'%5D, exc_info=True)
 %0A   
@@ -3431,36 +3431,40 @@
 ue)%0A            
-    
+report%5B'
 stack_trace = %22S
@@ -3458,16 +3458,18 @@
 ck_trace
+'%5D
  = %22See 
@@ -3498,23 +3498,8 @@
 log%22
-,%0A            )
 %0A%0A  

Clean up the logic slightly.