def _record(self, method, sql, params):
        start_time = time()
        try:
            return method(sql, params)
        finally:
            stop_time = time()
            duration = (stop_time - start_time) * 1000
            if dt_settings.get_config()["ENABLE_STACKTRACES"]:
                stacktrace = tidy_stacktrace(reversed(get_stack()))
            else:
                stacktrace = []
            _params = ""
            try:
                _params = json.dumps(self._decode(params))
            except TypeError:
                pass  # object not JSON serializable

            template_info = get_template_info()

            alias = getattr(self.db, "alias", "default")
            conn = self.db.connection
            vendor = getattr(conn, "vendor", "unknown")

            params = {
                "vendor": vendor,
                "alias": alias,
                "sql": self.db.ops.last_executed_query(
                    self.cursor, sql, self._quote_params(params)
                ),
                "duration": duration,
                "raw_sql": sql,
                "params": _params,
                "raw_params": params,
                "stacktrace": stacktrace,
                "start_time": start_time,
                "stop_time": stop_time,
                "is_slow": duration > dt_settings.get_config()["SQL_WARNING_THRESHOLD"],
                "is_select": sql.lower().strip().startswith("select"),
                "template_info": template_info,
            }

            if vendor == "postgresql":
                # If an erroneous query was ran on the connection, it might
                # be in a state where checking isolation_level raises an
                # exception.
                try:
                    iso_level = conn.isolation_level
                except conn.InternalError:
                    iso_level = "unknown"
                params.update(
                    {
                        "trans_id": self.logger.get_transaction_id(alias),
                        "trans_status": conn.get_transaction_status(),
                        "iso_level": iso_level,
                        "encoding": conn.encoding,
                    }
                )

            # We keep `sql` to maintain backwards compatibility
            self.logger.record(**params)
Example #2
0
    def test_prettify_sql(self):
        """
        Test case to validate that the PRETTIFY_SQL setting changes the output
        of the sql when it's toggled. It does not validate what it does
        though.
        """
        list(User.objects.filter(username__istartswith="spam"))

        response = self.panel.process_request(self.request)
        self.panel.generate_stats(self.request, response)
        pretty_sql = self.panel._queries[-1][1]["sql"]
        self.assertEqual(len(self.panel._queries), 1)

        # Reset the queries
        self.panel._queries = []
        # Run it again, but with prettyify off. Verify that it's different.
        dt_settings.get_config()["PRETTIFY_SQL"] = False
        list(User.objects.filter(username__istartswith="spam"))
        response = self.panel.process_request(self.request)
        self.panel.generate_stats(self.request, response)
        self.assertEqual(len(self.panel._queries), 1)
        self.assertNotEqual(pretty_sql, self.panel._queries[-1][1]["sql"])

        self.panel._queries = []
        # Run it again, but with prettyify back on.
        # This is so we don't have to check what PRETTIFY_SQL does exactly,
        # but we know it's doing something.
        dt_settings.get_config()["PRETTIFY_SQL"] = True
        list(User.objects.filter(username__istartswith="spam"))
        response = self.panel.process_request(self.request)
        self.panel.generate_stats(self.request, response)
        self.assertEqual(len(self.panel._queries), 1)
        self.assertEqual(pretty_sql, self.panel._queries[-1][1]["sql"])
    def _record(self, method, sql, params):
        start_time = time()
        try:
            return method(sql, params)
        finally:
            stop_time = time()
            duration = (stop_time - start_time) * 1000
            if dt_settings.get_config()['ENABLE_STACKTRACES']:
                stacktrace = tidy_stacktrace(reversed(get_stack()))
            else:
                stacktrace = []
            _params = ''
            try:
                _params = json.dumps(list(map(self._decode, params)))
            except Exception:
                pass  # object not JSON serializable

            template_info = get_template_info()

            alias = getattr(self.db, 'alias', 'default')
            conn = self.db.connection
            vendor = getattr(conn, 'vendor', 'unknown')

            params = {
                'vendor': vendor,
                'alias': alias,
                'sql': self.db.ops.last_executed_query(
                    self.cursor, sql, self._quote_params(params)),
                'duration': duration,
                'raw_sql': sql,
                'params': _params,
                'stacktrace': stacktrace,
                'start_time': start_time,
                'stop_time': stop_time,
                'is_slow': duration > dt_settings.get_config()['SQL_WARNING_THRESHOLD'],
                'is_select': sql.lower().strip().startswith('select'),
                'template_info': template_info,
            }

            if vendor == 'postgresql':
                # If an erroneous query was ran on the connection, it might
                # be in a state where checking isolation_level raises an
                # exception.
                try:
                    iso_level = conn.isolation_level
                except conn.InternalError:
                    iso_level = 'unknown'
                params.update({
                    'trans_id': self.logger.get_transaction_id(alias),
                    'trans_status': conn.get_transaction_status(),
                    'iso_level': iso_level,
                    'encoding': conn.encoding,
                })

            # We keep `sql` to maintain backwards compatibility
            self.logger.record(**params)
Example #4
0
    def _record(self, method, sql, params):
        start_time = time()
        try:
            return method(sql, params)
        finally:
            stop_time = time()
            duration = (stop_time - start_time) * 1000
            if dt_settings.get_config()['ENABLE_STACKTRACES']:
                stacktrace = tidy_stacktrace(reversed(get_stack()))
            else:
                stacktrace = []
            _params = ''
            try:
                _params = json.dumps(list(map(self._decode, params)))
            except Exception:
                pass  # object not JSON serializable

            template_info = get_template_info()

            alias = getattr(self.db, 'alias', 'default')
            conn = self.db.connection
            vendor = getattr(conn, 'vendor', 'unknown')

            params = {
                'vendor': vendor,
                'alias': alias,
                'sql': self.db.ops.last_executed_query(
                    self.cursor, sql, self._quote_params(params)),
                'duration': duration,
                'raw_sql': sql,
                'params': _params,
                'stacktrace': stacktrace,
                'start_time': start_time,
                'stop_time': stop_time,
                'is_slow': duration > dt_settings.get_config()['SQL_WARNING_THRESHOLD'],
                'is_select': sql.lower().strip().startswith('select'),
                'template_info': template_info,
            }

            if vendor == 'postgresql':
                # If an erroneous query was ran on the connection, it might
                # be in a state where checking isolation_level raises an
                # exception.
                try:
                    iso_level = conn.isolation_level
                except conn.InternalError:
                    iso_level = 'unknown'
                params.update({
                    'trans_id': self.logger.get_transaction_id(alias),
                    'trans_status': conn.get_transaction_status(),
                    'iso_level': iso_level,
                    'encoding': conn.encoding,
                })

            # We keep `sql` to maintain backwards compatibility
            self.logger.record(**params)
Example #5
0
def patched_store(self):
    if self.store_id:  # don't save if already have
        return
    self.store_id = uuid.uuid4().hex
    cls = type(self)
    cls._store[self.store_id] = self
    store_size = get_config().get('RESULTS_CACHE_SIZE',
                                  get_config().get('RESULTS_STORE_SIZE', 100))
    for dummy in range(len(cls._store) - store_size):
        try:
            # collections.OrderedDict
            cls._store.popitem(last=False)
        except TypeError:
            # django.utils.datastructures.SortedDict
            del cls._store[cls._store.keyOrder[0]]
Example #6
0
    def _store_api_info(self, sender, time_taken=0, method=None, url=None, response=None, args=None, kwargs=None, **kw):

        time_taken *= 1000
        self.total_time += time_taken

        # use debug-toolbar utilities to get & render stacktrace
        # skip last two entries, which are in eulfedora.debug_panel
        if dt_settings.get_config().get("ENABLE_STACKTRACES", False):
            stacktrace = tidy_stacktrace(reversed(get_stack()))[:-2]
        else:
            stacktrace = []

        try:
            method_name = method.__name__.upper()
        except AttributeError:
            method_name = method

        self.api_calls.append(
            {
                "time": time_taken,
                "method": method_name,
                "url": url,
                "args": args,
                "kwargs": kwargs,
                "response": response,
                "stack": render_stacktrace(stacktrace),
            }
        )
Example #7
0
 def content(self):
     """ Content of the panel when it's displayed in full screen. """
     toolbars = OrderedDict()
     for id, toolbar in DebugToolbar._store.items():
         content = {}
         for panel in toolbar.panels:
             panel_id = None
             nav_title = ''
             nav_subtitle = ''
             try:
                 panel_id = panel.panel_id
                 nav_title = panel.nav_title
                 nav_subtitle = panel.nav_subtitle() if isinstance(
                     panel.nav_subtitle, Callable) else panel.nav_subtitle
             except Exception:
                 logger.debug('Error parsing panel info:', exc_info=True)
             if panel_id is not None:
                 content.update({
                     panel_id: {
                         'panel_id': panel_id,
                         'nav_title': nav_title,
                         'nav_subtitle': nav_subtitle,
                     }
                 })
         toolbars[id] = {'toolbar': toolbar, 'content': content}
     return get_template().render(
         Context({
             'toolbars': OrderedDict(reversed(list(toolbars.items()))),
             'trunc_length': get_config().get('RH_POST_TRUNC_LENGTH', 0)
         }))
Example #8
0
def render_stacktrace(trace):
    show_locals = dt_settings.get_config()["ENABLE_STACKTRACES_LOCALS"]
    html = ""
    for abspath, lineno, func, code, locals_ in trace:
        if os.path.sep in abspath:
            directory, filename = abspath.rsplit(os.path.sep, 1)
            # We want the separator to appear in the UI so add it back.
            directory += os.path.sep
        else:
            # abspath could be something like "<frozen importlib._bootstrap>"
            directory = ""
            filename = abspath
        html += format_html(
            ('<span class="djdt-path">{}</span>' +
             '<span class="djdt-file">{}</span> in' +
             ' <span class="djdt-func">{}</span>' +
             '(<span class="djdt-lineno">{}</span>)\n' +
             '  <span class="djdt-code">{}</span>\n'),
            directory,
            filename,
            func,
            lineno,
            code,
        )
        if show_locals:
            html += format_html(
                '  <pre class="djdt-locals">{}</pre>\n',
                pformat(locals_),
            )
        html += "\n"
    return mark_safe(html)
Example #9
0
    def _record_call(self, cache, name, original_method, args, kwargs):
        # Some cache backends implement certain cache methods in terms of other cache
        # methods (e.g. get_or_set() in terms of get() and add()).  In order to only
        # record the calls made directly by the user code, set the _djdt_recording flag
        # here to cause the monkey patched cache methods to skip recording additional
        # calls made during the course of this call.
        cache._djdt_recording = True
        t = time.time()
        value = original_method(*args, **kwargs)
        t = time.time() - t
        cache._djdt_recording = False

        if dt_settings.get_config()["ENABLE_STACKTRACES"]:
            stacktrace = tidy_stacktrace(reversed(get_stack()))
        else:
            stacktrace = []

        self._store_call_info(
            name=name,
            time_taken=t,
            return_value=value,
            args=args,
            kwargs=kwargs,
            trace=stacktrace,
            template_info=get_template_info(),
            backend=cache,
        )
        return value
Example #10
0
def get_stack_trace(*, skip=0):
    """
    Return a processed stack trace for the current call stack.

    If the ``ENABLE_STACKTRACES`` setting is False, return an empty :class:`list`.
    Otherwise return a :class:`list` of processed stack frame tuples (file name, line
    number, function name, source line, frame locals) for the current call stack.  The
    first entry in the list will be for the bottom of the stack and the last entry will
    be for the top of the stack.

    ``skip`` is an :class:`int` indicating the number of stack frames above the frame
    for this function to omit from the stack trace.  The default value of ``0`` means
    that the entry for the caller of this function will be the last entry in the
    returned stack trace.
    """
    config = dt_settings.get_config()
    if not config["ENABLE_STACKTRACES"]:
        return []
    skip += 1  # Skip the frame for this function.
    stack_trace_recorder = getattr(_local_data, "stack_trace_recorder", None)
    if stack_trace_recorder is None:
        stack_trace_recorder = _StackTraceRecorder()
        _local_data.stack_trace_recorder = stack_trace_recorder
    return stack_trace_recorder.get_stack_trace(
        excluded_modules=config["HIDE_IN_STACKTRACES"],
        include_locals=config["ENABLE_STACKTRACES_LOCALS"],
        skip=skip,
    )
Example #11
0
    def _store_api_info(self,
                        sender,
                        time_taken=0,
                        method=None,
                        url=None,
                        response=None,
                        args=None,
                        kwargs=None,
                        **kw):

        time_taken *= 1000
        self.total_time += time_taken

        # use debug-toolbar utilities to get & render stacktrace
        # skip last two entries, which are in eulfedora.debug_panel
        if dt_settings.get_config().get('ENABLE_STACKTRACES', False):
            stacktrace = tidy_stacktrace(reversed(get_stack()))[:-2]
        else:
            stacktrace = []

        try:
            method_name = method.__name__.upper()
        except AttributeError:
            method_name = method

        self.api_calls.append({
            'time': time_taken,
            'method': method_name,
            'url': url,
            'args': args,
            'kwargs': kwargs,
            'response': response,
            'stack': render_stacktrace(stacktrace)
        })
def get_show_toolbar():
    # If SHOW_TOOLBAR_CALLBACK is a string, which is the recommended
    # setup, resolve it to the corresponding callable.
    func_or_path = dt_settings.get_config()["SHOW_TOOLBAR_CALLBACK"]
    if isinstance(func_or_path, str):
        return import_string(func_or_path)
    else:
        return func_or_path
Example #13
0
 def get_observe_request():
     # If OBSERVE_REQUEST_CALLBACK is a string, which is the recommended
     # setup, resolve it to the corresponding callable.
     func_or_path = dt_settings.get_config()["OBSERVE_REQUEST_CALLBACK"]
     if isinstance(func_or_path, str):
         return import_string(func_or_path)
     else:
         return func_or_path
Example #14
0
 def __init__(self):
     # If SHOW_TOOLBAR_CALLBACK is a string, which is the recommended
     # setup, resolve it to the corresponding callable.
     func_or_path = dt_settings.get_config()['SHOW_TOOLBAR_CALLBACK']
     if isinstance(func_or_path, six.string_types):
         self.show_toolbar = import_string(func_or_path)
     else:
         self.show_toolbar = func_or_path
 def __init__(self):
     # If SHOW_TOOLBAR_CALLBACK is a string, which is the recommended
     # setup, resolve it to the corresponding callable.
     func_or_path = dt_settings.get_config()['SHOW_TOOLBAR_CALLBACK']
     if isinstance(func_or_path, six.string_types):
         self.show_toolbar = import_string(func_or_path)
     else:
         self.show_toolbar = func_or_path
def get_show_toolbar():
    # If SHOW_TOOLBAR_CALLBACK is a string, which is the recommended
    # setup, resolve it to the corresponding callable.
    func_or_path = dt_settings.get_config()["SHOW_TOOLBAR_CALLBACK"]
    if isinstance(func_or_path, str):
        return import_string(func_or_path)
    else:
        return func_or_path
Example #17
0
 def __init__(self, request, response, kwargs):
     self.request = request
     self.response = response
     self.kwargs = kwargs
     if dt_settings.get_config()['ENABLE_STACKTRACES']:
         self.raw_stacktrace = tidy_stacktrace(reversed(get_stack()[5:]))
     else:
         self.raw_stacktrace = []
def get_connections():
    try:
        path = dt_settings.get_config()["ALCHEMY_DB_ALIASES"]
    except KeyError:
        raise ImproperlyConfigured(
            "Must specify ALCHEMY_DB_ALIASES in DEBUG_TOOLBAR_CONFIG")
    else:
        return import_string(path)()
Example #19
0
    def __call__(self, request):
        # Decide whether the toolbar is active for this request. Don't render
        # the toolbar during AJAX requests.
        show_toolbar = get_show_toolbar()
        if not show_toolbar(request) or request.is_ajax():
            return self.get_response(request)

        toolbar = DebugToolbar(request, self.get_response)

        # Activate instrumentation ie. monkey-patch.
        for panel in toolbar.enabled_panels:
            panel.enable_instrumentation()
        try:
            # Run panels like Django middleware.
            response = toolbar.process_request(request)
        finally:
            # Deactivate instrumentation ie. monkey-unpatch. This must run
            # regardless of the response. Keep 'return' clauses below.
            for panel in reversed(toolbar.enabled_panels):
                panel.disable_instrumentation()

        # Check for responses where the toolbar can't be inserted.
        content_encoding = response.get("Content-Encoding", "")
        content_type = response.get("Content-Type", "").split(";")[0]
        if any(
            (
                getattr(response, "streaming", False),
                "gzip" in content_encoding,
                content_type not in _HTML_TYPES,
            )
        ):
            return response

        # Collapse the toolbar by default if SHOW_COLLAPSED is set.
        if toolbar.config["SHOW_COLLAPSED"] and "djdt" not in request.COOKIES:
            response.set_cookie("djdt", "hide", 864000)

        # Insert the toolbar in the response.
        content = response.content.decode(response.charset)
        insert_before = dt_settings.get_config()["INSERT_BEFORE"]
        pattern = re.escape(insert_before)
        bits = re.split(pattern, content, flags=re.IGNORECASE)
        if len(bits) > 1:
            # When the toolbar will be inserted for sure, generate the stats.
            for panel in reversed(toolbar.enabled_panels):
                panel.generate_stats(request, response)
                panel.generate_server_timing(request, response)

            response = self.generate_server_timing_header(
                response, toolbar.enabled_panels
            )

            bits[-2] += toolbar.render_toolbar()
            response.content = insert_before.join(bits)
            if response.get("Content-Length", None):
                response["Content-Length"] = len(response.content)
        return response
Example #20
0
 def __init__(self, request):
     self.request = request
     self.config = dt_settings.get_config().copy()
     self._panels = OrderedDict()
     for panel_class in self.get_panel_classes():
         panel_instance = panel_class(self)
         self._panels[panel_instance.panel_id] = panel_instance
     self.stats = {}
     self.store_id = None
 def __init__(self, request):
     self.request = request
     self.config = dt_settings.get_config().copy()
     self._panels = OrderedDict()
     for panel_class in self.get_panel_classes():
         panel_instance = panel_class(self)
         self._panels[panel_instance.panel_id] = panel_instance
     self.stats = {}
     self.store_id = None
Example #22
0
    def __call__(self, request):
        # Decide whether the toolbar is active for this request.
        show_toolbar = get_show_toolbar()
        if not show_toolbar(request) or DebugToolbar.is_toolbar_request(
                request):
            return self.get_response(request)

        toolbar = DebugToolbar(request, self.get_response)

        # Activate instrumentation ie. monkey-patch.
        for panel in toolbar.enabled_panels:
            panel.enable_instrumentation()
        try:
            # Run panels like Django middleware.
            response = toolbar.process_request(request)
        finally:
            clear_stack_trace_caches()
            # Deactivate instrumentation ie. monkey-unpatch. This must run
            # regardless of the response. Keep 'return' clauses below.
            for panel in reversed(toolbar.enabled_panels):
                panel.disable_instrumentation()

        # Generate the stats for all requests when the toolbar is being shown,
        # but not necessarily inserted.
        for panel in reversed(toolbar.enabled_panels):
            panel.generate_stats(request, response)
            panel.generate_server_timing(request, response)

        # Always render the toolbar for the history panel, even if it is not
        # included in the response.
        rendered = toolbar.render_toolbar()

        for header, value in self.get_headers(request,
                                              toolbar.enabled_panels).items():
            response.headers[header] = value

        # Check for responses where the toolbar can't be inserted.
        content_encoding = response.get("Content-Encoding", "")
        content_type = response.get("Content-Type", "").split(";")[0]
        if (getattr(response, "streaming", False) or content_encoding != ""
                or content_type not in _HTML_TYPES):
            return response

        # Insert the toolbar in the response.
        content = response.content.decode(response.charset)
        insert_before = dt_settings.get_config()["INSERT_BEFORE"]
        pattern = re.escape(insert_before)
        bits = re.split(pattern, content, flags=re.IGNORECASE)
        if len(bits) > 1:
            bits[-2] += rendered
            response.content = insert_before.join(bits)
            if "Content-Length" in response:
                response["Content-Length"] = len(response.content)
        return response
Example #23
0
    def process_response(self, request, response):
        toolbar = self.__class__.debug_toolbars.pop(
            threading.current_thread().ident, None)
        if not toolbar:
            return response

        # Run process_response methods of panels like Django middleware.
        for panel in reversed(toolbar.enabled_panels):
            new_response = panel.process_response(request, response)
            if new_response:
                response = new_response

        # Deactivate instrumentation ie. monkey-unpatch. This must run
        # regardless of the response. Keep 'return' clauses below.
        # (NB: Django's model for middleware doesn't guarantee anything.)
        for panel in reversed(toolbar.enabled_panels):
            panel.disable_instrumentation()

        # Check for responses where the toolbar can't be inserted.
        content_encoding = response.get('Content-Encoding', '')
        content_type = response.get('Content-Type', '').split(';')[0]
        if any((getattr(response, 'streaming', False), 'gzip'
                in content_encoding, content_type not in _HTML_TYPES)):
            return response

        # Collapse the toolbar by default if SHOW_COLLAPSED is set.
        if toolbar.config['SHOW_COLLAPSED'] and 'djdt' not in request.COOKIES:
            response.set_cookie('djdt', 'hide', 864000)

        # Insert the toolbar in the response.
        content = force_text(response.content,
                             encoding=settings.DEFAULT_CHARSET)
        insert_before = dt_settings.get_config()['INSERT_BEFORE']
        try:  # Python >= 2.7
            pattern = re.escape(insert_before)
            bits = re.split(pattern, content, flags=re.IGNORECASE)
        except TypeError:  # Python < 2.7
            pattern = '(.+?)(%s|$)' % re.escape(insert_before)
            matches = re.findall(pattern,
                                 content,
                                 flags=re.DOTALL | re.IGNORECASE)
            bits = [m[0] for m in matches if m[1] == insert_before]
            # When the body ends with a newline, there's two trailing groups.
            bits.append(''.join(m[0] for m in matches if m[1] == ''))
        if len(bits) > 1:
            # When the toolbar will be inserted for sure, generate the stats.
            for panel in reversed(toolbar.enabled_panels):
                panel.generate_stats(request, response)

            bits[-2] += toolbar.render_toolbar()
            response.content = insert_before.join(bits)
            if response.get('Content-Length', None):
                response['Content-Length'] = len(response.content)
        return response
Example #24
0
def parse_sql(sql, aligned_indent=False):
    stack = sqlparse.engine.FilterStack()
    if dt_settings.get_config()["PRETTIFY_SQL"]:
        stack.enable_grouping()
    if aligned_indent:
        stack.stmtprocess.append(
            sqlparse.filters.AlignedIndentFilter(char="&nbsp;", n="<br/>")
        )
    stack.preprocess.append(BoldKeywordFilter())  # add our custom filter
    stack.postprocess.append(sqlparse.filters.SerializerUnicode())  # tokens -> strings
    return "".join(stack.run(sql))
    def __call__(self, request):
        # Decide whether the toolbar is active for this request.
        show_toolbar = get_show_toolbar()
        if not show_toolbar(request) or request.path.startswith("/__debug__/"):
            return self.get_response(request)

        toolbar = DebugToolbar(request, self.get_response)

        # Activate instrumentation ie. monkey-patch.
        for panel in toolbar.enabled_panels:
            panel.enable_instrumentation()
        try:
            # Run panels like Django middleware.
            response = toolbar.process_request(request)
        finally:
            # Deactivate instrumentation ie. monkey-unpatch. This must run
            # regardless of the response. Keep 'return' clauses below.
            for panel in reversed(toolbar.enabled_panels):
                panel.disable_instrumentation()

        # Generate the stats for all requests when the toolbar is being shown,
        # but not necessarily inserted.
        for panel in reversed(toolbar.enabled_panels):
            panel.generate_stats(request, response)
            panel.generate_server_timing(request, response)

        response = self.generate_server_timing_header(response,
                                                      toolbar.enabled_panels)

        # Check for responses where the toolbar can't be inserted.
        content_encoding = response.get("Content-Encoding", "")
        content_type = response.get("Content-Type", "").split(";")[0]
        if any((
                getattr(response, "streaming", False),
                "gzip" in content_encoding,
                content_type not in _HTML_TYPES,
                request.is_ajax(),
        )):
            # If a AJAX or JSON request, render the toolbar for the history.
            if request.is_ajax() or content_type == "application/json":
                toolbar.render_toolbar()
            return response

        # Insert the toolbar in the response.
        content = response.content.decode(response.charset)
        insert_before = dt_settings.get_config()["INSERT_BEFORE"]
        pattern = re.escape(insert_before)
        bits = re.split(pattern, content, flags=re.IGNORECASE)
        if len(bits) > 1:
            bits[-2] += toolbar.render_toolbar()
            response.content = insert_before.join(bits)
            if "Content-Length" in response:
                response["Content-Length"] = len(response.content)
        return response
Example #26
0
def tidy_stacktrace(stack):
    """
    Clean up stacktrace and remove all entries that are excluded by the
    HIDE_IN_STACKTRACES setting.

    ``stack`` should be a list of frame tuples from ``inspect.stack()`` or
    ``debug_toolbar.utils.get_stack()``.
    """
    _stack_trace_deprecation_warning()

    trace = []
    excluded_modules = dt_settings.get_config()["HIDE_IN_STACKTRACES"]
    for frame, path, line_no, func_name, text in (f[:5] for f in stack):
        if _is_excluded_frame(frame, excluded_modules):
            continue
        text = "".join(text).strip() if text else ""
        frame_locals = (frame.f_locals if
                        dt_settings.get_config()["ENABLE_STACKTRACES_LOCALS"]
                        else None)
        trace.append((path, line_no, func_name, text, frame_locals))
    return trace
    def process_response(self, request, response):
        toolbar = self.__class__.debug_toolbars.pop(
            threading.current_thread().ident, None)
        if not toolbar:
            return response

        # Run process_response methods of panels like Django middleware.
        for panel in reversed(toolbar.enabled_panels):
            new_response = panel.process_response(request, response)
            if new_response:
                response = new_response

        # Deactivate instrumentation ie. monkey-unpatch. This must run
        # regardless of the response. Keep 'return' clauses below.
        # (NB: Django's model for middleware doesn't guarantee anything.)
        for panel in reversed(toolbar.enabled_panels):
            panel.disable_instrumentation()

        # Check for responses where the toolbar can't be inserted.
        content_encoding = response.get("Content-Encoding", "")
        content_type = response.get("Content-Type", "").split(";")[0]
        if any((
                getattr(response, "streaming", False),
                "gzip" in content_encoding,
                content_type not in _HTML_TYPES,
        )):
            return response

        # Collapse the toolbar by default if SHOW_COLLAPSED is set.
        if toolbar.config["SHOW_COLLAPSED"] and "djdt" not in request.COOKIES:
            response.set_cookie("djdt", "hide", 864000)

        # Insert the toolbar in the response.
        content = force_text(response.content)
        insert_before = dt_settings.get_config()["INSERT_BEFORE"]
        pattern = re.escape(insert_before)
        bits = re.split(pattern, content, flags=re.IGNORECASE)
        if len(bits) > 1:
            # When the toolbar will be inserted for sure, generate the stats.
            for panel in reversed(toolbar.enabled_panels):
                panel.generate_stats(request, response)
                panel.generate_server_timing(request, response)

            response = self.generate_server_timing_header(
                response, toolbar.enabled_panels)

            bits[-2] += toolbar.render_toolbar()
            response.content = insert_before.join(bits)
            if response.get("Content-Length", None):
                response["Content-Length"] = len(response.content)
        return response
    def process_response(self, request, response):
        toolbar = self.__class__.debug_toolbars.pop(threading.current_thread().ident, None)
        if not toolbar:
            return response

        # Run process_response methods of panels like Django middleware.
        for panel in reversed(toolbar.enabled_panels):
            new_response = panel.process_response(request, response)
            if new_response:
                response = new_response

        # Deactivate instrumentation ie. monkey-unpatch. This must run
        # regardless of the response. Keep 'return' clauses below.
        # (NB: Django's model for middleware doesn't guarantee anything.)
        for panel in reversed(toolbar.enabled_panels):
            panel.disable_instrumentation()

        # Check for responses where the toolbar can't be inserted.
        content_encoding = response.get('Content-Encoding', '')
        content_type = response.get('Content-Type', '').split(';')[0]
        if any((getattr(response, 'streaming', False),
                'gzip' in content_encoding,
                content_type not in _HTML_TYPES)):
            return response

        # Collapse the toolbar by default if SHOW_COLLAPSED is set.
        if toolbar.config['SHOW_COLLAPSED'] and 'djdt' not in request.COOKIES:
            response.set_cookie('djdt', 'hide', 864000)

        # Insert the toolbar in the response.
        content = force_text(response.content, encoding=settings.DEFAULT_CHARSET)
        insert_before = dt_settings.get_config()['INSERT_BEFORE']
        try:                    # Python >= 2.7
            pattern = re.escape(insert_before)
            bits = re.split(pattern, content, flags=re.IGNORECASE)
        except TypeError:       # Python < 2.7
            pattern = '(.+?)(%s|$)' % re.escape(insert_before)
            matches = re.findall(pattern, content, flags=re.DOTALL | re.IGNORECASE)
            bits = [m[0] for m in matches if m[1] == insert_before]
            # When the body ends with a newline, there's two trailing groups.
            bits.append(''.join(m[0] for m in matches if m[1] == ''))
        if len(bits) > 1:
            # When the toolbar will be inserted for sure, generate the stats.
            for panel in reversed(toolbar.enabled_panels):
                panel.generate_stats(request, response)

            bits[-2] += toolbar.render_toolbar()
            response.content = insert_before.join(bits)
            if response.get('Content-Length', None):
                response['Content-Length'] = len(response.content)
        return response
    def wrapped(self, *args, **kwargs):
        t = time.time()
        value = method(self, *args, **kwargs)
        t = time.time() - t

        if dt_settings.get_config()['ENABLE_STACKTRACES']:
            stacktrace = tidy_stacktrace(reversed(get_stack()))
        else:
            stacktrace = []

        template_info = get_template_info()
        cache_called.send(sender=self.__class__, time_taken=t,
                          name=method.__name__, return_value=value,
                          args=args, kwargs=kwargs, trace=stacktrace,
                          template_info=template_info, backend=self.cache)
        return value
Example #30
0
    def generate_stats(self, request, response):
        if not hasattr(self, 'profiler'):
            return None
        # Could be delayed until the panel content is requested (perf. optim.)
        self.profiler.create_stats()
        self.stats = DjangoDebugToolbarStats(self.profiler)
        self.stats.calc_callees()

        root = FunctionCall(self.stats, self.stats.get_root_func(), depth=0)

        func_list = []
        self.add_node(func_list, root,
                      dt_settings.get_config()['PROFILER_MAX_DEPTH'],
                      root.stats[3] / 8)

        self.record_stats({'func_list': func_list})
Example #31
0
 def enabled(self):
     # Check to see if settings has a default value for it
     disabled_panels = dt_settings.get_config()['DISABLE_PANELS']
     panel_path = get_name_from_obj(self)
     # Some panels such as the SQLPanel and TemplatesPanel exist in a
     # panel module, but can be disabled without panel in the path.
     # For that reason, replace .panel. in the path and check for that
     # value in the disabled panels as well.
     disable_panel = (panel_path in disabled_panels or panel_path.replace(
         '.panel.', '.') in disabled_panels)
     if disable_panel:
         default = 'off'
     else:
         default = 'on'
     # The user's cookies should override the default value
     return self.toolbar.request.COOKIES.get('djdt' + self.panel_id,
                                             default) == 'on'
 def enabled(self):
     # Check to see if settings has a default value for it
     disabled_panels = dt_settings.get_config()['DISABLE_PANELS']
     panel_path = get_name_from_obj(self)
     # Some panels such as the SQLPanel and TemplatesPanel exist in a
     # panel module, but can be disabled without panel in the path.
     # For that reason, replace .panel. in the path and check for that
     # value in the disabled panels as well.
     disable_panel = (
         panel_path in disabled_panels or
         panel_path.replace('.panel.', '.') in disabled_panels)
     if disable_panel:
         default = 'off'
     else:
         default = 'on'
     # The user's cookies should override the default value
     return self.toolbar.request.COOKIES.get('djdt' + self.panel_id, default) == 'on'
    def generate_stats(self, request, response):
        if not hasattr(self, 'profiler'):
            return None
        # Could be delayed until the panel content is requested (perf. optim.)
        self.profiler.create_stats()
        self.stats = DjangoDebugToolbarStats(self.profiler)
        self.stats.calc_callees()

        root = FunctionCall(self.stats, self.stats.get_root_func(), depth=0)

        func_list = []
        self.add_node(func_list,
                      root,
                      dt_settings.get_config()['PROFILER_MAX_DEPTH'],
                      root.stats[3] / 8)

        self.record_stats({'func_list': func_list})
Example #34
0
 def __init__(self, request, get_response):
     self.request = request
     self.config = dt_settings.get_config().copy()
     panels = []
     for panel_class in reversed(self.get_panel_classes()):
         panel = panel_class(self, get_response)
         panels.append(panel)
         if panel.enabled:
             get_response = panel.process_request
     self.process_request = get_response
     self._panels = OrderedDict()
     while panels:
         panel = panels.pop()
         self._panels[panel.panel_id] = panel
     self.stats = {}
     self.server_timing_stats = {}
     self.store_id = None
Example #35
0
 def __init__(self, request, get_response):
     self.request = request
     self.config = dt_settings.get_config().copy()
     panels = []
     for panel_class in reversed(self.get_panel_classes()):
         panel = panel_class(self, get_response)
         panels.append(panel)
         if panel.enabled:
             get_response = panel.process_request
     self.process_request = get_response
     self._panels = OrderedDict()
     while panels:
         panel = panels.pop()
         self._panels[panel.panel_id] = panel
     self.stats = {}
     self.server_timing_stats = {}
     self.store_id = None
Example #36
0
def tidy_stacktrace(stack):
    """
    Clean up stacktrace and remove all entries that:
    1. Are part of Django (except contrib apps)
    2. Are part of socketserver (used by Django's dev server)
    3. Are the last entry (which is part of our stacktracing code)

    ``stack`` should be a list of frame tuples from ``inspect.stack()``
    """
    trace = []
    for frame, path, line_no, func_name, text in (f[:5] for f in stack):
        if omit_path(os.path.realpath(path)):
            continue
        text = "".join(text).strip() if text else ""
        frame_locals = (frame.f_locals if
                        dt_settings.get_config()["ENABLE_STACKTRACES_LOCALS"]
                        else None)
        trace.append((path, line_no, func_name, text, frame_locals))
    return trace
Example #37
0
    def __init__(self,
                 domain,
                 response,
                 result,
                 request,
                 start_time=None,
                 end_time=None):
        self.domain = domain
        self.request = request
        self.result = result
        self.response = response
        self.start_time = start_time
        self.end_time = end_time

        if dt_settings.get_config()['ENABLE_STACKTRACES']:
            # cut the first 6 lines, exactly until the original operation call
            self.raw_stacktrace = tidy_stacktrace(reversed(get_stack()[6:]))
        else:
            self.raw_stacktrace = []
Example #38
0
    def generate_stats(self, request, response):
        if not hasattr(self, "profiler"):
            return None
        # Could be delayed until the panel content is requested (perf. optim.)
        self.profiler.create_stats()
        self.stats = DjangoDebugToolbarStats(self.profiler)
        self.stats.calc_callees()

        root_func = self.stats.get_root_func()
        # Ensure root function exists before continuing with function call analysis
        if root_func:
            root = FunctionCall(self.stats, root_func, depth=0)
            func_list = []
            self.add_node(
                func_list,
                root,
                dt_settings.get_config()["PROFILER_MAX_DEPTH"],
                root.stats[3] / 8,
            )
            self.record_stats({"func_list": func_list})
    def generate_stats(self, request, response):
        if not hasattr(self, "profiler"):
            return None
        # Could be delayed until the panel content is requested (perf. optim.)
        self.profiler.create_stats()
        self.stats = Stats(self.profiler)
        self.stats.calc_callees()

        root_func = cProfile.label(super().process_request.__code__)

        if root_func in self.stats.stats:
            root = FunctionCall(self.stats, root_func, depth=0)
            func_list = []
            self.add_node(
                func_list,
                root,
                dt_settings.get_config()["PROFILER_MAX_DEPTH"],
                root.stats[3] / 8,
            )
            self.record_stats({"func_list": func_list})
Example #40
0
    def generate_stats(self, request, response):
        if not hasattr(self, "profiler"):
            return None
        # Could be delayed until the panel content is requested (perf. optim.)
        self.profiler.create_stats()
        self.stats = DjangoDebugToolbarStats(self.profiler)
        self.stats.calc_callees()

        root_func = self.stats.get_root_func()
        # Ensure root function exists before continuing with function call analysis
        if root_func:
            root = FunctionCall(self.stats, root_func, depth=0)
            func_list = []
            self.add_node(
                func_list,
                root,
                dt_settings.get_config()["PROFILER_MAX_DEPTH"],
                root.stats[3] / 8,
            )
            self.record_stats({"func_list": func_list})
Example #41
0
    def wrapped(self, *args, **kwargs):
        t = time.time()
        value = method(self, *args, **kwargs)
        t = time.time() - t

        if dt_settings.get_config()['ENABLE_STACKTRACES']:
            stacktrace = tidy_stacktrace(reversed(get_stack()))
        else:
            stacktrace = []

        template_info = get_template_info()
        cache_called.send(sender=self.__class__,
                          time_taken=t,
                          name=method.__name__,
                          return_value=value,
                          args=args,
                          kwargs=kwargs,
                          trace=stacktrace,
                          template_info=template_info,
                          backend=self.cache)
        return value
Example #42
0
 def __init__(self, request, get_response):
     self.request = request
     self.config = dt_settings.get_config().copy()
     panels = []
     for panel_class in reversed(self.get_panel_classes()):
         panel = panel_class(self, get_response)
         panels.append(panel)
         if panel.enabled:
             get_response = panel.process_request
     self.process_request = get_response
     # Use OrderedDict for the _panels attribute so that items can be efficiently
     # removed using FIFO order in the DebugToolbar.store() method.  The .popitem()
     # method of Python's built-in dict only supports LIFO removal.
     self._panels = OrderedDict()
     while panels:
         panel = panels.pop()
         self._panels[panel.panel_id] = panel
     self.stats = {}
     self.server_timing_stats = {}
     self.store_id = None
     self._created.send(request, toolbar=self)
Example #43
0
def get_module_path(module_name):
    try:
        module = import_module(module_name)
    except ImportError as e:
        raise ImproperlyConfigured("Error importing HIDE_IN_STACKTRACES: %s" % (e,))
    else:
        source_path = inspect.getsourcefile(module)
        if source_path.endswith("__init__.py"):
            source_path = os.path.dirname(source_path)
        return os.path.realpath(source_path)


hidden_paths = [
    get_module_path(module_name)
    for module_name in dt_settings.get_config()["HIDE_IN_STACKTRACES"]
]


def omit_path(path):
    return any(path.startswith(hidden_path) for hidden_path in hidden_paths)


def tidy_stacktrace(stack):
    """
    Clean up stacktrace and remove all entries that:
    1. Are part of Django (except contrib apps)
    2. Are part of socketserver (used by Django's dev server)
    3. Are the last entry (which is part of our stacktracing code)

    ``stack`` should be a list of frame tuples from ``inspect.stack()``
except ImportError:
    from django.utils.datastructures import SortedDict as OrderedDict

try:
    toolbar_version = LooseVersion(debug_toolbar.VERSION)
except:
    toolbar_version = LooseVersion('0')

logger = logging.getLogger(__name__)

DEBUG_TOOLBAR_URL_PREFIX = getattr(settings, 'DEBUG_TOOLBAR_URL_PREFIX', '/__debug__')


try:
    from debug_toolbar.settings import get_config
    CONFIG = get_config()
except ImportError:
    from debug_toolbar.settings import CONFIG


def patched_process_request(self, request):
    # Decide whether the toolbar is active for this request.
    show_toolbar = debug_toolbar.middleware.get_show_toolbar()
    if not show_toolbar(request):
        return

    toolbar = DebugToolbar(request)
    self.__class__.debug_toolbars[threading.current_thread().ident] = toolbar

    # Activate instrumentation ie. monkey-patch.
    for panel in toolbar.enabled_panels: