Skip to content

Instantly share code, notes, and snippets.

@chasetb
Forked from DominikSerafin/01_info
Last active May 4, 2018 18:58
Show Gist options
  • Save chasetb/c4c29f95ff53fb5d9267293b56c35eea to your computer and use it in GitHub Desktop.
Save chasetb/c4c29f95ff53fb5d9267293b56c35eea to your computer and use it in GitHub Desktop.
Django Google Chat Logger
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)
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