2013-04-23 18:51:17 +02:00
|
|
|
from __future__ import absolute_import
|
|
|
|
|
2013-10-31 18:33:19 +01:00
|
|
|
from django.conf import settings
|
2017-02-11 05:26:24 +01:00
|
|
|
from typing import Optional
|
2013-10-31 18:33:19 +01:00
|
|
|
|
2012-12-06 22:00:34 +01:00
|
|
|
import logging
|
|
|
|
import traceback
|
2013-01-02 23:25:40 +01:00
|
|
|
import platform
|
2012-12-06 22:00:34 +01:00
|
|
|
|
2013-01-16 20:45:07 +01:00
|
|
|
from django.core import mail
|
2016-06-05 07:51:18 +02:00
|
|
|
from django.http import HttpRequest
|
2013-01-16 20:45:07 +01:00
|
|
|
from django.utils.log import AdminEmailHandler
|
|
|
|
from django.views.debug import ExceptionReporter, get_exception_reporter_filter
|
2012-12-06 22:00:34 +01:00
|
|
|
|
2013-11-13 19:12:22 +01:00
|
|
|
from zerver.lib.queue import queue_json_publish
|
|
|
|
|
2013-08-06 21:35:33 +02:00
|
|
|
class AdminZulipHandler(logging.Handler):
|
2013-11-13 19:12:22 +01:00
|
|
|
"""An exception log handler that sends the exception to the queue to be
|
|
|
|
sent to the Zulip feedback server.
|
2012-12-06 22:00:34 +01:00
|
|
|
"""
|
|
|
|
|
|
|
|
# adapted in part from django/utils/log.py
|
|
|
|
|
|
|
|
def __init__(self):
|
2016-06-05 07:51:18 +02:00
|
|
|
# type: () -> None
|
2012-12-06 22:00:34 +01:00
|
|
|
logging.Handler.__init__(self)
|
|
|
|
|
|
|
|
def emit(self, record):
|
2016-06-05 07:51:18 +02:00
|
|
|
# type: (ExceptionReporter) -> None
|
2012-12-06 22:00:34 +01:00
|
|
|
try:
|
2017-01-08 16:36:19 +01:00
|
|
|
request = record.request # type: HttpRequest
|
2012-12-19 08:35:10 +01:00
|
|
|
|
2017-01-08 16:36:19 +01:00
|
|
|
exception_filter = get_exception_reporter_filter(request)
|
2013-11-13 19:12:22 +01:00
|
|
|
|
|
|
|
if record.exc_info:
|
2017-02-11 05:26:24 +01:00
|
|
|
stack_trace = ''.join(traceback.format_exception(*record.exc_info)) # type: Optional[str]
|
2013-11-13 19:12:22 +01:00
|
|
|
else:
|
|
|
|
stack_trace = None
|
|
|
|
|
|
|
|
try:
|
|
|
|
user_profile = request.user
|
|
|
|
user_full_name = user_profile.full_name
|
|
|
|
user_email = user_profile.email
|
|
|
|
except Exception:
|
|
|
|
traceback.print_exc()
|
|
|
|
# Error was triggered by an anonymous user.
|
|
|
|
user_full_name = None
|
|
|
|
user_email = None
|
|
|
|
|
2017-02-07 20:58:00 +01:00
|
|
|
try:
|
|
|
|
data = request.GET if request.method == 'GET' else \
|
2017-02-07 22:18:38 +01:00
|
|
|
exception_filter.get_post_parameters(request)
|
2017-02-07 20:58:00 +01:00
|
|
|
except Exception:
|
|
|
|
# exception_filter.get_post_parameters will throw
|
|
|
|
# RequestDataTooBig if there's a really big file uploaded
|
|
|
|
data = {}
|
2017-01-08 16:36:19 +01:00
|
|
|
|
2017-01-30 04:56:50 +01:00
|
|
|
try:
|
|
|
|
host = request.get_host().split(':')[0]
|
|
|
|
except Exception:
|
|
|
|
# request.get_host() will throw a DisallowedHost
|
|
|
|
# exception if the host is invalid
|
|
|
|
host = platform.node()
|
|
|
|
|
2013-11-13 19:12:22 +01:00
|
|
|
report = dict(
|
|
|
|
node = platform.node(),
|
2017-01-30 04:56:50 +01:00
|
|
|
host = host,
|
2013-11-13 19:12:22 +01:00
|
|
|
method = request.method,
|
|
|
|
path = request.path,
|
2017-01-08 16:36:19 +01:00
|
|
|
data = data,
|
2013-11-13 19:12:22 +01:00
|
|
|
remote_addr = request.META.get('REMOTE_ADDR', None),
|
|
|
|
query_string = request.META.get('QUERY_STRING', None),
|
|
|
|
server_name = request.META.get('SERVER_NAME', None),
|
|
|
|
message = record.getMessage(),
|
|
|
|
stack_trace = stack_trace,
|
|
|
|
user_full_name = user_full_name,
|
|
|
|
user_email = user_email,
|
|
|
|
)
|
2017-01-08 16:36:19 +01:00
|
|
|
except Exception:
|
2013-11-13 19:12:22 +01:00
|
|
|
traceback.print_exc()
|
|
|
|
report = dict(
|
|
|
|
node = platform.node(),
|
2017-01-30 04:56:50 +01:00
|
|
|
host = platform.node(),
|
2013-11-13 19:12:22 +01:00
|
|
|
message = record.getMessage(),
|
|
|
|
)
|
2012-12-06 22:00:34 +01:00
|
|
|
|
2013-01-25 20:15:26 +01:00
|
|
|
try:
|
2016-07-19 06:41:55 +02:00
|
|
|
if settings.STAGING_ERROR_NOTIFICATIONS:
|
2013-11-13 19:12:22 +01:00
|
|
|
# On staging, process the report directly so it can happen inside this
|
|
|
|
# try/except to prevent looping
|
|
|
|
from zilencer.error_notify import notify_server_error
|
|
|
|
notify_server_error(report)
|
2015-08-21 09:02:03 +02:00
|
|
|
else:
|
|
|
|
queue_json_publish('error_reports', dict(
|
|
|
|
type = "server",
|
|
|
|
report = report,
|
|
|
|
), lambda x: None)
|
2017-01-08 16:36:19 +01:00
|
|
|
except Exception:
|
2013-01-25 20:15:26 +01:00
|
|
|
# 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)
|