Skip to content

Instantly share code, notes, and snippets.

@apollo13
Last active May 12, 2022 01:09
Show Gist options
  • Save apollo13/005b067e1e8ccc1bd60e21ef2766b502 to your computer and use it in GitHub Desktop.
Save apollo13/005b067e1e8ccc1bd60e21ef2766b502 to your computer and use it in GitHub Desktop.
Django logging to Firefox/Chrome devtools
"""
License: MIT - https://opensource.org/licenses/MIT
ChromeLogger is a protocol which allows sending logging messages to the Browser.
This module implements simple support for Django. It consists of two components:
* `LoggingMiddleware` which is responsible for sending all log messages
associated with the request to the browser.
* `ChromeLoggerHandler` a python logging handler which collects all messages.
Configuration in settings.py is as follows::
MIDDLEWARE = [
'chromelogger.LoggingMiddleware',
... # other middlewares
]
LOGGING = {
...
'handlers': {
'browser': {
'class': 'chromelogger.ChromeLoggerHandler',
},
...
},
'loggers': {
'django': {
'handlers': ['console', 'browser'],
'level': 'DEBUG',
},
...
}
}
"""
import json
import logging
import threading
HEADER_DATA = {
'version': 1,
'columns': ['log', 'backtrace', 'type'],
}
STORAGE = threading.local()
def map_level(level):
"""Maps a logging level to a string understood by browser devtools."""
if level >= logging.ERROR:
return 'error'
elif level >= logging.WARNING:
return 'warn'
elif level >= logging.INFO:
return 'info'
return ''
def encode_data(data):
"""Return a base64 encoded json dump."""
bytes = json.dumps(data).encode('utf-8').encode('base64').replace('\n', '')
assert len(bytes) < 250 * 1024
return bytes
class ChromeLoggerHandler(logging.Handler):
def emit(self, record):
try:
STORAGE.records.append(record)
except AttributeError:
pass
def LoggingMiddleware(get_respone):
def middleware(request):
STORAGE.records = log_records = []
try:
response = get_respone(request)
logging_data = HEADER_DATA.copy()
rows = [
[['{}:'.format(record.name), record.getMessage().strip()],
'{} : {}'.format(record.pathname, record.lineno),
map_level(record.levelno)]
for record in log_records
]
rows.insert(0, [
['{} request to {}'.format(request.method, request.get_full_path())],
'', 'group'
])
rows.append([[], '', 'groupEnd'])
logging_data['rows'] = rows
response['X-ChromeLogger-Data'] = encode_data(logging_data)
return response
finally:
del STORAGE.records
return middleware
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment