mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 09:07:54 +01:00
Integrate bare-bone filter hit stats in the logger
Related issue: - https://github.com/gorhill/uBlock/issues/983 - https://github.com/gorhill/uBlock/issues/1353 The current implementation reports statistics for all static filters, and the presentation/featureset is intentionally minimal: *Do not open issues about this.* It's still a work in progress and it will be worked on slowly and thoughtfully over time and as time allows. Pausing the logger will not pause the collation of filter hit statistics, thus it is possible to lower the logger overhead by pausing logger output without losing filter hit collation.
This commit is contained in:
parent
e4681d0250
commit
26708b37c1
5 changed files with 172 additions and 51 deletions
|
@ -44,6 +44,9 @@
|
|||
width: 1em;
|
||||
}
|
||||
|
||||
.fa-icon > .fa-icon_bar-chart {
|
||||
width: calc(1em * 2048 / 1792);
|
||||
}
|
||||
.fa-icon > .fa-icon_eraser,
|
||||
.fa-icon > .fa-icon_film {
|
||||
width: calc(1em * 1920 / 1792);
|
||||
|
|
|
@ -829,31 +829,25 @@ body.colorBlind #netFilteringDialog > div.panes > .dynamic .entry > .action > .
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#loggerSettingsDialog {
|
||||
#loggerStatsDialog .sortedEntries {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: smaller;
|
||||
}
|
||||
#loggerSettingsDialog > div {
|
||||
padding-bottom: 1em;
|
||||
#loggerStatsDialog .sortedEntries > div {
|
||||
display: flex;
|
||||
}
|
||||
#loggerSettingsDialog > div:last-of-type {
|
||||
padding-bottom: 0;
|
||||
#loggerStatsDialog .sortedEntries > div > span:first-of-type {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
padding: 0 2em 0 0;
|
||||
text-align: right;
|
||||
width: 3em;
|
||||
}
|
||||
#loggerSettingsDialog ul {
|
||||
padding: 0;
|
||||
}
|
||||
body[dir="ltr"] #loggerSettingsDialog ul {
|
||||
padding-left: 2em;
|
||||
}
|
||||
body[dir="rtl"] #loggerSettingsDialog ul {
|
||||
padding-right: 2em;
|
||||
}
|
||||
#loggerSettingsDialog li {
|
||||
list-style-type: none;
|
||||
margin: 0.5em 0 0 0;
|
||||
}
|
||||
#loggerSettingsDialog input {
|
||||
max-width: 6em;
|
||||
#loggerStatsDialog .sortedEntries > div > span:last-of-type {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
#loggerExportDialog {
|
||||
|
@ -890,6 +884,33 @@ body[dir="rtl"] #loggerSettingsDialog ul {
|
|||
white-space: pre;
|
||||
}
|
||||
|
||||
#loggerSettingsDialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#loggerSettingsDialog > div {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
#loggerSettingsDialog > div:last-of-type {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
#loggerSettingsDialog ul {
|
||||
padding: 0;
|
||||
}
|
||||
body[dir="ltr"] #loggerSettingsDialog ul {
|
||||
padding-left: 2em;
|
||||
}
|
||||
body[dir="rtl"] #loggerSettingsDialog ul {
|
||||
padding-right: 2em;
|
||||
}
|
||||
#loggerSettingsDialog li {
|
||||
list-style-type: none;
|
||||
margin: 0.5em 0 0 0;
|
||||
}
|
||||
#loggerSettingsDialog input {
|
||||
max-width: 6em;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ License - https://github.com/FortAwesome/Font-Awesome/tree/a8386aae19e200ddb0f68
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display: none;">
|
||||
<defs>
|
||||
<symbol id="angle-up" viewBox="0 0 998 582"><path d="m 998,499 q 0,13 -10,23 l -50,50 q -10,10 -23,10 -13,0 -23,-10 L 499,179 106,572 Q 96,582 83,582 70,582 60,572 L 10,522 Q 0,512 0,499 0,486 10,476 L 476,10 q 10,-10 23,-10 13,0 23,10 l 466,466 q 10,10 10,23 z"/></symbol>
|
||||
<symbol id="bar-chart" viewBox="0 0 2048 1536"><path d="m 640,768 0,512 -256,0 0,-512 256,0 z m 384,-512 0,1024 -256,0 0,-1024 256,0 z m 1024,1152 0,128 L 0,1536 0,0 l 128,0 0,1408 1920,0 z m -640,-896 0,768 -256,0 0,-768 256,0 z m 384,-384 0,1152 -256,0 0,-1152 256,0 z"/></symbol>
|
||||
<symbol id="bolt" viewBox="0 0 896 1664"><path d="m 885.08696,438 q 18,20 7,44 l -540,1157 q -13,25 -42,25 -4,0 -14,-2 -17,-5 -25.5,-19 -8.5,-14 -4.5,-30 l 197,-808 -406,101 q -4,1 -12,1 -18,0 -31,-11 Q -3.9130435,881 1.0869565,857 L 202.08696,32 q 4,-14 16,-23 12,-9 28,-9 l 328,0 q 19,0 32,12.5 13,12.5 13,29.5 0,8 -5,18 l -171,463 396,-98 q 8,-2 12,-2 19,0 34,15 z"/></symbol>
|
||||
<symbol id="clipboard" viewBox="0 0 1792 1792"><path d="m 768,1664 896,0 0,-640 -416,0 q -40,0 -68,-28 -28,-28 -28,-68 l 0,-416 -384,0 0,1152 z m 256,-1440 0,-64 q 0,-13 -9.5,-22.5 Q 1005,128 992,128 l -704,0 q -13,0 -22.5,9.5 Q 256,147 256,160 l 0,64 q 0,13 9.5,22.5 9.5,9.5 22.5,9.5 l 704,0 q 13,0 22.5,-9.5 9.5,-9.5 9.5,-22.5 z m 256,672 299,0 -299,-299 0,299 z m 512,128 0,672 q 0,40 -28,68 -28,28 -68,28 l -960,0 q -40,0 -68,-28 -28,-28 -28,-68 l 0,-160 -544,0 Q 56,1536 28,1508 0,1480 0,1440 L 0,96 Q 0,56 28,28 56,0 96,0 l 1088,0 q 40,0 68,28 28,28 28,68 l 0,328 q 21,13 36,28 l 408,408 q 28,28 48,76 20,48 20,88 z"/></symbol>
|
||||
<symbol id="code" viewBox="0 0 1830 1373"><path d="m 572,1125.5 -50,50 q -10,10 -23,10 -13,0 -23,-10 l -466,-466 q -10,-10 -10,-23 0,-13 10,-23 l 466,-466 q 10,-10 23,-10 13,0 23,10 l 50,50 q 10,10 10,23 0,13 -10,23 l -393,393 393,393 q 10,10 10,23 0,13 -10,23 z M 1163,58.476203 790,1349.4762 q -4,13 -15.5,19.5 -11.5,6.5 -23.5,2.5 l -62,-17 q -13,-4 -19.5,-15.5 -6.5,-11.5 -2.5,-24.5 L 1040,23.5 q 4,-13 15.5,-19.5 11.5,-6.5 23.5,-2.5 l 62,17 q 13,4 19.5,15.5 6.5,11.5 2.5,24.5 z m 657,651 -466,466 q -10,10 -23,10 -13,0 -23,-10 l -50,-50 q -10,-10 -10,-23 0,-13 10,-23 l 393,-393 -393,-393 q -10,-10 -10,-23 0,-13 10,-23 l 50,-50 q 10,-10 23,-10 13,0 23,10 l 466,466 q 10,10 10,23 0,13 -10,23 z"/></symbol>
|
||||
|
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
@ -263,6 +263,10 @@ const processLoggerEntries = function(response) {
|
|||
|
||||
for ( const entry of entries ) {
|
||||
const unboxed = JSON.parse(entry);
|
||||
if ( unboxed.filter instanceof Object ){
|
||||
loggerStats.processFilter(unboxed.filter);
|
||||
}
|
||||
if ( netInspectorPaused ) { continue; }
|
||||
const parsed = parseLogEntry(unboxed);
|
||||
if (
|
||||
parsed.tabId !== undefined &&
|
||||
|
@ -384,7 +388,7 @@ const parseLogEntry = function(details) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const viewPort = (function() {
|
||||
const viewPort = (( ) => {
|
||||
const vwRenderer = document.getElementById('vwRenderer');
|
||||
const vwScroller = document.getElementById('vwScroller');
|
||||
const vwVirtualContent = document.getElementById('vwVirtualContent');
|
||||
|
@ -802,14 +806,14 @@ const viewPort = (function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const updateCurrentTabTitle = (function() {
|
||||
const updateCurrentTabTitle = (( ) => {
|
||||
const i18nCurrentTab = vAPI.i18n('loggerCurrentTab');
|
||||
|
||||
return function() {
|
||||
const select = uDom.nodeFromId('pageSelector');
|
||||
if ( select.value !== '_' || activeTabId === 0 ) { return; }
|
||||
const opt0 = select.querySelector('[value="_"]');
|
||||
const opt1 = select.querySelector('[value="' + activeTabId + '"]');
|
||||
const opt1 = select.querySelector(`[value="${activeTabId}"]`);
|
||||
let text = i18nCurrentTab;
|
||||
if ( opt1 !== null ) {
|
||||
text += ' / ' + opt1.textContent;
|
||||
|
@ -934,9 +938,7 @@ const onLogBufferRead = function(response) {
|
|||
pageSelectorFromURLHash();
|
||||
}
|
||||
|
||||
if ( netInspectorPaused === false ) {
|
||||
processLoggerEntries(response);
|
||||
}
|
||||
processLoggerEntries(response);
|
||||
|
||||
// Synchronize DOM with sent logger data
|
||||
document.body.classList.toggle(
|
||||
|
@ -955,7 +957,7 @@ const onLogBufferRead = function(response) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const readLogBuffer = (function() {
|
||||
const readLogBuffer = (( ) => {
|
||||
let timer;
|
||||
|
||||
const readLogBufferNow = function() {
|
||||
|
@ -1011,7 +1013,7 @@ const pageSelectorChanged = function() {
|
|||
pageSelectorFromURLHash();
|
||||
};
|
||||
|
||||
const pageSelectorFromURLHash = (function() {
|
||||
const pageSelectorFromURLHash = (( ) => {
|
||||
let lastHash;
|
||||
let lastSelectedTabId;
|
||||
|
||||
|
@ -1806,7 +1808,7 @@ const reloadTab = function(ev) {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
const rowFilterer = (function() {
|
||||
const rowFilterer = (( ) => {
|
||||
const userFilters = [];
|
||||
const builtinFilters = [];
|
||||
|
||||
|
@ -2017,7 +2019,7 @@ const rowFilterer = (function() {
|
|||
// - Max number of entry per distinct tab
|
||||
// - Max entry age
|
||||
|
||||
const rowJanitor = (function() {
|
||||
const rowJanitor = (( ) => {
|
||||
const tabIdToDiscard = new Set();
|
||||
const tabIdToLoadCountMap = new Map();
|
||||
const tabIdToEntryCountMap = new Map();
|
||||
|
@ -2226,7 +2228,7 @@ const toggleVCompactView = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const popupManager = (function() {
|
||||
const popupManager = (( ) => {
|
||||
let realTabId = 0;
|
||||
let popup = null;
|
||||
let popupObserver = null;
|
||||
|
@ -2316,7 +2318,95 @@ const popupManager = (function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
// Filter hit stats' MVP ("minimum viable product")
|
||||
//
|
||||
const loggerStats = (( ) => {
|
||||
const filterHits = new Map();
|
||||
let dialog;
|
||||
let timer;
|
||||
|
||||
const makeRow = function() {
|
||||
const div = document.createElement('div');
|
||||
div.appendChild(document.createElement('span'));
|
||||
div.appendChild(document.createElement('span'));
|
||||
return div;
|
||||
};
|
||||
|
||||
const fillRow = function(div, entry) {
|
||||
div.children[0].textContent = entry[1].toLocaleString();
|
||||
div.children[1].textContent = entry[0];
|
||||
};
|
||||
|
||||
const updateList = function() {
|
||||
const sortedHits = Array.from(filterHits).sort((a, b) => {
|
||||
return b[1] - a[1];
|
||||
});
|
||||
|
||||
const doc = document;
|
||||
const parent = dialog.querySelector('.sortedEntries');
|
||||
let i = 0;
|
||||
|
||||
// Reuse existing rows
|
||||
for ( let iRow = 0; iRow < parent.childElementCount; iRow++ ) {
|
||||
if ( i === sortedHits.length ) { break; }
|
||||
fillRow(parent.children[iRow], sortedHits[i]);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Append new rows
|
||||
if ( i < sortedHits.length ) {
|
||||
const list = doc.createDocumentFragment();
|
||||
for ( ; i < sortedHits.length; i++ ) {
|
||||
const div = makeRow();
|
||||
fillRow(div, sortedHits[i]);
|
||||
list.appendChild(div);
|
||||
}
|
||||
parent.appendChild(list);
|
||||
}
|
||||
|
||||
// Remove extraneous rows
|
||||
// [Should never happen at this point in this current
|
||||
// bare-bone implementation]
|
||||
};
|
||||
|
||||
const toggleOn = function() {
|
||||
dialog = modalDialog.create(
|
||||
'#loggerStatsDialog',
|
||||
( ) => {
|
||||
dialog = undefined;
|
||||
if ( timer !== undefined ) {
|
||||
self.cancelIdleCallback(timer);
|
||||
timer = undefined;
|
||||
}
|
||||
}
|
||||
);
|
||||
updateList();
|
||||
modalDialog.show();
|
||||
};
|
||||
|
||||
uDom.nodeFromId('loggerStats').addEventListener('click', toggleOn);
|
||||
|
||||
return {
|
||||
processFilter: function(filter) {
|
||||
if ( filter.source !== 'static' && filter.source !== 'cosmetic' ) {
|
||||
return;
|
||||
}
|
||||
filterHits.set(filter.raw, (filterHits.get(filter.raw) || 0) + 1);
|
||||
if ( dialog === undefined || timer !== undefined ) { return; }
|
||||
timer = self.requestIdleCallback(
|
||||
( ) => {
|
||||
timer = undefined;
|
||||
updateList();
|
||||
},
|
||||
{ timeout: 2001 }
|
||||
);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(( ) => {
|
||||
const lines = [];
|
||||
const options = {
|
||||
format: 'list',
|
||||
|
@ -2505,7 +2595,7 @@ const popupManager = (function() {
|
|||
// - an option to discard immediately filtered out new entries
|
||||
// - max entry count _per load_
|
||||
//
|
||||
const loggerSettings = (function() {
|
||||
const loggerSettings = (( ) => {
|
||||
const settings = {
|
||||
discard: {
|
||||
maxAge: 240, // global
|
||||
|
@ -2611,7 +2701,7 @@ const loggerSettings = (function() {
|
|||
viewPort.updateLayout();
|
||||
};
|
||||
|
||||
uDom.nodeFromId('settings').addEventListener('click', toggleOn);
|
||||
uDom.nodeFromId('loggerSettings').addEventListener('click', toggleOn);
|
||||
|
||||
return settings;
|
||||
})();
|
||||
|
|
|
@ -70,8 +70,9 @@
|
|||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span id="loggerStats" class="button fa-icon">bar-chart</span>
|
||||
<span id="loggerExport" class="button fa-icon">clipboard</span>
|
||||
<span id="settings" class="button fa-icon">cog</span>
|
||||
<span id="loggerSettings" class="button fa-icon">cog</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vscrollable">
|
||||
|
@ -159,6 +160,27 @@
|
|||
<button id="createCosmeticFilters" class="custom important" type="button" data-i18n="pickerCreate"></button>
|
||||
</div>
|
||||
|
||||
<div id="loggerStatsDialog">
|
||||
<div class="sortedEntries"></div>
|
||||
</div>
|
||||
|
||||
<div id="loggerExportDialog">
|
||||
<div class="options">
|
||||
<div data-radio="format">
|
||||
<span data-i18n="loggerExportFormatList" data-radio-item="list"></span>
|
||||
<span data-i18n="loggerExportFormatTable" data-radio-item="table"></span>
|
||||
</div>
|
||||
<div data-radio="encoding">
|
||||
<span data-i18n="loggerExportEncodePlain" data-radio-item="plain"></span>
|
||||
<span data-i18n="loggerExportEncodeMarkdown" data-radio-item="markdown"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span data-i18n="genericCopyToClipboard" class="pushbutton"></span>
|
||||
</div>
|
||||
</div>
|
||||
<textarea class="output" readonly spellcheck="false"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="loggerSettingsDialog">
|
||||
<div><span data-i18n="loggerSettingDiscardPrompt"></span>
|
||||
<ul>
|
||||
|
@ -178,22 +200,6 @@
|
|||
<div><label data-i18n="loggerSettingPerEntryLineCount"><input type="number" min="2" max="6"></label></div>
|
||||
</div>
|
||||
|
||||
<div id="loggerExportDialog">
|
||||
<div class="options">
|
||||
<div data-radio="format">
|
||||
<span data-i18n="loggerExportFormatList" data-radio-item="list"></span>
|
||||
<span data-i18n="loggerExportFormatTable" data-radio-item="table"></span>
|
||||
</div>
|
||||
<div data-radio="encoding">
|
||||
<span data-i18n="loggerExportEncodePlain" data-radio-item="plain"></span>
|
||||
<span data-i18n="loggerExportEncodeMarkdown" data-radio-item="markdown"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span data-i18n="genericCopyToClipboard" class="pushbutton"></span>
|
||||
</div>
|
||||
</div>
|
||||
<textarea class="output" readonly spellcheck="false"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/fa-icons.js"></script>
|
||||
|
|
Loading…
Reference in a new issue