Last active
May 12, 2022 01:09
-
-
Save apollo13/005b067e1e8ccc1bd60e21ef2766b502 to your computer and use it in GitHub Desktop.
Django logging to Firefox/Chrome devtools
This file contains 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
""" | |
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