feature #24263 Filter logs by level (ro0NL)
This PR was submitted for the 3.4 branch but it was merged into the 4.2-dev branch instead (closes #24263).
Discussion
----------
Filter logs by level
| Q | A
| ------------- | ---
| Branch? | 3.4
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #... <!-- #-prefixed issue number(s), if any -->
| License | MIT
| Doc PR | symfony/symfony-docs#... <!--highly recommended for new features-->
Proposal to filter logs by level. This PR competes with #23247 (but also see #23038) which propose to filter by channel.
<details>
<summary>Before</summary>
![image](https://user-images.githubusercontent.com/1047696/30607022-00536bbe-9d74-11e7-84dd-6427d328f50b.png)
</details>
<details>
<summary>After</summary>
![image](https://user-images.githubusercontent.com/1047696/31036405-6346da12-a56c-11e7-8747-b1ae89c549f2.png)
</details>
From https://github.com/symfony/symfony/pull/23247#issuecomment-322827776
> Adding configuration is always adding complexity for the end user. If we can do otherwise (including doing nothing), i think that might be better. I all depends on the current "brokenness" status.
This avoids that. Also single click; noise gone.
Commits
-------
8f88753381
Filter logs by level
This commit is contained in:
commit
6de1577fc4
@ -1,6 +1,5 @@
|
||||
{% set channel_is_defined = (logs|first).channel is defined %}
|
||||
|
||||
<table class="logs">
|
||||
<table class="logs" data-log-levels="Emergency,Alert,Critical,Error,Warning,Notice,Info,Debug" data-default-log-level="Info">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Level</th>
|
||||
@ -19,7 +18,7 @@
|
||||
{% set severity = log.context.exception.severity|default(false) %}
|
||||
{% set status = severity is constant('E_DEPRECATED') or severity is constant('E_USER_DEPRECATED') ? 'warning' : 'normal' %}
|
||||
{% endif %}
|
||||
<tr class="status-{{ status }}">
|
||||
<tr class="status-{{ status }}" data-log-level="{{ log.priorityName|lower }}">
|
||||
<td class="text-small" nowrap>
|
||||
<span class="colored text-bold">{{ log.priorityName }}</span>
|
||||
<span class="text-muted newline">{{ log.timestamp|date('H:i:s') }}</span>
|
||||
|
@ -171,6 +171,53 @@
|
||||
|
||||
toggles[i].setAttribute('data-processed', 'true');
|
||||
}
|
||||
},
|
||||
|
||||
createLogLevels: function() {
|
||||
document.querySelectorAll('.logs[data-log-levels]').forEach(function (el) {
|
||||
var bullets = document.createElement('ul'),
|
||||
levels = el.getAttribute('data-log-levels').toLowerCase().split(','),
|
||||
defaultLevel = el.hasAttribute('data-default-log-level') ? levels.indexOf(el.getAttribute('data-default-log-level').toLowerCase()) : levels.length - 1;
|
||||
addClass(bullets, 'log-levels');
|
||||
el.getAttribute('data-log-levels').split(',').forEach(function (level, i) {
|
||||
var bullet = document.createElement('li');
|
||||
bullet.innerText = level;
|
||||
bullet.setAttribute('data-log-level', String(i));
|
||||
bullets.appendChild(bullet);
|
||||
addEventListener(bullet, 'click', function() {
|
||||
if (i === this.parentNode.querySelectorAll('.active').length - 1) {
|
||||
return;
|
||||
}
|
||||
this.parentNode.querySelectorAll('li').forEach(function (bullet, j) {
|
||||
if (parseInt(bullet.getAttribute('data-log-level')) <= levels.indexOf(level.toLowerCase())) {
|
||||
addClass(bullet, 'active');
|
||||
if (i === j) {
|
||||
addClass(bullet, 'last-active');
|
||||
} else {
|
||||
removeClass(bullet, 'last-active');
|
||||
}
|
||||
} else {
|
||||
removeClass(bullet, 'active');
|
||||
removeClass(bullet, 'last-active');
|
||||
}
|
||||
});
|
||||
el.querySelectorAll('tr[data-log-level]').forEach(function (row) {
|
||||
row.style.display = i < levels.indexOf(row.getAttribute('data-log-level')) ? 'none' : '';
|
||||
});
|
||||
});
|
||||
if (i <= defaultLevel) {
|
||||
addClass(bullet, 'active');
|
||||
if (i === defaultLevel) {
|
||||
addClass(bullet, 'last-active');
|
||||
}
|
||||
} else {
|
||||
el.querySelectorAll('tr[data-log-level="'+level.toLowerCase()+'"]').forEach(function (row) {
|
||||
row.style.display = 'none';
|
||||
});
|
||||
}
|
||||
});
|
||||
el.parentNode.insertBefore(bullets, el);
|
||||
});
|
||||
}
|
||||
};
|
||||
})();
|
||||
@ -178,6 +225,7 @@
|
||||
Sfjs.addEventListener(document, 'DOMContentLoaded', function() {
|
||||
Sfjs.createTabs();
|
||||
Sfjs.createToggles();
|
||||
Sfjs.createLogLevels();
|
||||
});
|
||||
|
||||
/*]]>*/</script>
|
||||
|
@ -125,6 +125,14 @@ header .container { display: flex; justify-content: space-between; }
|
||||
|
||||
.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) {
|
||||
.hidden-xs-down { display: initial; }
|
||||
.help-link { margin-left: 30px; }
|
||||
|
@ -187,7 +187,7 @@
|
||||
{% import _self as helper %}
|
||||
{% set channel_is_defined = (logs|first).channel is defined %}
|
||||
|
||||
<table class="logs">
|
||||
<table class="logs"{% if show_level %} data-log-levels="Emergency,Alert,Critical,Error,Warning,Notice,Info"{% endif %}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ show_level ? 'Level' : 'Time' }}</th>
|
||||
@ -202,7 +202,7 @@
|
||||
: log.priorityName in ['CRITICAL', 'ERROR', 'ALERT', 'EMERGENCY'] ? 'status-error'
|
||||
: log.priorityName == 'WARNING' ? 'status-warning'
|
||||
%}
|
||||
<tr class="{{ css_class }}">
|
||||
<tr class="{{ css_class }}"{% if show_level %} data-log-level="{{ log.priorityName|lower }}"{% endif %}>
|
||||
<td class="font-normal text-small" nowrap>
|
||||
{% if show_level %}
|
||||
<span class="colored text-bold">{{ log.priorityName }}</span>
|
||||
@ -225,6 +225,10 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% if show_level %}
|
||||
<script>Sfjs.createLogLevels();</script>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_log_message(category, log_index, log) %}
|
||||
|
@ -682,6 +682,53 @@
|
||||
|
||||
toggles[i].setAttribute('data-processed', 'true');
|
||||
}
|
||||
},
|
||||
|
||||
createLogLevels: function() {
|
||||
document.querySelectorAll('.logs[data-log-levels]').forEach(function (el) {
|
||||
var bullets = document.createElement('ul'),
|
||||
levels = el.getAttribute('data-log-levels').toLowerCase().split(','),
|
||||
defaultLevel = el.hasAttribute('data-default-log-level') ? levels.indexOf(el.getAttribute('data-default-log-level').toLowerCase()) : levels.length - 1;
|
||||
addClass(bullets, 'log-levels');
|
||||
el.getAttribute('data-log-levels').split(',').forEach(function (level, i) {
|
||||
var bullet = document.createElement('li');
|
||||
bullet.innerText = level;
|
||||
bullet.setAttribute('data-log-level', String(i));
|
||||
bullets.appendChild(bullet);
|
||||
addEventListener(bullet, 'click', function() {
|
||||
if (i === this.parentNode.querySelectorAll('.active').length - 1) {
|
||||
return;
|
||||
}
|
||||
this.parentNode.querySelectorAll('li').forEach(function (bullet, j) {
|
||||
if (parseInt(bullet.getAttribute('data-log-level')) <= levels.indexOf(level.toLowerCase())) {
|
||||
addClass(bullet, 'active');
|
||||
if (i === j) {
|
||||
addClass(bullet, 'last-active');
|
||||
} else {
|
||||
removeClass(bullet, 'last-active');
|
||||
}
|
||||
} else {
|
||||
removeClass(bullet, 'active');
|
||||
removeClass(bullet, 'last-active');
|
||||
}
|
||||
});
|
||||
el.querySelectorAll('tr[data-log-level]').forEach(function (row) {
|
||||
row.style.display = i < levels.indexOf(row.getAttribute('data-log-level')) ? 'none' : '';
|
||||
});
|
||||
});
|
||||
if (i <= defaultLevel) {
|
||||
addClass(bullet, 'active');
|
||||
if (i === defaultLevel) {
|
||||
addClass(bullet, 'last-active');
|
||||
}
|
||||
} else {
|
||||
el.querySelectorAll('tr[data-log-level="'+level.toLowerCase()+'"]').forEach(function (row) {
|
||||
row.style.display = 'none';
|
||||
});
|
||||
}
|
||||
});
|
||||
el.parentNode.insertBefore(bullets, el);
|
||||
});
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -955,6 +955,13 @@ table.logs .metadata {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
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; }
|
||||
|
||||
{# Doctrine panel
|
||||
========================================================================= #}
|
||||
|
Reference in New Issue
Block a user