-
-
Save chasetb/c4c29f95ff53fb5d9267293b56c35eea to your computer and use it in GitHub Desktop.
Django Google Chat Logger
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.conf import settings | |
import requests | |
import json | |
from copy import copy | |
from django.utils.log import AdminEmailHandler | |
from django.views.debug import ExceptionReporter | |
class ChatExceptionHandler(AdminEmailHandler): | |
# replacing default django emit (https://github.com/django/django/blob/master/django/utils/log.py) | |
def emit(self, record, *args, **kwargs): | |
# original AdminEmailHandler "emit" method code (but without actually sending email) | |
try: | |
request = record.request | |
subject = '%s (%s IP): %s' % ( | |
record.levelname, | |
('internal' if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS | |
else 'EXTERNAL'), | |
record.getMessage() | |
) | |
except Exception: | |
subject = '%s: %s' % ( | |
record.levelname, | |
record.getMessage() | |
) | |
request = None | |
subject = self.format_subject(subject) | |
# Since we add a nicely formatted traceback on our own, create a copy | |
# of the log record without the exception data. | |
no_exc_record = copy(record) | |
no_exc_record.exc_info = None | |
no_exc_record.exc_text = None | |
if record.exc_info: | |
exc_info = record.exc_info | |
else: | |
exc_info = (None, record.getMessage(), None) | |
reporter = ExceptionReporter(request, is_email=True, *exc_info) | |
message = "%s\n\n%s" % (self.format(no_exc_record), reporter.get_traceback_text()) | |
html_message = reporter.get_traceback_html() if self.include_html else None | |
trace_data = reporter.get_traceback_data() | |
# construct chat card fields | |
card = { | |
"cards": [ | |
{ | |
"header": { | |
"title": subject, | |
"subtitle": "Django Error", | |
}, | |
"sections": [ | |
{ | |
"widgets": [ | |
{ | |
"keyValue": { | |
"topLabel": "Level", | |
"content": record.levelname, | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/sliders.png" | |
} | |
}, | |
{ | |
"keyValue": { | |
"topLabel": "Method", | |
"content": request.method if request else 'No Request', | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/cog.png" | |
} | |
}, | |
{ | |
"keyValue": { | |
"topLabel": "Path", | |
"content": request.path if request else 'No Request', | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/search.png" | |
} | |
}, | |
{ | |
"keyValue": { | |
"topLabel": "User", | |
"content": ((request.user.username + ' (' + str(request.user.pk) + ')' | |
if request.user.is_authenticated else 'Anonymous') | |
if request else 'No Request'), | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/user-circle.png" | |
} | |
}, | |
{ | |
"keyValue": { | |
"topLabel": "Status Code", | |
"content": str(record.status_code), | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/heartbeat.png" | |
} | |
}, | |
{ | |
"keyValue": { | |
"topLabel": "UA", | |
"content": (request.META['HTTP_USER_AGENT'] | |
if request and request.META else 'No Request'), | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/safari.png" | |
} | |
}, | |
{ | |
"keyValue": { | |
"topLabel": "GET Params", | |
"content": json.dumps(request.GET) if request else 'No Request', | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/cloud-download.png" | |
} | |
}, | |
{ | |
"keyValue": { | |
"topLabel": "POST Data", | |
"content": json.dumps(request.POST) if request else 'No Request', | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/cloud-upload.png" | |
} | |
}, | |
{ | |
"keyValue": { | |
"topLabel": "Exception Type", | |
"content": str(trace_data['exception_type']), | |
"contentMultiline": "false", | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/exclamation-triangle.png", | |
} | |
}, | |
{ | |
"keyValue": { | |
"topLabel": "Exception Value", | |
"content": str(trace_data['exception_value']), | |
"contentMultiline": "false", | |
"iconUrl": "https://github.com/encharm/Font-Awesome-SVG-PNG/raw/master/black/png/128/exclamation-triangle.png", | |
} | |
}, | |
] | |
} | |
] | |
} | |
] | |
} | |
# Google Chat room | |
url = '<INSERT GOOGLE CHAT WEBHOOKS URL>' | |
headers = {'Content-Type': 'application/json; charset=UTF-8'} | |
# Send card message | |
response = requests.post(url, data=json.dumps(card), headers=headers, json=True) | |
# Load data as JSON response | |
data = json.loads(response.text) | |
# Grab the traceback frames | |
trace_frames = reporter.get_traceback_frames() | |
# Begin the traceback string | |
error_info = "*Traceback*:" | |
# Format the frame data similar to the DEBUG html | |
for frame in trace_frames: | |
error_info += str("\nFile {} in {}".format(frame['filename'], frame['function'])) | |
error_info += str("\n{}{}".format(frame['lineno'], frame['context_line'])) | |
# Compose bot_message with the thread from the previous message | |
bot_message = { | |
'text': error_info, | |
'thread': data['thread'] | |
} | |
# Send traceback in thread | |
thread_response = requests.post(url, data=json.dumps(bot_message), headers=headers, json=True) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.utils.log import DEFAULT_LOGGING | |
LOGGING = DEFAULT_LOGGING | |
LOGGING['handlers']['chat_admins'] = { | |
'level': 'ERROR', | |
'filters': ['require_debug_false'], | |
'class': 'myapp.chat_logger.ChatExceptionHandler', | |
} | |
LOGGING['loggers']['django'] = { | |
'handlers': ['console', 'chat_admins'], | |
'level': 'INFO', | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment