[debug-toolbar/rql] add RQL panel

Closes #17219673

authorLaurent Peuch <cortex@worlddomination.be>
changesetd5ae5abd0876
branchdefault
phasepublic
hiddenno
parent revision#ec834074ea25 [debug/emit/rql] add RQL debug channel and emit queries
child revision#10b8352b0208 [debug-toolbar/rql] display sql queries generated by rql ones
files modified by this revision
cubicweb/pyramid/debug_toolbar_templates/rql.dbtmako
cubicweb/pyramid/debugtoolbar_panels.py
# HG changeset patch
# User Laurent Peuch <cortex@worlddomination.be>
# Date 1564539380 -7200
# Wed Jul 31 04:16:20 2019 +0200
# Node ID d5ae5abd0876e91f1d935113befe32b56dfe5f80
# Parent ec834074ea25983246cb5d0a64d36f611c3dd9cd
[debug-toolbar/rql] add RQL panel

Closes #17219673

diff --git a/cubicweb/pyramid/debug_toolbar_templates/rql.dbtmako b/cubicweb/pyramid/debug_toolbar_templates/rql.dbtmako
@@ -0,0 +1,119 @@
1 +<table id="rql-table" class="table table-striped table-condensed">
2 +    <thead>
3 +        <tr>
4 +            <th class="table-col-1">#</th>
5 +            <th class="table-col-2">Time (ms)</th>
6 +            <th class="table-col-3">RQL</th>
7 +            <th class="table-col-5">Result</th>
8 +            <th class="table-col-7">Description</th>
9 +            <th class="table-col-8">Stack</th>
10 +        </tr>
11 +    </thead>
12 +    <tbody>
13 +        % for i, query in enumerate(rql_queries):
14 +            <tr>
15 +                <th class="table-col-1">${1 + i}</th>
16 +                <td class="table-col-2">${'%.2f' % query["time"]}</td>
17 +                <td class="table-col-3">${highlight(query["rql"], "RQL") | n}<br>${highlight(query["args"], "python3") | n}</td>
18 +                % if len(str(query["result"])) > 50:
19 +                <td id="result-${i}" class="table-col-5">
20 +                    <span id="result-${i}-short">
21 +                    ${highlight(str(query["result"])[:50], "python3") | n}...
22 +                    <a title="display more" href="javascript:show_result(${i})"><span class="badge progress-bar-default">+</span></a>
23 +                    </span>
24 +                    <span id="result-${i}-long" style="display: none">
25 +                    ${highlight(query["result"], "python3") | n}
26 +                    <a title="display less" href="javascript:hide_result(${i})"><span class="badge progress-bar-warning">←</span></a>
27 +                    </span>
28 +                </td>
29 +                % else:
30 +                <td class="table-col-5">${highlight(query["result"], "python3") | n}</td>
31 +                % endif
32 +                <td class="table-col-7">${highlight(query["description"], "python3") | n}</td>
33 +                <td class="table-col-8">
34 +                    <a class="btn btn-default" id="show-stack-${i}" href="javascript:show_stack(${i})">show stack</a>
35 +                    <a class="btn btn-default" id="hide-stack-${i}" href="javascript:hide_stack(${i})" style="display: none">hide stack</a>
36 +                </td>
37 +            </tr>
38 +            <tr style="display: none" id="stack-${i}">
39 +                <td colspan="7">
40 +                    <pre>${highlight(query["callstack"], "py3tb", linenos="inline") | n}</pre>
41 +                </td>
42 +            </tr>
43 +            <tr style="display: none"></tr> <!-- css hack because of previous hidden tr for -stripped -->
44 +        % endfor
45 +    </tbody>
46 +</table>
47 +
48 +<script type="text/javascript" charset="utf-8">
49 +    function show_result(result_id) {
50 +        element = document.querySelector("#result-" + result_id + "-long");
51 +        element.style.setProperty("display", "inline");
52 +
53 +        element = document.querySelector("#result-" + result_id + "-short");
54 +        element.style.setProperty("display", "none");
55 +    }
56 +
57 +    function hide_result(result_id) {
58 +        element = document.querySelector("#result-" + result_id + "-short");
59 +        element.style.setProperty("display", "inline");
60 +
61 +        element = document.querySelector("#result-" + result_id + "-long");
62 +        element.style.setProperty("display", "none");
63 +    }
64 +
65 +    function show_stack(stack_id) {
66 +        element = document.querySelector("#stack-" + stack_id);
67 +        element.style.setProperty("display", "table-row");
68 +
69 +        element = document.querySelector("#show-stack-" + stack_id);
70 +        element.style.setProperty("display", "none");
71 +
72 +        element = document.querySelector("#hide-stack-" + stack_id);
73 +        element.style.setProperty("display", "inline");
74 +    }
75 +
76 +    function hide_stack(stack_id) {
77 +        element = document.querySelector("#stack-" + stack_id);
78 +        element.style.setProperty("display", "none");
79 +
80 +        element = document.querySelector("#show-stack-" + stack_id);
81 +        element.style.setProperty("display", "inline");
82 +
83 +        element = document.querySelector("#hide-stack-" + stack_id);
84 +        element.style.setProperty("display", "none");
85 +    }
86 +</script>
87 +
88 +<style>
89 +#rql-table {
90 +    table-layout: fixed;
91 +}
92 +
93 +#rql-table .table-col-1 {
94 +    text-align: right;
95 +    width: 30px;
96 +}
97 +
98 +#rql-table .table-col-2 {
99 +    white-space: nowrap;
100 +    width: 73px;
101 +    text-align: center;
102 +}
103 +
104 +#rql-table .table-col-8 {
105 +    padding: 8px;
106 +    width: 110px;
107 +    text-align: center;
108 +}
109 +
110 +${generate_css() | n}
111 +
112 +.highlight > pre {
113 +    word-break: unset;
114 +    border: none;
115 +    margin: 0;
116 +    padding: 0;
117 +    background-color: unset;
118 +}
119 +</style>
diff --git a/cubicweb/pyramid/debugtoolbar_panels.py b/cubicweb/pyramid/debugtoolbar_panels.py
@@ -0,0 +1,56 @@
120 +# copyright 2019 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
121 +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
122 +#
123 +# This file is part of CubicWeb.
124 +#
125 +# CubicWeb is free software: you can redistribute it and/or modify it under the
126 +# terms of the GNU Lesser General Public License as published by the Free
127 +# Software Foundation, either version 2.1 of the License, or (at your option)
128 +# any later version.
129 +#
130 +# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
131 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
132 +# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
133 +# details.
134 +#
135 +# You should have received a copy of the GNU Lesser General Public License along
136 +# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
137 +
138 +from pyramid_debugtoolbar.panels import DebugPanel
139 +from cubicweb.debug import subscribe_to_debug_channel, unsubscribe_to_debug_channel
140 +from cubicweb.misc.source_highlight import highlight_html, generate_css
141 +
142 +
143 +class RQLDebugPanel(DebugPanel):
144 +    """
145 +    CubicWeb RQL debug panel
146 +    """
147 +    name = 'RQL'
148 +    title = 'RQL queries'
149 +    nav_title = 'RQL'
150 +    nav_subtitle_style = 'progress-bar-info'
151 +
152 +    has_content = True
153 +    template = 'cubicweb.pyramid:debug_toolbar_templates/rql.dbtmako'
154 +
155 +    def __init__(self, request):
156 +        self.data = {
157 +            'rql_queries': [],
158 +            'highlight': highlight_html,
159 +            'generate_css': generate_css,
160 +        }
161 +        subscribe_to_debug_channel("rql", self.collect_rql_queries)
162 +
163 +    @property
164 +    def nav_subtitle(self):
165 +        return '%d' % len(self.data['rql_queries'])
166 +
167 +    def collect_rql_queries(self, rql_query):
168 +        self.data["rql_queries"].append(rql_query)
169 +
170 +    def process_response(self, response):
171 +        unsubscribe_to_debug_channel("rql", self.collect_rql_queries)
172 +
173 +
174 +def includeme(config):
175 +    config.add_debugtoolbar_panel(RQLDebugPanel)