aboutsummaryrefslogtreecommitdiffstats
path: root/debug_toolbar/utils/tracking/db.py
diff options
context:
space:
mode:
Diffstat (limited to 'debug_toolbar/utils/tracking/db.py')
-rw-r--r--debug_toolbar/utils/tracking/db.py85
1 files changed, 85 insertions, 0 deletions
diff --git a/debug_toolbar/utils/tracking/db.py b/debug_toolbar/utils/tracking/db.py
new file mode 100644
index 0000000..4c9ee53
--- /dev/null
+++ b/debug_toolbar/utils/tracking/db.py
@@ -0,0 +1,85 @@
+import sys
+import traceback
+
+from datetime import datetime
+
+from django.conf import settings
+from django.template import Node
+from django.utils import simplejson
+from django.utils.encoding import force_unicode
+from django.utils.hashcompat import sha_constructor
+
+from debug_toolbar.utils import ms_from_timedelta, tidy_stacktrace, get_template_info
+
+# TODO:This should be set in the toolbar loader as a default and panels should
+# get a copy of the toolbar object with access to its config dictionary
+SQL_WARNING_THRESHOLD = getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}) \
+ .get('SQL_WARNING_THRESHOLD', 500)
+
+class CursorWrapper(object):
+ """
+ Wraps a cursor and logs queries.
+ """
+
+ def __init__(self, cursor, db, logger):
+ self.cursor = cursor
+ # Instance of a BaseDatabaseWrapper subclass
+ self.db = db
+ # logger must implement a ``record`` method
+ self.logger = logger
+
+ def execute(self, sql, params=()):
+ start = datetime.now()
+ try:
+ return self.cursor.execute(sql, params)
+ finally:
+ stop = datetime.now()
+ duration = ms_from_timedelta(stop - start)
+ stacktrace = tidy_stacktrace(traceback.extract_stack())
+ _params = ''
+ try:
+ _params = simplejson.dumps([force_unicode(x, strings_only=True) for x in params])
+ except TypeError:
+ pass # object not JSON serializable
+
+ template_info = None
+ cur_frame = sys._getframe().f_back
+ try:
+ while cur_frame is not None:
+ if cur_frame.f_code.co_name == 'render':
+ node = cur_frame.f_locals['self']
+ if isinstance(node, Node):
+ template_info = get_template_info(node.source)
+ break
+ cur_frame = cur_frame.f_back
+ except:
+ pass
+ del cur_frame
+
+ # We keep `sql` to maintain backwards compatibility
+ self.logger.record(**{
+ 'alias': getattr(self, 'alias', 'default'),
+ 'sql': self.db.ops.last_executed_query(self.cursor, sql, params),
+ 'duration': duration,
+ 'raw_sql': sql,
+ 'params': _params,
+ 'hash': sha_constructor(settings.SECRET_KEY + sql + _params).hexdigest(),
+ 'stacktrace': stacktrace,
+ 'start_time': start,
+ 'stop_time': stop,
+ 'is_slow': (duration > SQL_WARNING_THRESHOLD),
+ 'is_select': sql.lower().strip().startswith('select'),
+ 'template_info': template_info,
+ })
+
+ def executemany(self, sql, param_list):
+ return self.cursor.executemany(sql, param_list)
+
+ def __getattr__(self, attr):
+ if attr in self.__dict__:
+ return self.__dict__[attr]
+ else:
+ return getattr(self.cursor, attr)
+
+ def __iter__(self):
+ return iter(self.cursor) \ No newline at end of file