Skip to content

Commit c03f08f

Browse files
committed
Update all panels to use data from get_stats on render
Any instance attributes shouldn't be used because they can't be relied upon for historical purposes. Especially when it comes to the titles and nav titles.
1 parent 71edcf5 commit c03f08f

File tree

17 files changed

+105
-85
lines changed

17 files changed

+105
-85
lines changed

debug_toolbar/panels/cache.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,16 +169,17 @@ def _record_call(self, cache, name, original_method, args, kwargs):
169169

170170
@property
171171
def nav_subtitle(self):
172-
cache_calls = len(self.calls)
172+
stats = self.get_stats()
173+
cache_calls = len(stats.get("calls"))
173174
return ngettext(
174175
"%(cache_calls)d call in %(time).2fms",
175176
"%(cache_calls)d calls in %(time).2fms",
176177
cache_calls,
177-
) % {"cache_calls": cache_calls, "time": self.total_time}
178+
) % {"cache_calls": cache_calls, "time": stats.get("total_time")}
178179

179180
@property
180181
def title(self):
181-
count = len(getattr(settings, "CACHES", ["default"]))
182+
count = self.get_stats().get("total_caches")
182183
return ngettext(
183184
"Cache calls from %(count)d backend",
184185
"Cache calls from %(count)d backends",
@@ -214,6 +215,7 @@ def generate_stats(self, request, response):
214215
"hits": self.hits,
215216
"misses": self.misses,
216217
"counts": self.counts,
218+
"total_caches": len(getattr(settings, "CACHES", ["default"])),
217219
}
218220
)
219221

debug_toolbar/panels/history/panel.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ def content(self):
8989
toolbar_history = {}
9090
for request_id in reversed(self.toolbar.store.request_ids()):
9191
toolbar_history[request_id] = {
92+
"history_stats": self.toolbar.store.panel(
93+
request_id, HistoryPanel.panel_id
94+
),
9295
"form": HistoryStoreForm(
9396
initial={"request_id": request_id, "exclude_history": True}
9497
),

debug_toolbar/panels/history/views.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,18 @@ def history_refresh(request):
5555
"content": render_to_string(
5656
"debug_toolbar/panels/history_tr.html",
5757
{
58-
"id": request_id,
59-
"store_context": {
60-
"toolbar": toolbar,
61-
"form": HistoryStoreForm(
62-
initial={
63-
"request_id": request_id,
64-
"exclude_history": True,
65-
}
66-
),
58+
"request_id": request_id,
59+
"history_context": {
60+
"history_stats": toolbar.store.panel(
61+
request_id, "HistoryPanel"
62+
)
6763
},
64+
"form": HistoryStoreForm(
65+
initial={
66+
"request_id": request_id,
67+
"exclude_history": True,
68+
}
69+
),
6870
},
6971
),
7072
}

debug_toolbar/panels/settings.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from django.conf import settings
21
from django.utils.encoding import force_str
32
from django.utils.translation import gettext_lazy as _
43
from django.views.debug import get_default_exception_reporter_filter
@@ -18,7 +17,9 @@ class SettingsPanel(Panel):
1817
nav_title = _("Settings")
1918

2019
def title(self):
21-
return _("Settings from %s") % settings.SETTINGS_MODULE
20+
return _("Settings from %s") % self.get_stats()["settings"].get(
21+
"SETTINGS_MODULE"
22+
)
2223

2324
def generate_stats(self, request, response):
2425
self.record_stats(

debug_toolbar/panels/sql/panel.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,19 +159,20 @@ def record(self, **kwargs):
159159

160160
@property
161161
def nav_subtitle(self):
162-
query_count = len(self._queries)
162+
stats = self.get_stats()
163+
query_count = len(stats.get("queries", []))
163164
return ngettext(
164165
"%(query_count)d query in %(sql_time).2fms",
165166
"%(query_count)d queries in %(sql_time).2fms",
166167
query_count,
167168
) % {
168169
"query_count": query_count,
169-
"sql_time": self._sql_time,
170+
"sql_time": stats.get("sql_time"),
170171
}
171172

172173
@property
173174
def title(self):
174-
count = len(self._databases)
175+
count = len(self.get_stats().get("databases"))
175176
return ngettext(
176177
"SQL queries from %(count)d connection",
177178
"SQL queries from %(count)d connections",

debug_toolbar/panels/staticfiles.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ class StaticFilesPanel(panels.Panel):
7979

8080
@property
8181
def title(self):
82+
stats = self.get_stats()
8283
return _("Static files (%(num_found)s found, %(num_used)s used)") % {
83-
"num_found": self.num_found,
84-
"num_used": self.num_used,
84+
"num_found": stats.get("num_found"),
85+
"num_used": stats.get("num_used"),
8586
}
8687

8788
def __init__(self, *args, **kwargs):
@@ -95,16 +96,11 @@ def enable_instrumentation(self):
9596
def disable_instrumentation(self):
9697
storage.staticfiles_storage = _original_storage
9798

98-
@property
99-
def num_used(self):
100-
stats = self.get_stats()
101-
return stats and stats["num_used"]
102-
10399
nav_title = _("Static files")
104100

105101
@property
106102
def nav_subtitle(self):
107-
num_used = self.num_used
103+
num_used = self.get_stats().get("num_used")
108104
return ngettext(
109105
"%(num_used)s file used", "%(num_used)s files used", num_used
110106
) % {"num_used": num_used}

debug_toolbar/panels/templates/panel.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,16 @@ def _store_template_info(self, sender, **kwargs):
145145

146146
@property
147147
def title(self):
148-
num_templates = len(self.templates)
148+
num_templates = len(self.get_stats()["templates"])
149149
return _("Templates (%(num_templates)s rendered)") % {
150150
"num_templates": num_templates
151151
}
152152

153153
@property
154154
def nav_subtitle(self):
155-
if self.templates:
156-
return self.templates[0]["template"].name
155+
templates = self.get_stats()["templates"]
156+
if templates:
157+
return templates[0]["name"]
157158
return ""
158159

159160
template = "debug_toolbar/panels/templates.html"
@@ -171,7 +172,6 @@ def disable_instrumentation(self):
171172
def generate_stats(self, request, response):
172173
template_context = []
173174
for template_data in self.templates:
174-
info = {}
175175
# Clean up some info about templates
176176
template = template_data["template"]
177177
if hasattr(template, "origin") and template.origin and template.origin.name:
@@ -180,12 +180,15 @@ def generate_stats(self, request, response):
180180
else:
181181
template.origin_name = _("No origin")
182182
template.origin_hash = ""
183-
info["template"] = force_str(template)
183+
context = {
184+
"template": force_str(template),
185+
"name": template.name,
186+
}
184187
# Clean up context for better readability
185188
if self.toolbar.config["SHOW_TEMPLATE_CONTEXT"]:
186189
context_list = template_data.get("context", [])
187-
info["context"] = "\n".join(context_list)
188-
template_context.append(info)
190+
context["context"] = "\n".join(context_list)
191+
template_context.append(context)
189192

190193
# Fetch context_processors/template_dirs from any template
191194
if self.templates:

debug_toolbar/panels/timer.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ class TimerPanel(Panel):
1919

2020
def nav_subtitle(self):
2121
stats = self.get_stats()
22-
if hasattr(self, "_start_rusage"):
23-
utime = self._end_rusage.ru_utime - self._start_rusage.ru_utime
24-
stime = self._end_rusage.ru_stime - self._start_rusage.ru_stime
22+
if stats.get("utime"):
23+
utime = stats.get("utime")
24+
stime = stats.get("stime")
2525
return _("CPU: %(cum)0.2fms (%(total)0.2fms)") % {
26-
"cum": (utime + stime) * 1000.0,
26+
"cum": (utime + stime),
2727
"total": stats["total_time"],
2828
}
2929
elif "total_time" in stats:
@@ -64,27 +64,44 @@ def process_request(self, request):
6464
self._start_rusage = resource.getrusage(resource.RUSAGE_SELF)
6565
return super().process_request(request)
6666

67+
def serialize_rusage(self, data):
68+
fields_to_serialize = [
69+
"ru_utime",
70+
"ru_stime",
71+
"ru_nvcsw",
72+
"ru_nivcsw",
73+
"ru_minflt",
74+
"ru_majflt",
75+
]
76+
return {field: getattr(data, field) for field in fields_to_serialize}
77+
6778
def generate_stats(self, request, response):
6879
stats = {}
6980
if hasattr(self, "_start_time"):
7081
stats["total_time"] = (perf_counter() - self._start_time) * 1000
71-
if hasattr(self, "_start_rusage"):
82+
if self.has_content:
7283
self._end_rusage = resource.getrusage(resource.RUSAGE_SELF)
73-
stats["utime"] = 1000 * self._elapsed_ru("ru_utime")
74-
stats["stime"] = 1000 * self._elapsed_ru("ru_stime")
84+
start = self.serialize_rusage(self._start_rusage)
85+
end = self.serialize_rusage(self._end_rusage)
86+
stats.update(
87+
{
88+
"utime": 1000 * self._elapsed_ru(start, end, "ru_utime"),
89+
"stime": 1000 * self._elapsed_ru(start, end, "ru_stime"),
90+
"vcsw": self._elapsed_ru(start, end, "ru_nvcsw"),
91+
"ivcsw": self._elapsed_ru(start, end, "ru_nivcsw"),
92+
"minflt": self._elapsed_ru(start, end, "ru_minflt"),
93+
"majflt": self._elapsed_ru(start, end, "ru_majflt"),
94+
}
95+
)
7596
stats["total"] = stats["utime"] + stats["stime"]
76-
stats["vcsw"] = self._elapsed_ru("ru_nvcsw")
77-
stats["ivcsw"] = self._elapsed_ru("ru_nivcsw")
78-
stats["minflt"] = self._elapsed_ru("ru_minflt")
79-
stats["majflt"] = self._elapsed_ru("ru_majflt")
8097
# these are documented as not meaningful under Linux. If you're
8198
# running BSD feel free to enable them, and add any others that I
8299
# hadn't gotten to before I noticed that I was getting nothing but
83100
# zeroes and that the docs agreed. :-(
84101
#
85-
# stats['blkin'] = self._elapsed_ru('ru_inblock')
86-
# stats['blkout'] = self._elapsed_ru('ru_oublock')
87-
# stats['swap'] = self._elapsed_ru('ru_nswap')
102+
# stats['blkin'] = self._elapsed_ru(start, end, 'ru_inblock')
103+
# stats['blkout'] = self._elapsed_ru(start, end, 'ru_oublock')
104+
# stats['swap'] = self._elapsed_ru(start, end, 'ru_nswap')
88105
# stats['rss'] = self._end_rusage.ru_maxrss
89106
# stats['srss'] = self._end_rusage.ru_ixrss
90107
# stats['urss'] = self._end_rusage.ru_idrss
@@ -102,5 +119,6 @@ def generate_server_timing(self, request, response):
102119
"total_time", "Elapsed time", stats.get("total_time", 0)
103120
)
104121

105-
def _elapsed_ru(self, name):
106-
return getattr(self._end_rusage, name) - getattr(self._start_rusage, name)
122+
@staticmethod
123+
def _elapsed_ru(start, end, name):
124+
return end.get(name) - start.get(name)

debug_toolbar/panels/versions.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class VersionsPanel(Panel):
1414

1515
@property
1616
def nav_subtitle(self):
17-
return "Django %s" % django.get_version()
17+
return "Django %s" % self.get_stats()["django_version"]
1818

1919
title = _("Versions")
2020

@@ -27,7 +27,11 @@ def generate_stats(self, request, response):
2727
]
2828
versions += list(self.gen_app_versions())
2929
self.record_stats(
30-
{"versions": sorted(versions, key=lambda v: v[0]), "paths": sys.path}
30+
{
31+
"django_version": django.get_version(),
32+
"versions": sorted(versions, key=lambda v: v[0]),
33+
"paths": sys.path,
34+
}
3135
)
3236

3337
def gen_app_versions(self):

debug_toolbar/store.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@ def panel(cls, request_id: str, panel_id: str) -> Any:
128128
else:
129129
return deserialize(data)
130130

131+
@classmethod
132+
def panels(cls, request_id: str) -> Any:
133+
"""Fetch all the panel data for the given request_id"""
134+
try:
135+
panel_mapping = cls._request_store[request_id]
136+
except KeyError:
137+
return {}
138+
for panel, data in panel_mapping.items():
139+
yield panel, deserialize(data)
140+
131141

132142
def get_store() -> BaseStore:
133143
return import_string(dt_settings.get_config()["TOOLBAR_STORE_CLASS"])

0 commit comments

Comments
 (0)