Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion InfoLogger/lib/ProfileService.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class ProfileService {
errsource: { match: '', exclude: '' },
message: { match: '', exclude: '' },
severity: { in: 'I W E F' },
level: { max: null },
level: { max: 1 },
};
}

Expand Down
32 changes: 32 additions & 0 deletions InfoLogger/public/constants/log-level-filters.const.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* @license
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
* All rights not expressly granted are reserved.
*
* This software is distributed under the terms of the GNU General Public
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

/**
* Maps each log level to the set of severity codes that are NOT available at that level.
* @type {Map<number|null, string[]>}
*/
const DISABLED_SEVERITIES_BY_LEVEL = new Map([
[1, ['D']],
[6, []],
[11, []],
[null, []],
]);

/**
* Return the severity codes that are disabled for a given log level.
* @param {number|null} level - the current log level (1=Ops, 6=Support, 11=Developer, null=Trace)
* If provided a level not in the map, we enable all severities as this will be a custom event
* @returns {string[]} severity codes that should be disabled at the given log level
*/
export const getDisabledSeverities = (level) => DISABLED_SEVERITIES_BY_LEVEL.get(level) ?? [];
28 changes: 17 additions & 11 deletions InfoLogger/public/log/Log.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default class Log extends Observable {

this.filter = new LogFilter(model);
this.filter.bubbleTo(this);
this.filter.observe(this.onFilterChange.bind(this));

this.focus = { // show date picker on focus
timestampSince: false,
Expand Down Expand Up @@ -400,17 +401,22 @@ export default class Log extends Observable {
}
value = copy.join(' ');
}
if (this.filter.setCriteria(field, operator, value)) {
if (this.isLiveModeRunning()) {
this.model.ws.setFilter(this.model.log.filter.toStringifyFunction());
this.model.notification.show(
'The current live session has been adapted to the new filter configuration.',
'primary',
2000,
);
} else if (this.isActiveModeQuery()) {
this.model.notification.show('Filters have changed. Query again for updated results', 'primary', 2000);
}
this.filter.setCriteria(field, operator, value);
}

/**
* Notify the active mode (live or query) that filters have changed.
*/
onFilterChange() {
if (this.isLiveModeRunning()) {
this.model.ws.setFilter(this.filter.toStringifyFunction());
this.model.notification.show(
'The current live session has been adapted to the new filter configuration.',
'primary',
2000,
);
} else if (this.isActiveModeQuery()) {
this.model.notification.show('Filters have changed. Query again for updated results', 'primary', 2000);
}
}

Expand Down
6 changes: 3 additions & 3 deletions InfoLogger/public/log/cellContextMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ export const cellContextMenu = (model) => {
hideMenu();
},
),
createMenuItem(iconTrash(), 'danger', 'Clear Level Filter', () => {
model.log.setCriteria('level', 'max', null);
createMenuItem(iconTrash(), 'danger', 'Reset Level Filter', () => {
model.log.setCriteria('level', 'max', 1);
hideMenu();
}, model.log.filter.criterias.level.max === null),
}, model.log.filter.criterias.level.max === 1),
];
}
return [
Expand Down
43 changes: 40 additions & 3 deletions InfoLogger/public/logFilter/LogFilter.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import { Observable } from '/js/src/index.js';
import { TEXT_FILTER_OPERATORS } from '../constants/text-filter-operators.const.js';
import { getDisabledSeverities } from '../constants/log-level-filters.const.js';

/**
* @typedef Criteria
Expand All @@ -23,7 +24,7 @@
*/

/**
* @typedef Criteria * @type {Array.<Criteria>}

Check warning on line 27 in InfoLogger/public/logFilter/LogFilter.js

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest

Unexpected inline JSDoc tag. Did you mean to use {@type}, \@type, or `@type`?

Check warning on line 27 in InfoLogger/public/logFilter/LogFilter.js

View workflow job for this annotation

GitHub Actions / Tests & coverage on ubuntu-latest

Unexpected inline JSDoc tag. Did you mean to use {@type}, \@type, or `@type`?
*/

/**
Expand Down Expand Up @@ -88,6 +89,11 @@
throw new Error('unknown operator');
}

// enforces on both severity and level as fromObject can set them in either order
if (field === 'severity' || field === 'level') {
this.enforceDisabledSeverities();
}

this.notify();
return true;
} else {
Expand Down Expand Up @@ -153,10 +159,41 @@
TEXT_FILTER_OPERATORS.some((operator) => criteria[operator]?.trim()));
}

/**
* Check whether a severity is disabled for the current log level.
* @param {string} severityCode - [D, I, W, E, F]
* @returns {boolean} true if the severity is not allowed at the current level
*/
isSeverityDisabled(severityCode) {
return getDisabledSeverities(this.criterias.level.max).includes(severityCode);
}

/**
* Remove any active severity selections that are disallowed by the current level.
*/
enforceDisabledSeverities() {
const disabled = getDisabledSeverities(this.criterias.level.max);
if (disabled.length === 0 || !this.criterias.severity.$in) {
return;
}

const current = this.criterias.severity.$in;
if (!current) {
return;
}

const filteredSeverities = current.filter((s) => !disabled.includes(s));
// Only update if there is a change
if (filteredSeverities.length !== current.length) {
this.criterias.severity.$in = filteredSeverities;
this.criterias.severity.in = filteredSeverities.join(' ');
}
}

/**
* Generates a function to filter a log passed as argument to it
* Output of function is boolean.
* @returns {Function.<WebSocketMessage, boolean>} - function to filter logs

Check warning on line 196 in InfoLogger/public/logFilter/LogFilter.js

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest

Prefer a more specific type to `Function`

Check warning on line 196 in InfoLogger/public/logFilter/LogFilter.js

View workflow job for this annotation

GitHub Actions / Tests & coverage on ubuntu-latest

Prefer a more specific type to `Function`
*/
toStringifyFunction() {
/**
Expand Down Expand Up @@ -389,11 +426,11 @@
},
severity: {
in: 'I W E F',
$in: ['W', 'I', 'E', 'F'],
$in: ['I', 'W', 'E', 'F'],
},
level: {
max: null, // 0, 1, 6, 11, 21
$max: null, // 0, 1, 6, 11, 21
max: 1,
$max: 1,
},
};
this.notify();
Expand Down
20 changes: 12 additions & 8 deletions InfoLogger/public/logFilter/commandFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,18 @@ export default (model) => [
* @param {string} value - a char to represent severity: W E F or I, can be many with spaces like 'W E'
* @returns {vnode} - the button to toggle severity
*/
const buttonSeverity = (model, label, title, value) => h('button.btn', {
className: model.log.filter.criterias.severity.in.includes(value) ? 'active' : '',
onclick: (e) => {
model.log.setCriteria('severity', 'in', value);
e.target.blur(); // remove focus so user can 'enter' without actually toggle again the button
},
title: title,
}, label);
const buttonSeverity = (model, label, title, value) => {
const disabled = model.log.filter.isSeverityDisabled(value);
return h('button.btn', {
className: disabled ? 'disabled' : model.log.filter.criterias.severity.in.includes(value) ? 'active' : '',
onclick: disabled ? null : (e) => {
model.log.setCriteria('severity', 'in', value);
e.target.blur();
},
disabled,
title: disabled ? `${label} is not available at the current log level` : title,
}, label);
};

/**
* Makes a button to set filtering level (shifter, debug, etc) with number
Expand Down
4 changes: 2 additions & 2 deletions InfoLogger/test/lib/mocha-profile-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const DEFAULT_PROFILE = {
errsource: { match: '', exclude: '' },
message: { match: '', exclude: '' },
severity: { in: 'I W E F' },
level: { max: null },
level: { max: 1 },
},
},
};
Expand Down Expand Up @@ -135,7 +135,7 @@ const FULL_PROFILE = {
errsource: { match: '', exclude: '' },
message: { match: '', exclude: '' },
severity: { in: 'I W E F' },
level: { max: null },
level: { max: 1 },
},
},
};
4 changes: 2 additions & 2 deletions InfoLogger/test/mocha-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ describe('InfoLogger', function() {
}
});

it('should have redirected to default page "/?q={"severity":{"in":"I W E F"}}"', async function() {
it('should have redirected to default page "/?q={"severity":{"in":"I W E F"},"level":{"max":1}}"', async function() {
await page.goto(baseUrl, {waitUntil: 'networkidle0'});
const location = await page.evaluate(() => window.location);
const search = decodeURIComponent(location.search);

assert.deepStrictEqual(search, '?q={"severity":{"in":"I W E F"}}');
assert.deepStrictEqual(search, '?q={"severity":{"in":"I W E F"},"level":{"max":1}}');
});

require('./public/user-actions-mocha');
Expand Down
9 changes: 7 additions & 2 deletions InfoLogger/test/public/live-mode-mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Live Mode test-suite', async () => {
const location = await page.evaluate(() => window.location);
const search = decodeURIComponent(location.search);

assert.deepStrictEqual(search, '?q={"severity":{"in":"I W E F"}}');
assert.deepStrictEqual(search, '?q={"severity":{"in":"I W E F"},"level":{"max":1}}');
});

it('should successfully enable LIVE mode', async () => {
Expand Down Expand Up @@ -60,6 +60,7 @@ describe('Live Mode test-suite', async () => {
await page.evaluate(() => window.model.log.liveStop('Paused'));
await page.evaluate(() => {
window.model.log.filter.resetCriteria();
window.model.log.filter.setCriteria('level', 'max', null);
window.model.log.filter.setCriteria('hostname', 'match', 'aldaqecs01-v1');
});
await page.evaluate(() => window.model.log.liveStart());
Expand All @@ -76,6 +77,7 @@ describe('Live Mode test-suite', async () => {
await page.evaluate(() => window.model.log.liveStop('Query'));
await page.evaluate(() => {
window.model.log.filter.resetCriteria();
window.model.log.filter.setCriteria('level', 'max', null);
window.model.log.filter.setCriteria('hostname', 'exclude', 'aldaqdip01');
});
await page.evaluate(() => window.model.log.liveStart());
Expand All @@ -90,7 +92,10 @@ describe('Live Mode test-suite', async () => {

it('should filter messages based on SQL Wildcards `hostname` excluding `%ldaqdip%` and username matching `a_iceda_`'
+ ' without changing state of live mode', async () => {
await page.evaluate(() => window.model.log.filter.resetCriteria());
await page.evaluate(() => {
window.model.log.filter.resetCriteria();
window.model.log.filter.setCriteria('level', 'max', null);
});
await page.evaluate(() => {
window.model.log.setCriteria('hostname', 'exclude', '%ldaqdip%');
window.model.log.setCriteria('username', 'match', 'a_iceda_');
Expand Down
24 changes: 14 additions & 10 deletions InfoLogger/test/public/log-context-menu-mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ describe('Cell Context Menu', async () => {
it('should show correct actions for level field', async () => {
await openContextMenu(page, 'level', '3', 100, 120);
const labels = await getMenuActionLabels(page);
assert.deepStrictEqual(labels, ['Set Level To Support', 'Set Level To Ops', 'Clear Level Filter', 'Copy', 'Open Inspector']);
assert.deepStrictEqual(labels, ['Set Level To Support', 'Set Level To Ops', 'Reset Level Filter', 'Copy', 'Open Inspector']);
});
});

Expand Down Expand Up @@ -561,7 +561,7 @@ describe('Cell Context Menu', async () => {
});
});

describe('Set/Clear level filter for level field', async () => {
describe('Set/Reset Level Filter for level field', async () => {
it('should set level to nearest threshold above via include', async () => {
await openContextMenu(page, 'level', '3', 100, 120);

Expand All @@ -586,34 +586,38 @@ describe('Cell Context Menu', async () => {
assert.strictEqual(level.$max, 1);
});

it('should disable "Clear Level Filter" when no level filter is set', async () => {
it('should disable "Reset Level Filter" when level is already cleared', async () => {
await page.evaluate(() => {
window.model.log.filter.setCriteria('level', 'max', 1);
});

await openContextMenu(page, 'level', '3', 100, 120);

assert.strictEqual(await isMenuItemDisabled(page, 'Clear Level Filter'), true);
assert.strictEqual(await isMenuItemDisabled(page, 'Reset Level Filter'), true);
});

it('should enable "Clear Level Filter" when a level filter is active', async () => {
it('should enable "Reset Level Filter" when a level filter is active', async () => {
await page.evaluate(() => {
window.model.log.filter.setCriteria('level', 'max', 6);
});

await openContextMenu(page, 'level', '3', 100, 120);

assert.strictEqual(await isMenuItemDisabled(page, 'Clear Level Filter'), false);
assert.strictEqual(await isMenuItemDisabled(page, 'Reset Level Filter'), false);
});

it('should clear level filter back to null', async () => {
it('should reset level filter back to default', async () => {
await page.evaluate(() => {
window.model.log.filter.setCriteria('level', 'max', 6);
});

await openContextMenu(page, 'level', '3', 100, 120);

await clickMenuItemByLabel(page, 'Clear Level Filter');
await clickMenuItemByLabel(page, 'Reset Level Filter');

const level = await page.evaluate(() => window.model.log.filter.criterias.level);
assert.strictEqual(level.max, null);
assert.strictEqual(level.$max, null);
assert.strictEqual(level.max, 1);
assert.strictEqual(level.$max, 1);
});
});

Expand Down
Loading
Loading