From b6128b1e7258ef6076f5f04a16fadc86e9fa8068 Mon Sep 17 00:00:00 2001 From: tschilling Date: Tue, 4 Jul 2023 08:08:32 -0500 Subject: [PATCH 1/2] Log serialization warning when a panel errors. This will help third party panels identify issues with serializing the content of their panels in the future, without causing the entire toolbar to break. --- debug_toolbar/settings.py | 1 + debug_toolbar/store.py | 12 +++++++++++- docs/changes.rst | 2 ++ docs/configuration.rst | 8 ++++++++ tests/test_store.py | 17 +++++++++++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/debug_toolbar/settings.py b/debug_toolbar/settings.py index fcd253c59..a7d49adb5 100644 --- a/debug_toolbar/settings.py +++ b/debug_toolbar/settings.py @@ -37,6 +37,7 @@ "PROFILER_CAPTURE_PROJECT_CODE": True, "PROFILER_MAX_DEPTH": 10, "PROFILER_THRESHOLD_RATIO": 8, + "SERIALIZATION_WARNINGS": True, "SHOW_TEMPLATE_CONTEXT": True, "SKIP_TEMPLATE_PREFIXES": ("django/forms/widgets/", "admin/widgets/"), "SQL_WARNING_THRESHOLD": 500, # milliseconds diff --git a/debug_toolbar/store.py b/debug_toolbar/store.py index b32d3b62a..571b7fffb 100644 --- a/debug_toolbar/store.py +++ b/debug_toolbar/store.py @@ -1,5 +1,6 @@ import contextlib import json +import logging from collections import defaultdict, deque from typing import Any, Dict, Iterable @@ -8,6 +9,8 @@ from debug_toolbar import settings as dt_settings +logger = logging.getLogger(__name__) + def serialize(data: Any) -> str: # If this starts throwing an exceptions, consider @@ -103,7 +106,14 @@ def delete(cls, request_id: str): def save_panel(cls, request_id: str, panel_id: str, data: Any = None): """Save the panel data for the given request_id""" cls.set(request_id) - cls._request_store[request_id][panel_id] = serialize(data) + try: + cls._request_store[request_id][panel_id] = serialize(data) + except TypeError: + if dt_settings.get_config()["SERIALIZATION_WARNINGS"]: + log = "Panel (%s) failed to serialized data %s properly." + logger.warning(log % (panel_id, data)) + else: + raise @classmethod def panel(cls, request_id: str, panel_id: str) -> Any: diff --git a/docs/changes.rst b/docs/changes.rst index 9d70eb418..60ec26e6a 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -7,6 +7,8 @@ Serializable (don't include in main) * Defines the ``BaseStore`` interface for request storage mechanisms. * Added the setting ``TOOLBAR_STORE_CLASS`` to configure the request storage mechanism. Defaults to ``debug_toolbar.store.MemoryStore``. +* Added setting ``SERIALIZATION_WARNINGS`` to log a warning when a + ``TypeError`` occurs during a panel's serialization. Pending diff --git a/docs/configuration.rst b/docs/configuration.rst index f2f6b7de9..fd27aad82 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -306,6 +306,14 @@ Panel options the nested functions. The threshold is calculated by the root calls' cumulative time divided by this ratio. +* ``SERIALIZATION_WARNINGS`` + + Default: ``True`` + + If set to ``True`` then panels will log a warning if a ``TypeError`` is + raised when attempting to serialize a panel's stats. The default will + eventually be set to ``False`` and removed entirely. + * ``SHOW_TEMPLATE_CONTEXT`` Default: ``True`` diff --git a/tests/test_store.py b/tests/test_store.py index c51afde1e..1c17aaf96 100644 --- a/tests/test_store.py +++ b/tests/test_store.py @@ -1,3 +1,5 @@ +import logging + from django.test import TestCase from django.test.utils import override_settings @@ -93,6 +95,21 @@ def test_save_panel(self): self.assertEqual(list(self.store.request_ids()), ["bar"]) self.assertEqual(self.store.panel("bar", "bar.panel"), {"a": 1}) + def test_save_panel_serialization_warning(self): + """The store should warn the user about a serialization error.""" + self.assertLogs() + + with self.assertLogs("debug_toolbar.store", level=logging.WARNING) as logs: + self.store.save_panel("bar", "bar.panel", {"value": {"foo"}}) + + self.assertEqual( + logs.output, + [ + "WARNING:debug_toolbar.store:Panel (bar.panel) failed to " + "serialized data {'value': {'foo'}} properly." + ], + ) + def test_panel(self): self.assertEqual(self.store.panel("missing", "missing"), {}) self.store.save_panel("bar", "bar.panel", {"a": 1}) From b686789fedc83403110c059eac03fd8b47d6cfa6 Mon Sep 17 00:00:00 2001 From: Tim Schilling Date: Sun, 20 Aug 2023 14:31:16 -0500 Subject: [PATCH 2/2] Change setting name to SUPPRESS_SERIALIZATION_ERRORS --- debug_toolbar/settings.py | 2 +- debug_toolbar/store.py | 2 +- docs/changes.rst | 4 ++-- docs/configuration.rst | 7 ++++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/debug_toolbar/settings.py b/debug_toolbar/settings.py index a7d49adb5..b2a07dcd9 100644 --- a/debug_toolbar/settings.py +++ b/debug_toolbar/settings.py @@ -37,7 +37,7 @@ "PROFILER_CAPTURE_PROJECT_CODE": True, "PROFILER_MAX_DEPTH": 10, "PROFILER_THRESHOLD_RATIO": 8, - "SERIALIZATION_WARNINGS": True, + "SUPPRESS_SERIALIZATION_ERRORS": True, "SHOW_TEMPLATE_CONTEXT": True, "SKIP_TEMPLATE_PREFIXES": ("django/forms/widgets/", "admin/widgets/"), "SQL_WARNING_THRESHOLD": 500, # milliseconds diff --git a/debug_toolbar/store.py b/debug_toolbar/store.py index 571b7fffb..0bba0c2ef 100644 --- a/debug_toolbar/store.py +++ b/debug_toolbar/store.py @@ -109,7 +109,7 @@ def save_panel(cls, request_id: str, panel_id: str, data: Any = None): try: cls._request_store[request_id][panel_id] = serialize(data) except TypeError: - if dt_settings.get_config()["SERIALIZATION_WARNINGS"]: + if dt_settings.get_config()["SUPPRESS_SERIALIZATION_ERRORS"]: log = "Panel (%s) failed to serialized data %s properly." logger.warning(log % (panel_id, data)) else: diff --git a/docs/changes.rst b/docs/changes.rst index 60ec26e6a..2dea4306f 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -7,8 +7,8 @@ Serializable (don't include in main) * Defines the ``BaseStore`` interface for request storage mechanisms. * Added the setting ``TOOLBAR_STORE_CLASS`` to configure the request storage mechanism. Defaults to ``debug_toolbar.store.MemoryStore``. -* Added setting ``SERIALIZATION_WARNINGS`` to log a warning when a - ``TypeError`` occurs during a panel's serialization. +* Added setting ``SUPPRESS_SERIALIZATION_ERRORS`` to suppress + warnings when a ``TypeError`` occurs during a panel's serialization. Pending diff --git a/docs/configuration.rst b/docs/configuration.rst index fd27aad82..d9d03a853 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -306,13 +306,14 @@ Panel options the nested functions. The threshold is calculated by the root calls' cumulative time divided by this ratio. -* ``SERIALIZATION_WARNINGS`` +* ``SUPPRESS_SERIALIZATION_ERRORS`` Default: ``True`` If set to ``True`` then panels will log a warning if a ``TypeError`` is - raised when attempting to serialize a panel's stats. The default will - eventually be set to ``False`` and removed entirely. + raised when attempting to serialize a panel's stats rather than raising an + exception.. If set to ``False`` then the ``TypeError`` will be raised. The + default will eventually be set to ``False`` and removed entirely. * ``SHOW_TEMPLATE_CONTEXT``