diff options
Diffstat (limited to 'debug_toolbar/utils/tracking/db.py')
| -rw-r--r-- | debug_toolbar/utils/tracking/db.py | 85 | 
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 | 
