Forked from stantonk/django_orm_query_stacktrace.py
Last active
March 16, 2021 18:59
-
-
Save Guest007/5978aeddfe30e6c26dc5f365953ec879 to your computer and use it in GitHub Desktop.
Django logging config to dump a stack trace for every ORM query, so you can find the code that is producing queries that are icky.
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
# add this to your existed Django settings with LOGGING already present | |
import sqlparse | |
import logging, inspect | |
SQL_LOG = os.getenv('SQL_LOG', 'FALSE').strip().upper() == 'TRUE' | |
SQL_STACKTRACE = os.getenv('SQL_STACKTRACE', 'FALSE').strip().upper() == 'TRUE' | |
if SQL_LOG: | |
if 'formatters' not in LOGGING: | |
LOGGING['formatters'] = {} | |
LOGGING['formatters']['sourcetrace'] = { | |
'format': '-'*80 + '\n%(sql)s\n%(sourcetrace)s' + '-'*80 + '\n', | |
} | |
LOGGING['handlers']['django.db.sourcetrace'] = { | |
'class': 'logging.StreamHandler', | |
'formatter': 'sourcetrace', | |
} | |
LOGGING['loggers']['django.db.backends'] = { | |
'handlers': ['django.db.sourcetrace'], | |
'propagate': False, | |
'level': 'DEBUG', | |
} | |
class ContextFilter(logging.Filter): | |
""" | |
Injects SQL and stack trace information when added as a filter to a | |
python logger | |
""" | |
def _compose_sql_stacktrace(self): | |
source_trace = '' | |
stack = inspect.stack() | |
for stack_memeber in reversed(stack): | |
line = stack_memeber[2] | |
file = '/'.join(stack_memeber[1].split('/')[-3:]) | |
calling_method = stack_memeber[3] | |
source_trace += f'{line} in {file} at {calling_method}\n' | |
# clean up | |
del stack | |
return source_trace | |
def filter(self, record): | |
# pass to format string | |
if SQL_LOG and SQL_STACKTRACE: | |
record.sourcetrace = f'\nStacktrace of SQL query producer: {self._compose_sql_stacktrace()}' | |
else: | |
record.sourcetrace = '' | |
# remove annoing messages | |
if 'silk_' in record.sql: | |
record.sql = '' | |
return False | |
record.sql = sqlparse.format(record.sql, reindent_aligned=True, keyword_case='upper') | |
return True | |
if SQL_LOG: | |
django_db_backends_logger = logging.getLogger('django.db.backends') | |
f = ContextFilter() | |
django_db_backends_logger.addFilter(f) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment