Skip to content

Instantly share code, notes, and snippets.

@airstrike
Last active April 18, 2020 03:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save airstrike/c4a1dbad231345563ae7ab12f536e5ca to your computer and use it in GitHub Desktop.
Save airstrike/c4a1dbad231345563ae7ab12f536e5ca to your computer and use it in GitHub Desktop.
Pretty logging in django
# add to settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'loggers': {
'django.db.backends': {
'handlers': ['console_sql'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO').upper(),
},
'cache': {
'handlers': ['console'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO').upper(),
},
'django.utils.autoreload': {
'handlers': ['console'],
'level': 'ERROR',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'simple',
},
'console_sql': {
'class': 'logging.StreamHandler',
'formatter': 'sql',
},
},
'formatters': {
'simple': {
'()': 'myproject.logging.ColorFormatter', # colored output
'format': '{bg %(levelname)s} %(levelname)s %(name)s %(filename)s@%(lineno)s {clear}\n{clear}{%(levelname)s}%(message)s\n{clear}'
},
'sql': {
'()': 'myproject.logging.SQLFormatter', # colored output
'format': '{bg %(levelname)s} %(levelname)s %(name)s %(filename)s@%(lineno)s {clear}\n{clear}{%(levelname)s}%(message)s\n{clear}'
},
'verbose': {
'()': 'myproject.logging.ColorFormatter', # colored output
'format': '%(levelname)s %(name)s %(asctime)s %(module)s %(process)d %(thread)d %(pathname)s@%(lineno)s: %(message)s{clear}'
},
},
}
# myproject/logging.py
from itertools import cycle
import logging
import sqlparse
COLORS = {
'DEBUG': '\033[0;34m', 'bold DEBUG': '\033[0;94m', 'bg DEBUG': '\033[7;34m',
'INFO': '\033[0;32m', 'bold INFO': '\033[1;32m', 'bg INFO': '\033[7;32m',
'WARNING': '\033[0;33m', 'bold WARNING': '\033[1;33m', 'bg WARNING': '\033[7;33m',
'CRITICAL': '\033[0;31m', 'bold CRITICAL': '\033[1;31m', 'bg CRITICAL': '\033[7;31m',
'ERROR': '\033[0;35m', 'bold ERROR': '\033[1;35m', 'bg ERROR': '\033[7;35m',
'black': '\033[0;30m', 'bold black': '\033[1;30m',
'red': '\033[0;31m', 'bold red': '\033[1;31m',
'green': '\033[0;32m', 'bold green': '\033[1;32m',
'yellow': '\033[0;33m', 'bold yellow': '\033[1;33m',
'blue': '\033[0;34m', 'bold blue': '\033[1;34m',
'purple': '\033[0;35m', 'bold purple': '\033[1;35m',
'cyan': '\033[0;36m', 'bold cyan': '\033[1;36m',
'gray': '\033[0;37m', 'bold gray': '\033[1;37m',
'white': '\033[1;37m',
'clear': '\033[0m', 'reverse': '\033[0;7m'
}
class GracefulDict(dict):
def __missing__(self, key):
return '{'+key+'}'
def graceful_format_map(record, mapping):
"""
Since someone thought it was smart to make {} the special characters for delimiting
string parameters to be formatted despite how ubiquitous curly braces are in json,
css files, python dict literals (!!!) and whatnot, we need to be a little creative
in our escaping so that .format_map() doesn't spit out an exception
"""
chunks = record.split('}')
results = ''
for chunk in chunks:
chunk = chunk + '}'
try:
chunk = chunk.format_map(GracefulDict(**mapping))
except ValueError:
pass
results += chunk
return results[:-1]
class ColorFormatter(logging.Formatter):
colors = COLORS
def format(self, record):
record = super().format(record)
return graceful_format_map(record, self.colors) + self.colors['clear']
class SQLFormatter(logging.Formatter):
colors = COLORS
def format(self, record):
try:
record = super().format(record)
record = sqlparse.format(record, reindent=True, keyword_case='upper')
record = graceful_format_map(record, self.colors) + self.colors['clear']
except:
logging.exception(record)
return record
@airstrike
Copy link
Author

Screenshot using cmder with Dracula theme

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment