Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 01dfca1

Browse files
committed
feature #28934 [WebProfilerBundle] Add channel log filter (ro0NL)
This PR was squashed before being merged into the 4.2-dev branch (closes #28934). Discussion ---------- [WebProfilerBundle] Add channel log filter | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #... <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> Continuation of #28906 The JS is revised to be more generic; - support 2 filter types: `level` and `choice` (respectively `Log level` and `Log channel` here) - remove default filter value support (not used yet, but opportunity kept open) - it requires a bit more work to genericify it. - filters refines the resultset (e.g. show all logs in the app channel with priority higher than alert) ![image](https://user-images.githubusercontent.com/1047696/47257162-b01bfe00-d48a-11e8-8364-d1eca69c9182.png) Level filter (works the same as shown in #28906 ) ![image](https://user-images.githubusercontent.com/1047696/47257699-78648480-d491-11e8-8c55-1dccda980de4.png) Choice filter ![image](https://user-images.githubusercontent.com/1047696/47257205-3c2e2580-d48b-11e8-821b-e95bfed36331.png) ![image](https://user-images.githubusercontent.com/1047696/47257209-4bad6e80-d48b-11e8-8fcc-e868aa556ff8.png) We forgot to update TwigBundle previously, that's still needed after review here. Commits ------- e1bd82e [WebProfilerBundle] Add channel log filter
2 parents e0c6049 + e1bd82e commit 01dfca1

File tree

8 files changed

+301
-141
lines changed

8 files changed

+301
-141
lines changed

src/Symfony/Bundle/TwigBundle/Resources/views/Exception/logs.html.twig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{% set channel_is_defined = (logs|first).channel is defined %}
2-
<table class="logs" data-log-levels="Emergency,Alert,Critical,Error,Warning,Notice,Info,Debug" data-default-log-level="Info">
2+
<table class="logs" data-filter-level="Emergency,Alert,Critical,Error,Warning,Notice,Info,Debug" data-filters>
33
<thead>
44
<tr>
5-
<th>Level</th>
6-
{% if channel_is_defined %}<th>Channel</th>{% endif %}
5+
<th data-filter="level">Level</th>
6+
{% if channel_is_defined %}<th data-filter="channel">Channel</th>{% endif %}
77
<th class="full-width">Message</th>
88
</tr>
99
</thead>
@@ -18,7 +18,7 @@
1818
{% set severity = log.context.exception.severity|default(false) %}
1919
{% set status = severity is constant('E_DEPRECATED') or severity is constant('E_USER_DEPRECATED') ? 'warning' : 'normal' %}
2020
{% endif %}
21-
<tr class="status-{{ status }}" data-log-level="{{ log.priorityName|lower }}">
21+
<tr class="status-{{ status }}" data-filter-level="{{ log.priorityName|lower }}"{% if channel_is_defined %} data-filter-channel="{{ log.channel }}"{% endif %}>
2222
<td class="text-small" nowrap>
2323
<span class="colored text-bold">{{ log.priorityName }}</span>
2424
<span class="text-muted newline">{{ log.timestamp|date('H:i:s') }}</span>

src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig

Lines changed: 89 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -173,50 +173,102 @@
173173
}
174174
},
175175
176-
createLogLevels: function() {
177-
document.querySelectorAll('.logs[data-log-levels]').forEach(function (el) {
178-
var bullets = document.createElement('ul'),
179-
levels = el.getAttribute('data-log-levels').toLowerCase().split(','),
180-
defaultLevel = el.hasAttribute('data-default-log-level') ? levels.indexOf(el.getAttribute('data-default-log-level').toLowerCase()) : levels.length - 1;
181-
addClass(bullets, 'log-levels');
182-
el.getAttribute('data-log-levels').split(',').forEach(function (level, i) {
183-
var bullet = document.createElement('li');
184-
bullet.innerText = level;
185-
bullet.setAttribute('data-log-level', String(i));
186-
bullets.appendChild(bullet);
187-
addEventListener(bullet, 'click', function() {
188-
if (i === this.parentNode.querySelectorAll('.active').length - 1) {
189-
return;
190-
}
191-
this.parentNode.querySelectorAll('li').forEach(function (bullet, j) {
192-
if (parseInt(bullet.getAttribute('data-log-level')) <= levels.indexOf(level.toLowerCase())) {
193-
addClass(bullet, 'active');
194-
if (i === j) {
195-
addClass(bullet, 'last-active');
196-
} else {
197-
removeClass(bullet, 'last-active');
176+
createFilters: function() {
177+
document.querySelectorAll('[data-filters] [data-filter]').forEach(function (filter) {
178+
var filters = filter.closest('[data-filters]'),
179+
type = 'choice',
180+
name = filter.dataset.filter,
181+
ucName = name.charAt(0).toUpperCase()+name.slice(1),
182+
list = document.createElement('ul'),
183+
values = filters.dataset['filter'+ucName] || filters.querySelectorAll('[data-filter-'+name+']'),
184+
labels = {},
185+
defaults = null,
186+
indexed = {},
187+
processed = {};
188+
if (typeof values === 'string') {
189+
type = 'level';
190+
labels = values.split(',');
191+
values = values.toLowerCase().split(',');
192+
defaults = values.length - 1;
193+
}
194+
addClass(list, 'filter-list');
195+
addClass(list, 'filter-list-'+type);
196+
values.forEach(function (value, i) {
197+
if (value instanceof HTMLElement) {
198+
value = value.dataset['filter'+ucName];
199+
}
200+
if (value in processed) {
201+
return;
202+
}
203+
var option = document.createElement('li'),
204+
label = i in labels ? labels[i] : value,
205+
active = false,
206+
matches;
207+
if ('' === label) {
208+
option.innerHTML = '<em>(none)</em>';
209+
} else {
210+
option.innerText = label;
211+
}
212+
option.dataset.filter = value;
213+
option.setAttribute('title', 1 === (matches = filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').length) ? 'Matches 1 row' : 'Matches '+matches+' rows');
214+
indexed[value] = i;
215+
list.appendChild(option);
216+
addEventListener(option, 'click', function () {
217+
if ('choice' === type) {
218+
filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) {
219+
if (option.dataset.filter === row.dataset['filter'+ucName]) {
220+
toggleClass(row, 'filter-hidden-'+name);
198221
}
199-
} else {
200-
removeClass(bullet, 'active');
201-
removeClass(bullet, 'last-active');
222+
});
223+
toggleClass(option, 'active');
224+
} else if ('level' === type) {
225+
if (i === this.parentNode.querySelectorAll('.active').length - 1) {
226+
return;
202227
}
203-
});
204-
el.querySelectorAll('tr[data-log-level]').forEach(function (row) {
205-
row.style.display = i < levels.indexOf(row.getAttribute('data-log-level')) ? 'none' : '';
206-
});
228+
this.parentNode.querySelectorAll('li').forEach(function (currentOption, j) {
229+
if (j <= i) {
230+
addClass(currentOption, 'active');
231+
if (i === j) {
232+
addClass(currentOption, 'last-active');
233+
} else {
234+
removeClass(currentOption, 'last-active');
235+
}
236+
} else {
237+
removeClass(currentOption, 'active');
238+
removeClass(currentOption, 'last-active');
239+
}
240+
});
241+
filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) {
242+
if (i < indexed[row.dataset['filter'+ucName]]) {
243+
addClass(row, 'filter-hidden-'+name);
244+
} else {
245+
removeClass(row, 'filter-hidden-'+name);
246+
}
247+
});
248+
}
207249
});
208-
if (i <= defaultLevel) {
209-
addClass(bullet, 'active');
210-
if (i === defaultLevel) {
211-
addClass(bullet, 'last-active');
250+
if ('choice' === type) {
251+
active = null === defaults || 0 <= defaults.indexOf(value);
252+
} else if ('level' === type) {
253+
active = i <= defaults;
254+
if (active && i === defaults) {
255+
addClass(option, 'last-active');
212256
}
257+
}
258+
if (active) {
259+
addClass(option, 'active');
213260
} else {
214-
el.querySelectorAll('tr[data-log-level="'+level.toLowerCase()+'"]').forEach(function (row) {
215-
row.style.display = 'none';
261+
filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').forEach(function (row) {
262+
toggleClass(row, 'filter-hidden-'+name);
216263
});
217264
}
265+
processed[value] = true;
218266
});
219-
el.parentNode.insertBefore(bullets, el);
267+
268+
if (1 < list.childNodes.length) {
269+
filter.appendChild(list);
270+
filter.dataset.filtered = '';
271+
}
220272
});
221273
}
222274
};
@@ -225,7 +277,7 @@
225277
Sfjs.addEventListener(document, 'DOMContentLoaded', function() {
226278
Sfjs.createTabs();
227279
Sfjs.createToggles();
228-
Sfjs.createLogLevels();
280+
Sfjs.createFilters();
229281
});
230282
231283
/*]]>*/</script>

src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,39 @@
1+
{# This file is based on WebProfilerBundle/Resources/views/Profiler/profiler.css.twig.
2+
If you make any change in this file, verify the same change is needed in the other file. #}
3+
:root {
4+
--font-sans-serif: 'Helvetica, Arial, sans-serif';
5+
--page-background: #f9f9f9;
6+
--color-text: #222;
7+
/* when updating any of these colors, do the same in toolbar.css.twig */
8+
--color-success: #4f805d;
9+
--color-warning: #a46a1f;
10+
--color-error: #b0413e;
11+
--color-muted: #999;
12+
--tab-background: #fff;
13+
--tab-color: #444;
14+
--tab-active-background: #666;
15+
--tab-active-color: #fafafa;
16+
--tab-disabled-background: #f5f5f5;
17+
--tab-disabled-color: #999;
18+
--metric-value-background: #fff;
19+
--metric-value-color: inherit;
20+
--metric-unit-color: #999;
21+
--metric-label-background: #e0e0e0;
22+
--metric-label-color: inherit;
23+
--table-border: #e0e0e0;
24+
--table-background: #fff;
25+
--table-header: #e0e0e0;
26+
--shadow: 0px 0px 1px rgba(128, 128, 128, .2);
27+
--border: 1px solid #e0e0e0;
28+
--base-0: #fff;
29+
--base-1: #f5f5f5;
30+
--base-2: #e0e0e0;
31+
--base-3: #ccc;
32+
--base-4: #666;
33+
--base-5: #444;
34+
--base-6: #222;
35+
}
36+
137
html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}
238

339
html {
@@ -20,6 +56,7 @@ table th { background-color: #E0E0E0; font-weight: bold; text-align: left; }
2056
.m-t-5 { margin-top: 5px; }
2157
.hidden-xs-down { display: none; }
2258
.block { display: block; }
59+
.full-width { width: 100%; }
2360
.hidden { display: none; }
2461
.prewrap { white-space: pre-wrap; }
2562
.nowrap { white-space: nowrap; }
@@ -58,6 +95,40 @@ thead.sf-toggle-content.sf-toggle-visible, tbody.sf-toggle-content.sf-toggle-vis
5895
.tab-navigation li .badge.status-error { background: #B0413E; color: #FFF; }
5996
.tab-content > *:first-child { margin-top: 0; }
6097

98+
[data-filters] { position: relative; }
99+
[data-filtered] { cursor: pointer; }
100+
[data-filtered]:after { content: '\00a0\25BE'; }
101+
[data-filtered]:hover .filter-list li { display: inline-flex; }
102+
[class*="filter-hidden-"] { display: none; }
103+
.filter-list { position: absolute; border: var(--border); box-shadow: var(--shadow); margin: 0; padding: 0; display: flex; flex-direction: column; }
104+
.filter-list :after { content: ''; }
105+
.filter-list li {
106+
background: var(--tab-disabled-background);
107+
border-bottom: var(--border);
108+
color: var(--tab-disabled-color);
109+
display: none;
110+
list-style: none;
111+
margin: 0;
112+
padding: 5px 10px;
113+
text-align: left;
114+
font-weight: normal;
115+
}
116+
.filter-list li.active {
117+
background: var(--tab-background);
118+
color: var(--tab-color);
119+
}
120+
.filter-list li.last-active {
121+
background: var(--tab-active-background);
122+
color: var(--tab-active-color);
123+
}
124+
125+
.filter-list-level li { cursor: s-resize; }
126+
.filter-list-level li.active { cursor: n-resize; }
127+
.filter-list-level li.last-active { cursor: default; }
128+
.filter-list-level li.last-active:before { content: '\2714\00a0'; }
129+
.filter-list-choice li:before { content: '\2714\00a0'; color: var(--tab-background); }
130+
.filter-list-choice li.active:before { color: unset; }
131+
61132
.container { max-width: 1024px; margin: 0 auto; padding: 0 15px; }
62133
.container::after { content: ""; display: table; clear: both; }
63134

@@ -125,14 +196,6 @@ header .container { display: flex; justify-content: space-between; }
125196

126197
.trace-as-text .stacktrace { line-height: 1.8; margin: 0 0 15px; white-space: pre-wrap; }
127198

128-
table.logs tr td:last-child { width: 100%; }
129-
130-
.log-levels { width: 100%; margin: 0; padding: 0; display: flex; align-items: center; list-style: none; }
131-
.log-levels li { width: 100%; padding: 3px; margin: 0; cursor: pointer; text-align: center; border: 2px dashed #e0e0e0; border-radius: 5px; color: #888; }
132-
.log-levels li + li { margin-left: 10px; }
133-
.log-levels li.active { background: #eee; color: #666; border-style: solid; border-width: 1px; padding: 4px; border-color: #aaa; }
134-
.log-levels li.last-active { cursor: not-allowed; }
135-
136199
@media (min-width: 575px) {
137200
.hidden-xs-down { display: initial; }
138201
.help-link { margin-left: 30px; }

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/logger.html.twig

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -180,18 +180,21 @@
180180
</div>
181181

182182
</div>
183+
184+
<script>Sfjs.createFilters();</script>
183185
{% endif %}
184186
{% endblock %}
185187

186188
{% macro render_table(logs, category = '', show_level = false, is_deprecation = false) %}
187189
{% import _self as helper %}
188190
{% set channel_is_defined = (logs|first).channel is defined %}
191+
{% set filter = show_level or channel_is_defined %}
189192

190-
<table class="logs"{% if show_level %} data-log-levels="Emergency,Alert,Critical,Error,Warning,Notice,Info"{% endif %}>
193+
<table class="logs"{% if show_level %} data-filter-level="Emergency,Alert,Critical,Error,Warning,Notice,Info"{% endif %}{% if filter %} data-filters{% endif %}>
191194
<thead>
192195
<tr>
193-
<th>{{ show_level ? 'Level' : 'Time' }}</th>
194-
{% if channel_is_defined %}<th>Channel</th>{% endif %}
196+
{% if show_level %}<th data-filter="level">Level</th>{% else %}<th>Time</th>{% endif %}
197+
{% if channel_is_defined %}<th data-filter="channel">Channel</th>{% endif %}
195198
<th class="full-width">Message</th>
196199
</tr>
197200
</thead>
@@ -202,7 +205,7 @@
202205
: log.priorityName in ['CRITICAL', 'ERROR', 'ALERT', 'EMERGENCY'] ? 'status-error'
203206
: log.priorityName == 'WARNING' ? 'status-warning'
204207
%}
205-
<tr class="{{ css_class }}"{% if show_level %} data-log-level="{{ log.priorityName|lower }}"{% endif %}>
208+
<tr class="{{ css_class }}"{% if show_level %} data-filter-level="{{ log.priorityName|lower }}"{% endif %}{% if channel_is_defined %} data-filter-channel="{{ log.channel is not null ? log.channel : '' }}"{% endif %}>
206209
<td class="font-normal text-small" nowrap>
207210
{% if show_level %}
208211
<span class="colored text-bold">{{ log.priorityName }}</span>
@@ -212,7 +215,7 @@
212215

213216
{% if channel_is_defined %}
214217
<td class="font-normal text-small text-bold" nowrap>
215-
{{ log.channel }}
218+
{% if log.channel is null %}<em>n/a</em>{% else %}{{ log.channel }}{% endif %}
216219
{% if log.errorCount is defined and log.errorCount > 1 %}
217220
<span class="text-muted">({{ log.errorCount }} times)</span>
218221
{% endif %}
@@ -225,10 +228,6 @@
225228
{% endfor %}
226229
</tbody>
227230
</table>
228-
229-
{% if show_level %}
230-
<script>Sfjs.createLogLevels();</script>
231-
{% endif %}
232231
{% endmacro %}
233232

234233
{% macro render_log_message(category, log_index, log) %}

0 commit comments

Comments
 (0)