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)
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)
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]]
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 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) }))
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)
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
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, )
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
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
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, 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)()
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
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 __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
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 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=" ", 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
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
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})
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 __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
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
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 = []
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})
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)
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: