Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQL panel work #1786

Merged
merged 6 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions debug_toolbar/panels/sql/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.urls import path
from django.utils.translation import gettext_lazy as _, ngettext

from debug_toolbar import settings as dt_settings
from debug_toolbar.forms import SignedDataForm
from debug_toolbar.panels import Panel
from debug_toolbar.panels.sql import views
Expand Down Expand Up @@ -110,9 +111,7 @@ class SQLPanel(Panel):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._offset = {k: len(connections[k].queries) for k in connections}
self._sql_time = 0
self._num_queries = 0
self._queries = []
self._databases = {}
# synthetic transaction IDs, keyed by DB alias
Expand Down Expand Up @@ -151,20 +150,20 @@ def record(self, **kwargs):
self._databases[alias]["time_spent"] += kwargs["duration"]
self._databases[alias]["num_queries"] += 1
self._sql_time += kwargs["duration"]
self._num_queries += 1

# Implement the Panel API

nav_title = _("SQL")

@property
def nav_subtitle(self):
query_count = len(self._queries)
return ngettext(
"%(query_count)d query in %(sql_time).2fms",
"%(query_count)d queries in %(sql_time).2fms",
self._num_queries,
query_count,
) % {
"query_count": self._num_queries,
"query_count": query_count,
"sql_time": self._sql_time,
}

Expand Down Expand Up @@ -204,6 +203,8 @@ def generate_stats(self, request, response):
duplicate_query_groups = defaultdict(list)

if self._queries:
sql_warning_threshold = dt_settings.get_config()["SQL_WARNING_THRESHOLD"]

width_ratio_tally = 0
factor = int(256.0 / (len(self._databases) * 2.5))
for n, db in enumerate(self._databases.values()):
Expand Down Expand Up @@ -261,6 +262,12 @@ def generate_stats(self, request, response):

if query["sql"]:
query["sql"] = reformat_sql(query["sql"], with_toggle=True)

query["is_slow"] = query["duration"] > sql_warning_threshold
query["is_select"] = (
query["raw_sql"].lower().lstrip().startswith("select")
)

query["rgb_color"] = self._databases[alias]["rgb_color"]
try:
query["width_ratio"] = (query["duration"] / self._sql_time) * 100
Expand Down
23 changes: 11 additions & 12 deletions debug_toolbar/panels/sql/tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from django.db.backends.utils import CursorWrapper
from django.utils.encoding import force_str

from debug_toolbar import settings as dt_settings
from debug_toolbar.utils import get_stack_trace, get_template_info

try:
Expand All @@ -34,8 +33,14 @@ class SQLQueryTriggered(Exception):


def wrap_cursor(connection):
# If running a Django SimpleTestCase, which isn't allowed to access the database,
# don't perform any monkey patching.
# When running a SimpleTestCase, Django monkey patches some DatabaseWrapper
# methods, including .cursor() and .chunked_cursor(), to raise an exception
# if the test code tries to access the database, and then undoes the monkey
# patching when the test case is finished. If we monkey patch those methods
# also, Django's process of undoing those monkey patches will fail. To
# avoid this failure, and because database access is not allowed during a
# SimpleTextCase anyway, skip applying our instrumentation monkey patches if
# we detect that Django has already monkey patched DatabaseWrapper.cursor().
if isinstance(connection.cursor, django.test.testcases._DatabaseFailure):
return
if not hasattr(connection, "_djdt_cursor"):
Expand Down Expand Up @@ -182,7 +187,7 @@ def _record(self, method, sql, params):
else:
sql = str(sql)

params = {
kwargs = {
"vendor": vendor,
"alias": alias,
"sql": self._last_executed_query(sql, params),
Expand All @@ -191,12 +196,6 @@ def _record(self, method, sql, params):
"params": _params,
"raw_params": params,
"stacktrace": get_stack_trace(skip=2),
"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,
}

Expand Down Expand Up @@ -228,7 +227,7 @@ def _record(self, method, sql, params):
else:
trans_id = None

params.update(
kwargs.update(
{
"trans_id": trans_id,
"trans_status": conn.info.transaction_status,
Expand All @@ -237,7 +236,7 @@ def _record(self, method, sql, params):
)

# We keep `sql` to maintain backwards compatibility
self.logger.record(**params)
self.logger.record(**kwargs)

def callproc(self, procname, params=None):
return self._record(super().callproc, procname, params)
Expand Down