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
-------
e1bd82e89c
[WebProfilerBundle] Add channel log filter
This commit is contained in:
commit
01dfca1590
@ -1,9 +1,9 @@
|
|||||||
{% set channel_is_defined = (logs|first).channel is defined %}
|
{% set channel_is_defined = (logs|first).channel is defined %}
|
||||||
<table class="logs" data-log-levels="Emergency,Alert,Critical,Error,Warning,Notice,Info,Debug" data-default-log-level="Info">
|
<table class="logs" data-filter-level="Emergency,Alert,Critical,Error,Warning,Notice,Info,Debug" data-filters>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Level</th>
|
<th data-filter="level">Level</th>
|
||||||
{% if channel_is_defined %}<th>Channel</th>{% endif %}
|
{% if channel_is_defined %}<th data-filter="channel">Channel</th>{% endif %}
|
||||||
<th class="full-width">Message</th>
|
<th class="full-width">Message</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -18,7 +18,7 @@
|
|||||||
{% set severity = log.context.exception.severity|default(false) %}
|
{% set severity = log.context.exception.severity|default(false) %}
|
||||||
{% set status = severity is constant('E_DEPRECATED') or severity is constant('E_USER_DEPRECATED') ? 'warning' : 'normal' %}
|
{% set status = severity is constant('E_DEPRECATED') or severity is constant('E_USER_DEPRECATED') ? 'warning' : 'normal' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<tr class="status-{{ status }}" data-log-level="{{ log.priorityName|lower }}">
|
<tr class="status-{{ status }}" data-filter-level="{{ log.priorityName|lower }}"{% if channel_is_defined %} data-filter-channel="{{ log.channel }}"{% endif %}>
|
||||||
<td class="text-small" nowrap>
|
<td class="text-small" nowrap>
|
||||||
<span class="colored text-bold">{{ log.priorityName }}</span>
|
<span class="colored text-bold">{{ log.priorityName }}</span>
|
||||||
<span class="text-muted newline">{{ log.timestamp|date('H:i:s') }}</span>
|
<span class="text-muted newline">{{ log.timestamp|date('H:i:s') }}</span>
|
||||||
|
@ -173,50 +173,102 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
createLogLevels: function() {
|
createFilters: function() {
|
||||||
document.querySelectorAll('.logs[data-log-levels]').forEach(function (el) {
|
document.querySelectorAll('[data-filters] [data-filter]').forEach(function (filter) {
|
||||||
var bullets = document.createElement('ul'),
|
var filters = filter.closest('[data-filters]'),
|
||||||
levels = el.getAttribute('data-log-levels').toLowerCase().split(','),
|
type = 'choice',
|
||||||
defaultLevel = el.hasAttribute('data-default-log-level') ? levels.indexOf(el.getAttribute('data-default-log-level').toLowerCase()) : levels.length - 1;
|
name = filter.dataset.filter,
|
||||||
addClass(bullets, 'log-levels');
|
ucName = name.charAt(0).toUpperCase()+name.slice(1),
|
||||||
el.getAttribute('data-log-levels').split(',').forEach(function (level, i) {
|
list = document.createElement('ul'),
|
||||||
var bullet = document.createElement('li');
|
values = filters.dataset['filter'+ucName] || filters.querySelectorAll('[data-filter-'+name+']'),
|
||||||
bullet.innerText = level;
|
labels = {},
|
||||||
bullet.setAttribute('data-log-level', String(i));
|
defaults = null,
|
||||||
bullets.appendChild(bullet);
|
indexed = {},
|
||||||
addEventListener(bullet, 'click', function() {
|
processed = {};
|
||||||
if (i === this.parentNode.querySelectorAll('.active').length - 1) {
|
if (typeof values === 'string') {
|
||||||
return;
|
type = 'level';
|
||||||
}
|
labels = values.split(',');
|
||||||
this.parentNode.querySelectorAll('li').forEach(function (bullet, j) {
|
values = values.toLowerCase().split(',');
|
||||||
if (parseInt(bullet.getAttribute('data-log-level')) <= levels.indexOf(level.toLowerCase())) {
|
defaults = values.length - 1;
|
||||||
addClass(bullet, 'active');
|
}
|
||||||
if (i === j) {
|
addClass(list, 'filter-list');
|
||||||
addClass(bullet, 'last-active');
|
addClass(list, 'filter-list-'+type);
|
||||||
} else {
|
values.forEach(function (value, i) {
|
||||||
removeClass(bullet, 'last-active');
|
if (value instanceof HTMLElement) {
|
||||||
}
|
value = value.dataset['filter'+ucName];
|
||||||
} else {
|
}
|
||||||
removeClass(bullet, 'active');
|
if (value in processed) {
|
||||||
removeClass(bullet, 'last-active');
|
return;
|
||||||
}
|
}
|
||||||
});
|
var option = document.createElement('li'),
|
||||||
el.querySelectorAll('tr[data-log-level]').forEach(function (row) {
|
label = i in labels ? labels[i] : value,
|
||||||
row.style.display = i < levels.indexOf(row.getAttribute('data-log-level')) ? 'none' : '';
|
active = false,
|
||||||
});
|
matches;
|
||||||
});
|
if ('' === label) {
|
||||||
if (i <= defaultLevel) {
|
option.innerHTML = '<em>(none)</em>';
|
||||||
addClass(bullet, 'active');
|
|
||||||
if (i === defaultLevel) {
|
|
||||||
addClass(bullet, 'last-active');
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
el.querySelectorAll('tr[data-log-level="'+level.toLowerCase()+'"]').forEach(function (row) {
|
option.innerText = label;
|
||||||
row.style.display = 'none';
|
}
|
||||||
|
option.dataset.filter = value;
|
||||||
|
option.setAttribute('title', 1 === (matches = filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').length) ? 'Matches 1 row' : 'Matches '+matches+' rows');
|
||||||
|
indexed[value] = i;
|
||||||
|
list.appendChild(option);
|
||||||
|
addEventListener(option, 'click', function () {
|
||||||
|
if ('choice' === type) {
|
||||||
|
filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) {
|
||||||
|
if (option.dataset.filter === row.dataset['filter'+ucName]) {
|
||||||
|
toggleClass(row, 'filter-hidden-'+name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggleClass(option, 'active');
|
||||||
|
} else if ('level' === type) {
|
||||||
|
if (i === this.parentNode.querySelectorAll('.active').length - 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.parentNode.querySelectorAll('li').forEach(function (currentOption, j) {
|
||||||
|
if (j <= i) {
|
||||||
|
addClass(currentOption, 'active');
|
||||||
|
if (i === j) {
|
||||||
|
addClass(currentOption, 'last-active');
|
||||||
|
} else {
|
||||||
|
removeClass(currentOption, 'last-active');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeClass(currentOption, 'active');
|
||||||
|
removeClass(currentOption, 'last-active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) {
|
||||||
|
if (i < indexed[row.dataset['filter'+ucName]]) {
|
||||||
|
addClass(row, 'filter-hidden-'+name);
|
||||||
|
} else {
|
||||||
|
removeClass(row, 'filter-hidden-'+name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ('choice' === type) {
|
||||||
|
active = null === defaults || 0 <= defaults.indexOf(value);
|
||||||
|
} else if ('level' === type) {
|
||||||
|
active = i <= defaults;
|
||||||
|
if (active && i === defaults) {
|
||||||
|
addClass(option, 'last-active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (active) {
|
||||||
|
addClass(option, 'active');
|
||||||
|
} else {
|
||||||
|
filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').forEach(function (row) {
|
||||||
|
toggleClass(row, 'filter-hidden-'+name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
processed[value] = true;
|
||||||
});
|
});
|
||||||
el.parentNode.insertBefore(bullets, el);
|
|
||||||
|
if (1 < list.childNodes.length) {
|
||||||
|
filter.appendChild(list);
|
||||||
|
filter.dataset.filtered = '';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -225,7 +277,7 @@
|
|||||||
Sfjs.addEventListener(document, 'DOMContentLoaded', function() {
|
Sfjs.addEventListener(document, 'DOMContentLoaded', function() {
|
||||||
Sfjs.createTabs();
|
Sfjs.createTabs();
|
||||||
Sfjs.createToggles();
|
Sfjs.createToggles();
|
||||||
Sfjs.createLogLevels();
|
Sfjs.createFilters();
|
||||||
});
|
});
|
||||||
|
|
||||||
/*]]>*/</script>
|
/*]]>*/</script>
|
||||||
|
@ -1,3 +1,39 @@
|
|||||||
|
{# This file is based on WebProfilerBundle/Resources/views/Profiler/profiler.css.twig.
|
||||||
|
If you make any change in this file, verify the same change is needed in the other file. #}
|
||||||
|
:root {
|
||||||
|
--font-sans-serif: 'Helvetica, Arial, sans-serif';
|
||||||
|
--page-background: #f9f9f9;
|
||||||
|
--color-text: #222;
|
||||||
|
/* when updating any of these colors, do the same in toolbar.css.twig */
|
||||||
|
--color-success: #4f805d;
|
||||||
|
--color-warning: #a46a1f;
|
||||||
|
--color-error: #b0413e;
|
||||||
|
--color-muted: #999;
|
||||||
|
--tab-background: #fff;
|
||||||
|
--tab-color: #444;
|
||||||
|
--tab-active-background: #666;
|
||||||
|
--tab-active-color: #fafafa;
|
||||||
|
--tab-disabled-background: #f5f5f5;
|
||||||
|
--tab-disabled-color: #999;
|
||||||
|
--metric-value-background: #fff;
|
||||||
|
--metric-value-color: inherit;
|
||||||
|
--metric-unit-color: #999;
|
||||||
|
--metric-label-background: #e0e0e0;
|
||||||
|
--metric-label-color: inherit;
|
||||||
|
--table-border: #e0e0e0;
|
||||||
|
--table-background: #fff;
|
||||||
|
--table-header: #e0e0e0;
|
||||||
|
--shadow: 0px 0px 1px rgba(128, 128, 128, .2);
|
||||||
|
--border: 1px solid #e0e0e0;
|
||||||
|
--base-0: #fff;
|
||||||
|
--base-1: #f5f5f5;
|
||||||
|
--base-2: #e0e0e0;
|
||||||
|
--base-3: #ccc;
|
||||||
|
--base-4: #666;
|
||||||
|
--base-5: #444;
|
||||||
|
--base-6: #222;
|
||||||
|
}
|
||||||
|
|
||||||
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}
|
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}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@ -20,6 +56,7 @@ table th { background-color: #E0E0E0; font-weight: bold; text-align: left; }
|
|||||||
.m-t-5 { margin-top: 5px; }
|
.m-t-5 { margin-top: 5px; }
|
||||||
.hidden-xs-down { display: none; }
|
.hidden-xs-down { display: none; }
|
||||||
.block { display: block; }
|
.block { display: block; }
|
||||||
|
.full-width { width: 100%; }
|
||||||
.hidden { display: none; }
|
.hidden { display: none; }
|
||||||
.prewrap { white-space: pre-wrap; }
|
.prewrap { white-space: pre-wrap; }
|
||||||
.nowrap { white-space: nowrap; }
|
.nowrap { white-space: nowrap; }
|
||||||
@ -58,6 +95,40 @@ thead.sf-toggle-content.sf-toggle-visible, tbody.sf-toggle-content.sf-toggle-vis
|
|||||||
.tab-navigation li .badge.status-error { background: #B0413E; color: #FFF; }
|
.tab-navigation li .badge.status-error { background: #B0413E; color: #FFF; }
|
||||||
.tab-content > *:first-child { margin-top: 0; }
|
.tab-content > *:first-child { margin-top: 0; }
|
||||||
|
|
||||||
|
[data-filters] { position: relative; }
|
||||||
|
[data-filtered] { cursor: pointer; }
|
||||||
|
[data-filtered]:after { content: '\00a0\25BE'; }
|
||||||
|
[data-filtered]:hover .filter-list li { display: inline-flex; }
|
||||||
|
[class*="filter-hidden-"] { display: none; }
|
||||||
|
.filter-list { position: absolute; border: var(--border); box-shadow: var(--shadow); margin: 0; padding: 0; display: flex; flex-direction: column; }
|
||||||
|
.filter-list :after { content: ''; }
|
||||||
|
.filter-list li {
|
||||||
|
background: var(--tab-disabled-background);
|
||||||
|
border-bottom: var(--border);
|
||||||
|
color: var(--tab-disabled-color);
|
||||||
|
display: none;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px 10px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.filter-list li.active {
|
||||||
|
background: var(--tab-background);
|
||||||
|
color: var(--tab-color);
|
||||||
|
}
|
||||||
|
.filter-list li.last-active {
|
||||||
|
background: var(--tab-active-background);
|
||||||
|
color: var(--tab-active-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-list-level li { cursor: s-resize; }
|
||||||
|
.filter-list-level li.active { cursor: n-resize; }
|
||||||
|
.filter-list-level li.last-active { cursor: default; }
|
||||||
|
.filter-list-level li.last-active:before { content: '\2714\00a0'; }
|
||||||
|
.filter-list-choice li:before { content: '\2714\00a0'; color: var(--tab-background); }
|
||||||
|
.filter-list-choice li.active:before { color: unset; }
|
||||||
|
|
||||||
.container { max-width: 1024px; margin: 0 auto; padding: 0 15px; }
|
.container { max-width: 1024px; margin: 0 auto; padding: 0 15px; }
|
||||||
.container::after { content: ""; display: table; clear: both; }
|
.container::after { content: ""; display: table; clear: both; }
|
||||||
|
|
||||||
@ -125,14 +196,6 @@ header .container { display: flex; justify-content: space-between; }
|
|||||||
|
|
||||||
.trace-as-text .stacktrace { line-height: 1.8; margin: 0 0 15px; white-space: pre-wrap; }
|
.trace-as-text .stacktrace { line-height: 1.8; margin: 0 0 15px; white-space: pre-wrap; }
|
||||||
|
|
||||||
table.logs tr td:last-child { width: 100%; }
|
|
||||||
|
|
||||||
.log-levels { width: 100%; margin: 0; padding: 0; display: flex; align-items: center; list-style: none; }
|
|
||||||
.log-levels li { width: 100%; padding: 3px; margin: 0; cursor: pointer; text-align: center; border: 2px dashed #e0e0e0; border-radius: 5px; color: #888; }
|
|
||||||
.log-levels li + li { margin-left: 10px; }
|
|
||||||
.log-levels li.active { background: #eee; color: #666; border-style: solid; border-width: 1px; padding: 4px; border-color: #aaa; }
|
|
||||||
.log-levels li.last-active { cursor: not-allowed; }
|
|
||||||
|
|
||||||
@media (min-width: 575px) {
|
@media (min-width: 575px) {
|
||||||
.hidden-xs-down { display: initial; }
|
.hidden-xs-down { display: initial; }
|
||||||
.help-link { margin-left: 30px; }
|
.help-link { margin-left: 30px; }
|
||||||
|
@ -180,18 +180,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>Sfjs.createFilters();</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% macro render_table(logs, category = '', show_level = false, is_deprecation = false) %}
|
{% macro render_table(logs, category = '', show_level = false, is_deprecation = false) %}
|
||||||
{% import _self as helper %}
|
{% import _self as helper %}
|
||||||
{% set channel_is_defined = (logs|first).channel is defined %}
|
{% set channel_is_defined = (logs|first).channel is defined %}
|
||||||
|
{% set filter = show_level or channel_is_defined %}
|
||||||
|
|
||||||
<table class="logs"{% if show_level %} data-log-levels="Emergency,Alert,Critical,Error,Warning,Notice,Info"{% endif %}>
|
<table class="logs"{% if show_level %} data-filter-level="Emergency,Alert,Critical,Error,Warning,Notice,Info"{% endif %}{% if filter %} data-filters{% endif %}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ show_level ? 'Level' : 'Time' }}</th>
|
{% if show_level %}<th data-filter="level">Level</th>{% else %}<th>Time</th>{% endif %}
|
||||||
{% if channel_is_defined %}<th>Channel</th>{% endif %}
|
{% if channel_is_defined %}<th data-filter="channel">Channel</th>{% endif %}
|
||||||
<th class="full-width">Message</th>
|
<th class="full-width">Message</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -202,7 +205,7 @@
|
|||||||
: log.priorityName in ['CRITICAL', 'ERROR', 'ALERT', 'EMERGENCY'] ? 'status-error'
|
: log.priorityName in ['CRITICAL', 'ERROR', 'ALERT', 'EMERGENCY'] ? 'status-error'
|
||||||
: log.priorityName == 'WARNING' ? 'status-warning'
|
: log.priorityName == 'WARNING' ? 'status-warning'
|
||||||
%}
|
%}
|
||||||
<tr class="{{ css_class }}"{% if show_level %} data-log-level="{{ log.priorityName|lower }}"{% endif %}>
|
<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 %}>
|
||||||
<td class="font-normal text-small" nowrap>
|
<td class="font-normal text-small" nowrap>
|
||||||
{% if show_level %}
|
{% if show_level %}
|
||||||
<span class="colored text-bold">{{ log.priorityName }}</span>
|
<span class="colored text-bold">{{ log.priorityName }}</span>
|
||||||
@ -212,7 +215,7 @@
|
|||||||
|
|
||||||
{% if channel_is_defined %}
|
{% if channel_is_defined %}
|
||||||
<td class="font-normal text-small text-bold" nowrap>
|
<td class="font-normal text-small text-bold" nowrap>
|
||||||
{{ log.channel }}
|
{% if log.channel is null %}<em>n/a</em>{% else %}{{ log.channel }}{% endif %}
|
||||||
{% if log.errorCount is defined and log.errorCount > 1 %}
|
{% if log.errorCount is defined and log.errorCount > 1 %}
|
||||||
<span class="text-muted">({{ log.errorCount }} times)</span>
|
<span class="text-muted">({{ log.errorCount }} times)</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -225,10 +228,6 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% if show_level %}
|
|
||||||
<script>Sfjs.createLogLevels();</script>
|
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro render_log_message(category, log_index, log) %}
|
{% macro render_log_message(category, log_index, log) %}
|
||||||
|
@ -684,51 +684,102 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
createLogLevels: function() {
|
createFilters: function() {
|
||||||
document.querySelectorAll('.logs[data-log-levels]').forEach(function (el) {
|
document.querySelectorAll('[data-filters] [data-filter]').forEach(function (filter) {
|
||||||
var bullets = document.createElement('ul'),
|
var filters = filter.closest('[data-filters]'),
|
||||||
levels = el.getAttribute('data-log-levels').toLowerCase().split(','),
|
type = 'choice',
|
||||||
defaultLevel = el.hasAttribute('data-default-log-level') ? levels.indexOf(el.getAttribute('data-default-log-level').toLowerCase()) : levels.length - 1;
|
name = filter.dataset.filter,
|
||||||
addClass(bullets, 'log-levels');
|
ucName = name.charAt(0).toUpperCase()+name.slice(1),
|
||||||
el.getAttribute('data-log-levels').split(',').forEach(function (level, i) {
|
list = document.createElement('ul'),
|
||||||
var bullet = document.createElement('li');
|
values = filters.dataset['filter'+ucName] || filters.querySelectorAll('[data-filter-'+name+']'),
|
||||||
bullet.innerText = level;
|
labels = {},
|
||||||
bullet.setAttribute('data-log-level', String(i));
|
defaults = null,
|
||||||
bullet.setAttribute('title', 'Show logs of level ' + level + ' or higher');
|
indexed = {},
|
||||||
bullets.appendChild(bullet);
|
processed = {};
|
||||||
addEventListener(bullet, 'click', function() {
|
if (typeof values === 'string') {
|
||||||
if (i === this.parentNode.querySelectorAll('.active').length - 1) {
|
type = 'level';
|
||||||
return;
|
labels = values.split(',');
|
||||||
}
|
values = values.toLowerCase().split(',');
|
||||||
this.parentNode.querySelectorAll('li').forEach(function (bullet, j) {
|
defaults = values.length - 1;
|
||||||
if (parseInt(bullet.getAttribute('data-log-level')) <= levels.indexOf(level.toLowerCase())) {
|
}
|
||||||
addClass(bullet, 'active');
|
addClass(list, 'filter-list');
|
||||||
if (i === j) {
|
addClass(list, 'filter-list-'+type);
|
||||||
addClass(bullet, 'last-active');
|
values.forEach(function (value, i) {
|
||||||
} else {
|
if (value instanceof HTMLElement) {
|
||||||
removeClass(bullet, 'last-active');
|
value = value.dataset['filter'+ucName];
|
||||||
}
|
}
|
||||||
} else {
|
if (value in processed) {
|
||||||
removeClass(bullet, 'active');
|
return;
|
||||||
removeClass(bullet, 'last-active');
|
}
|
||||||
}
|
var option = document.createElement('li'),
|
||||||
});
|
label = i in labels ? labels[i] : value,
|
||||||
el.querySelectorAll('tr[data-log-level]').forEach(function (row) {
|
active = false,
|
||||||
row.style.display = i < levels.indexOf(row.getAttribute('data-log-level')) ? 'none' : '';
|
matches;
|
||||||
});
|
if ('' === label) {
|
||||||
});
|
option.innerHTML = '<em>(none)</em>';
|
||||||
if (i <= defaultLevel) {
|
|
||||||
addClass(bullet, 'active');
|
|
||||||
if (i === defaultLevel) {
|
|
||||||
addClass(bullet, 'last-active');
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
el.querySelectorAll('tr[data-log-level="'+level.toLowerCase()+'"]').forEach(function (row) {
|
option.innerText = label;
|
||||||
row.style.display = 'none';
|
}
|
||||||
|
option.dataset.filter = value;
|
||||||
|
option.setAttribute('title', 1 === (matches = filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').length) ? 'Matches 1 row' : 'Matches '+matches+' rows');
|
||||||
|
indexed[value] = i;
|
||||||
|
list.appendChild(option);
|
||||||
|
addEventListener(option, 'click', function () {
|
||||||
|
if ('choice' === type) {
|
||||||
|
filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) {
|
||||||
|
if (option.dataset.filter === row.dataset['filter'+ucName]) {
|
||||||
|
toggleClass(row, 'filter-hidden-'+name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggleClass(option, 'active');
|
||||||
|
} else if ('level' === type) {
|
||||||
|
if (i === this.parentNode.querySelectorAll('.active').length - 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.parentNode.querySelectorAll('li').forEach(function (currentOption, j) {
|
||||||
|
if (j <= i) {
|
||||||
|
addClass(currentOption, 'active');
|
||||||
|
if (i === j) {
|
||||||
|
addClass(currentOption, 'last-active');
|
||||||
|
} else {
|
||||||
|
removeClass(currentOption, 'last-active');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeClass(currentOption, 'active');
|
||||||
|
removeClass(currentOption, 'last-active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) {
|
||||||
|
if (i < indexed[row.dataset['filter'+ucName]]) {
|
||||||
|
addClass(row, 'filter-hidden-'+name);
|
||||||
|
} else {
|
||||||
|
removeClass(row, 'filter-hidden-'+name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ('choice' === type) {
|
||||||
|
active = null === defaults || 0 <= defaults.indexOf(value);
|
||||||
|
} else if ('level' === type) {
|
||||||
|
active = i <= defaults;
|
||||||
|
if (active && i === defaults) {
|
||||||
|
addClass(option, 'last-active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (active) {
|
||||||
|
addClass(option, 'active');
|
||||||
|
} else {
|
||||||
|
filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').forEach(function (row) {
|
||||||
|
toggleClass(row, 'filter-hidden-'+name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
processed[value] = true;
|
||||||
});
|
});
|
||||||
el.parentNode.insertBefore(bullets, el);
|
|
||||||
|
if (1 < list.childNodes.length) {
|
||||||
|
filter.appendChild(list);
|
||||||
|
filter.dataset.filtered = '';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
{# This file is partially duplicated in TwigBundle/Resources/views/exceotion.css.twig.
|
||||||
|
If you make any change in this file, verify the same change is needed in the other file. #}
|
||||||
{# Normalization
|
{# Normalization
|
||||||
(normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css)
|
(normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css)
|
||||||
========================================================================= #}
|
========================================================================= #}
|
||||||
@ -7,7 +9,7 @@
|
|||||||
--font-sans-serif: 'Helvetica, Arial, sans-serif';
|
--font-sans-serif: 'Helvetica, Arial, sans-serif';
|
||||||
--page-background: #f9f9f9;
|
--page-background: #f9f9f9;
|
||||||
--color-text: #222;
|
--color-text: #222;
|
||||||
--color-muted: #777;
|
--color-muted: #999;
|
||||||
/* when updating any of these colors, do the same in toolbar.css.twig */
|
/* when updating any of these colors, do the same in toolbar.css.twig */
|
||||||
--color-success: #4f805d;
|
--color-success: #4f805d;
|
||||||
--color-warning: #a46a1f;
|
--color-warning: #a46a1f;
|
||||||
@ -28,7 +30,6 @@
|
|||||||
--table-header: #e0e0e0;
|
--table-header: #e0e0e0;
|
||||||
--shadow: 0px 0px 1px rgba(128, 128, 128, .2);
|
--shadow: 0px 0px 1px rgba(128, 128, 128, .2);
|
||||||
--border: 1px solid #e0e0e0;
|
--border: 1px solid #e0e0e0;
|
||||||
--color-muted: #999;
|
|
||||||
--base-0: #fff;
|
--base-0: #fff;
|
||||||
--base-1: #f5f5f5;
|
--base-1: #f5f5f5;
|
||||||
--base-2: #e0e0e0;
|
--base-2: #e0e0e0;
|
||||||
@ -901,9 +902,6 @@ tr.status-warning td {
|
|||||||
background-color: var(--base-5);
|
background-color: var(--base-5);
|
||||||
color: var(--base-2);
|
color: var(--base-2);
|
||||||
}
|
}
|
||||||
.tab-content {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.tab-content > *:first-child {
|
.tab-content > *:first-child {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
@ -926,6 +924,42 @@ tr.status-warning td {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{# Filters
|
||||||
|
========================================================================= #}
|
||||||
|
[data-filters] { position: relative; }
|
||||||
|
[data-filtered] { cursor: pointer; }
|
||||||
|
[data-filtered]:after { content: '\00a0\25BE'; }
|
||||||
|
[data-filtered]:hover .filter-list li { display: inline-flex; }
|
||||||
|
[class*="filter-hidden-"] { display: none; }
|
||||||
|
.filter-list { position: absolute; border: var(--border); box-shadow: var(--shadow); margin: 0; padding: 0; display: flex; flex-direction: column; }
|
||||||
|
.filter-list :after { content: ''; }
|
||||||
|
.filter-list li {
|
||||||
|
background: var(--tab-disabled-background);
|
||||||
|
border-bottom: var(--border);
|
||||||
|
color: var(--tab-disabled-color);
|
||||||
|
display: none;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px 10px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.filter-list li.active {
|
||||||
|
background: var(--tab-background);
|
||||||
|
color: var(--tab-color);
|
||||||
|
}
|
||||||
|
.filter-list li.last-active {
|
||||||
|
background: var(--tab-active-background);
|
||||||
|
color: var(--tab-active-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-list-level li { cursor: s-resize; }
|
||||||
|
.filter-list-level li.active { cursor: n-resize; }
|
||||||
|
.filter-list-level li.last-active { cursor: default; }
|
||||||
|
.filter-list-level li.last-active:before { content: '\2714\00a0'; }
|
||||||
|
.filter-list-choice li:before { content: '\2714\00a0'; color: var(--tab-background); }
|
||||||
|
.filter-list-choice li.active:before { color: unset; }
|
||||||
|
|
||||||
{# Twig panel
|
{# Twig panel
|
||||||
========================================================================= #}
|
========================================================================= #}
|
||||||
#twig-dump pre {
|
#twig-dump pre {
|
||||||
@ -967,45 +1001,6 @@ table.logs .metadata {
|
|||||||
display: block;
|
display: block;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
table.logs tr td:last-child { width: 100%; }
|
|
||||||
|
|
||||||
.log-levels { position: absolute; right: 5px; top: 33px; }
|
|
||||||
.log-levels { border: var(--border); box-shadow: var(--shadow); margin: 0; padding: 0; display: flex; flex-direction: column; align-items: flex-end; }
|
|
||||||
.log-levels:before {
|
|
||||||
content: "Filter";
|
|
||||||
cursor: pointer;
|
|
||||||
/* "filter" icon provided by FontAwesome - CC BY 4.0 License
|
|
||||||
https://github.com/FortAwesome/Font-Awesome/blob/master/LICENSE.txt */
|
|
||||||
background: var(--table-background) no-repeat url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="%23999" d="M487.976 0H24.028C2.71 0-8.047 25.866 7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02 518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0 487.976 0z" class=""></path></svg>');
|
|
||||||
background-position: 6px 6px;
|
|
||||||
background-size: 14px 14px;
|
|
||||||
padding: 4px 10px 4px 24px;
|
|
||||||
position: absolute;
|
|
||||||
top: -28px;
|
|
||||||
}
|
|
||||||
.log-levels:hover li { display: inline-flex; }
|
|
||||||
.log-levels li {
|
|
||||||
background: var(--tab-disabled-background);
|
|
||||||
border-bottom: var(--border);
|
|
||||||
color: var(--tab-disabled-color);
|
|
||||||
cursor: s-resize;
|
|
||||||
display: none;
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 5px 10px;
|
|
||||||
text-align: left;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.log-levels li.active {
|
|
||||||
background: var(--tab-background);
|
|
||||||
color: var(--tab-color);
|
|
||||||
cursor: n-resize;
|
|
||||||
}
|
|
||||||
.log-levels li.last-active {
|
|
||||||
background: var(--tab-active-background);
|
|
||||||
color: var(--tab-active-color);
|
|
||||||
cursor: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
{# Doctrine panel
|
{# Doctrine panel
|
||||||
========================================================================= #}
|
========================================================================= #}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": "^7.1.3",
|
"php": "^7.1.3",
|
||||||
"symfony/config": "^4.2",
|
"symfony/config": "^4.2",
|
||||||
"symfony/http-kernel": "~4.1",
|
"symfony/http-kernel": "~4.2",
|
||||||
"symfony/routing": "~3.4|~4.0",
|
"symfony/routing": "~3.4|~4.0",
|
||||||
"symfony/twig-bundle": "~4.2",
|
"symfony/twig-bundle": "~4.2",
|
||||||
"symfony/var-dumper": "~3.4|~4.0",
|
"symfony/var-dumper": "~3.4|~4.0",
|
||||||
|
@ -134,7 +134,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
|
|||||||
$log['timestamp'] = $bootTime;
|
$log['timestamp'] = $bootTime;
|
||||||
$log['priority'] = 100;
|
$log['priority'] = 100;
|
||||||
$log['priorityName'] = 'DEBUG';
|
$log['priorityName'] = 'DEBUG';
|
||||||
$log['channel'] = '-';
|
$log['channel'] = null;
|
||||||
$log['scream'] = false;
|
$log['scream'] = false;
|
||||||
unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']);
|
unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']);
|
||||||
$logs[] = $log;
|
$logs[] = $log;
|
||||||
|
Reference in New Issue
Block a user