diff --git a/debug_toolbar/middleware.py b/debug_toolbar/middleware.py index 03044f3a4..1bf9b4e70 100644 --- a/debug_toolbar/middleware.py +++ b/debug_toolbar/middleware.py @@ -112,7 +112,10 @@ async def __acall__(self, request): # Activate instrumentation ie. monkey-patch. for panel in toolbar.enabled_panels: - panel.enable_instrumentation() + if hasattr(panel, "aenable_instrumentation"): + await panel.aenable_instrumentation() + else: + panel.enable_instrumentation() try: # Run panels like Django middleware. response = await toolbar.process_request(request) diff --git a/debug_toolbar/panels/__init__.py b/debug_toolbar/panels/__init__.py index de18f95e3..217708ec2 100644 --- a/debug_toolbar/panels/__init__.py +++ b/debug_toolbar/panels/__init__.py @@ -154,6 +154,9 @@ def enable_instrumentation(self): Unless the toolbar or this panel is disabled, this method will be called early in ``DebugToolbarMiddleware``. It should be idempotent. + + Add the ``aenable_instrumentation`` method to a panel subclass + to support async logic for instrumentation. """ def disable_instrumentation(self): diff --git a/debug_toolbar/panels/sql/panel.py b/debug_toolbar/panels/sql/panel.py index 7be5c4da6..fe18a9c11 100644 --- a/debug_toolbar/panels/sql/panel.py +++ b/debug_toolbar/panels/sql/panel.py @@ -2,6 +2,7 @@ from collections import defaultdict from copy import copy +from asgiref.sync import sync_to_async from django.db import connections from django.urls import path from django.utils.translation import gettext_lazy as _, ngettext @@ -113,7 +114,7 @@ class SQLPanel(Panel): the request. """ - is_async = False + is_async = True def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -192,6 +193,13 @@ def get_urls(cls): path("sql_profile/", views.sql_profile, name="sql_profile"), ] + async def aenable_instrumentation(self): + """ + Async version of enable instrumentation. + For async capable panels having async logic for instrumentation. + """ + await sync_to_async(self.enable_instrumentation)() + def enable_instrumentation(self): # This is thread-safe because database connections are thread-local. for connection in connections.all(): diff --git a/docs/architecture.rst b/docs/architecture.rst index cf5c54951..54b3b9318 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -81,8 +81,7 @@ Problematic Parts the main benefit of the toolbar - Support for async and multi-threading: ``debug_toolbar.middleware.DebugToolbarMiddleware`` is now async compatible and can process async requests. However certain - panels such as ``SQLPanel``, ``TimerPanel``, - ``RequestPanel`` and ``ProfilingPanel`` aren't fully - compatible and currently being worked on. For now, these panels + panels such as ``TimerPanel``, ``RequestPanel`` and ``ProfilingPanel`` aren't + fully compatible and currently being worked on. For now, these panels are disabled by default when running in async environment. follow the progress of this issue in `Async compatible toolbar project `_. diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 829ff9bec..662e6df4f 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -6,7 +6,9 @@ Pympler Roboto Transifex Werkzeug +aenable ajax +asgi async backend backends @@ -21,6 +23,7 @@ flatpages frontend htmx inlining +instrumentation isort jQuery jinja