[debug-toolbar] add registry decisions debug panel
authorLaurent Peuch <cortex@worlddomination.be>
Thu, 12 Sep 2019 05:59:10 +0200
changeset 12768 7d2c61d40fe9
parent 12767 d50661367401
child 12769 a61e0fe17a69
[debug-toolbar] add registry decisions debug panel Closes #17219866
cubicweb/cwvreg.py
cubicweb/debug.py
cubicweb/pyramid/debug_toolbar_templates/registry_decisions.dbtmako
cubicweb/pyramid/debugtoolbar_panels.py
--- a/cubicweb/cwvreg.py	Wed Nov 20 20:46:45 2019 +0100
+++ b/cubicweb/cwvreg.py	Thu Sep 12 05:59:10 2019 +0200
@@ -33,6 +33,7 @@
 from yams.constraints import BASE_CONVERTERS
 
 from cubicweb import _
+from cubicweb.debug import emit_to_debug_channel
 from cubicweb import (CW_SOFTWARE_ROOT, ETYPE_NAME_MAP, CW_EVENT_MANAGER,
                       onevent, Binary, UnknownProperty, UnknownEid)
 from cubicweb.predicates import appobject_selectable, _reset_is_instance_cache
@@ -72,6 +73,16 @@
         super(CWRegistry, self).__init__(True)
         self.vreg = vreg
 
+    def _select_best(self, objects, *args, **kwargs):
+        """
+        Overwrite version of Registry._select_best to emit debug information.
+        """
+        def emit_registry_debug_information(debug_registry_select_best):
+            emit_to_debug_channel("registry_decisions", debug_registry_select_best)
+
+        kwargs["debug_callback"] = emit_registry_debug_information
+        return super()._select_best(objects, *args, **kwargs)
+
     @property
     def schema(self):
         """The :py:class:`cubicweb.schema.CubicWebSchema`
--- a/cubicweb/debug.py	Wed Nov 20 20:46:45 2019 +0100
+++ b/cubicweb/debug.py	Thu Sep 12 05:59:10 2019 +0200
@@ -26,6 +26,7 @@
     "rql": [],
     "sql": [],
     "vreg": [],
+    "registry_decisions": [],
 }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/pyramid/debug_toolbar_templates/registry_decisions.dbtmako	Thu Sep 12 05:59:10 2019 +0200
@@ -0,0 +1,65 @@
+<%def name="render_object(obj)">
+% if hasattr(obj, "__name__"):
+    ${obj.__module__}.${obj.__name__}
+% else:
+    ${obj}
+% endif
+</%def>
+
+<table class="table table-bordered table-striped">
+    <tr>
+        <th>Result</th>
+        <th>Decision</th>
+    </tr>
+    <tr></tr>
+% for registry_decision in registry_decisions:
+    <tr>
+        <td colspan="2"><b>${repr(registry_decision["key"])} -&gt; ${render_object(registry_decision["winner"])}</b></td>
+    </tr>
+    <tr>
+        <td>
+            <p>End score: ${registry_decision["end_score"]}</p>
+            <div class="highlight-inline">args: ${highlight(registry_decision["args"], "html") | n}</div>
+            <div>kwargs:
+                <ul>
+                % for key, value in registry_decision["kwargs"].items():
+                    <li>${repr(key)}: ${repr(value)}</li>
+                % endfor
+                </ul>
+            </div>
+        </td>
+
+        <td>
+            <ul>
+                % for obj in registry_decision["all_objects"]:
+                <li>
+                    ${obj["score"]}: ${render_object(obj["object"])}
+                </li>
+                % endfor
+            </ul>
+        </td>
+
+    </tr>
+
+% endfor
+</table>
+<style>
+${generate_css() | n}
+
+.highlight-inline {
+    margin: 0 0 10px; /* like <p> */
+}
+
+.highlight-inline > .highlight {
+    display: inline;
+}
+
+.highlight > pre {
+    word-break: unset;
+    border: none;
+    margin: 0;
+    padding: 0;
+    background-color: unset;
+    display: inline;
+}
+</style>
--- a/cubicweb/pyramid/debugtoolbar_panels.py	Wed Nov 20 20:46:45 2019 +0100
+++ b/cubicweb/pyramid/debugtoolbar_panels.py	Thu Sep 12 05:59:10 2019 +0200
@@ -54,6 +54,59 @@
         unsubscribe_to_debug_channel("controller", self.collect_controller)
 
 
+class RegistryDecisionsDebugPanel(DebugPanel):
+    """
+    CubicWeb registry decisions debug panel
+    """
+
+    name = 'RegistryDecisions'
+    title = 'Registry Decisions'
+    nav_title = 'Registry Decisions'
+
+    has_content = True
+    template = 'cubicweb.pyramid:debug_toolbar_templates/registry_decisions.dbtmako'
+
+    def __init__(self, request):
+        # clear on every new response
+        self.data = {
+            'registry_decisions': [],
+            'vreg': None,
+            'highlight': highlight_html,
+            'generate_css': generate_css,
+        }
+
+        subscribe_to_debug_channel("vreg", self.collect_vreg)
+        subscribe_to_debug_channel("registry_decisions", self.collect_registry_decisions)
+
+    def collect_vreg(self, message):
+        self.data["vreg"] = message["vreg"]
+
+    def collect_registry_decisions(self, decision):
+        # decision = {
+        #     "all_objects": [],
+        #     "end_score": int,
+        #     "winners": [],
+        #     "registry": obj,
+        #     "args": args,
+        #     "kwargs": kwargs,
+        # }
+        decision["key"] = None
+        self.data["registry_decisions"].append(decision)
+
+    def link_registry_to_their_key(self):
+        if self.data["vreg"]:
+            # use "id" here to be hashable
+            registry_to_key = {id(registry): key for key, registry in self.data["vreg"].items()}
+            for decision in self.data["registry_decisions"]:
+                decision["key"] = registry_to_key.get(id(decision["self"]))
+
+    def process_response(self, response):
+        unsubscribe_to_debug_channel("registry_decisions", self.collect_registry_decisions)
+        unsubscribe_to_debug_channel("vreg", self.collect_vreg)
+
+        self.link_registry_to_their_key()
+
+
 class RegistryDebugPanel(DebugPanel):
     """
     CubicWeb registry content and decisions debug panel
@@ -190,6 +243,7 @@
 
 def includeme(config):
     config.add_debugtoolbar_panel(CubicWebDebugPanel)
+    config.add_debugtoolbar_panel(RegistryDecisionsDebugPanel)
     config.add_debugtoolbar_panel(RegistryDebugPanel)
     config.add_debugtoolbar_panel(RQLDebugPanel)
     config.add_debugtoolbar_panel(SQLDebugPanel)