Skip to content

Commit 487dfb3

Browse files
Log serialization warning when a panel errors. (#1810)
* 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. * Change setting name to SUPPRESS_SERIALIZATION_ERRORS
1 parent 97fcda7 commit 487dfb3

File tree

5 files changed

+40
-1
lines changed

5 files changed

+40
-1
lines changed

debug_toolbar/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"PROFILER_CAPTURE_PROJECT_CODE": True,
3838
"PROFILER_MAX_DEPTH": 10,
3939
"PROFILER_THRESHOLD_RATIO": 8,
40+
"SUPPRESS_SERIALIZATION_ERRORS": True,
4041
"SHOW_TEMPLATE_CONTEXT": True,
4142
"SKIP_TEMPLATE_PREFIXES": ("django/forms/widgets/", "admin/widgets/"),
4243
"SQL_WARNING_THRESHOLD": 500, # milliseconds

debug_toolbar/store.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import contextlib
22
import json
3+
import logging
34
from collections import defaultdict, deque
45
from typing import Any, Dict, Iterable
56

@@ -8,6 +9,8 @@
89

910
from debug_toolbar import settings as dt_settings
1011

12+
logger = logging.getLogger(__name__)
13+
1114

1215
def serialize(data: Any) -> str:
1316
# If this starts throwing an exceptions, consider
@@ -103,7 +106,14 @@ def delete(cls, request_id: str):
103106
def save_panel(cls, request_id: str, panel_id: str, data: Any = None):
104107
"""Save the panel data for the given request_id"""
105108
cls.set(request_id)
106-
cls._request_store[request_id][panel_id] = serialize(data)
109+
try:
110+
cls._request_store[request_id][panel_id] = serialize(data)
111+
except TypeError:
112+
if dt_settings.get_config()["SUPPRESS_SERIALIZATION_ERRORS"]:
113+
log = "Panel (%s) failed to serialized data %s properly."
114+
logger.warning(log % (panel_id, data))
115+
else:
116+
raise
107117

108118
@classmethod
109119
def panel(cls, request_id: str, panel_id: str) -> Any:

docs/changes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Serializable (don't include in main)
77
* Defines the ``BaseStore`` interface for request storage mechanisms.
88
* Added the setting ``TOOLBAR_STORE_CLASS`` to configure the request
99
storage mechanism. Defaults to ``debug_toolbar.store.MemoryStore``.
10+
* Added setting ``SUPPRESS_SERIALIZATION_ERRORS`` to suppress
11+
warnings when a ``TypeError`` occurs during a panel's serialization.
1012

1113

1214
Pending

docs/configuration.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,15 @@ Panel options
306306
the nested functions. The threshold is calculated by the root calls'
307307
cumulative time divided by this ratio.
308308

309+
* ``SUPPRESS_SERIALIZATION_ERRORS``
310+
311+
Default: ``True``
312+
313+
If set to ``True`` then panels will log a warning if a ``TypeError`` is
314+
raised when attempting to serialize a panel's stats rather than raising an
315+
exception.. If set to ``False`` then the ``TypeError`` will be raised. The
316+
default will eventually be set to ``False`` and removed entirely.
317+
309318
* ``SHOW_TEMPLATE_CONTEXT``
310319

311320
Default: ``True``

tests/test_store.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import logging
2+
13
from django.test import TestCase
24
from django.test.utils import override_settings
35

@@ -93,6 +95,21 @@ def test_save_panel(self):
9395
self.assertEqual(list(self.store.request_ids()), ["bar"])
9496
self.assertEqual(self.store.panel("bar", "bar.panel"), {"a": 1})
9597

98+
def test_save_panel_serialization_warning(self):
99+
"""The store should warn the user about a serialization error."""
100+
self.assertLogs()
101+
102+
with self.assertLogs("debug_toolbar.store", level=logging.WARNING) as logs:
103+
self.store.save_panel("bar", "bar.panel", {"value": {"foo"}})
104+
105+
self.assertEqual(
106+
logs.output,
107+
[
108+
"WARNING:debug_toolbar.store:Panel (bar.panel) failed to "
109+
"serialized data {'value': {'foo'}} properly."
110+
],
111+
)
112+
96113
def test_panel(self):
97114
self.assertEqual(self.store.panel("missing", "missing"), {})
98115
self.store.save_panel("bar", "bar.panel", {"a": 1})

0 commit comments

Comments
 (0)