Skip to content

Commit

Permalink
Merge pull request #5836 from perlpunk/logfilter
Browse files Browse the repository at this point in the history
Add interactive log viewer
  • Loading branch information
mergify[bot] authored Aug 15, 2024
2 parents b24c267 + 5313e25 commit ab9f78b
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 3 deletions.
3 changes: 3 additions & 0 deletions assets/javascripts/anser-import.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ const module = {};
function ansiToHtml(data) {
return Anser.linkify(Anser.ansiToHtml(Anser.escapeForHtml(data), {use_classes: true}));
}
function ansiToText(data) {
return Anser.ansiToText(data);
}
101 changes: 99 additions & 2 deletions assets/javascripts/test_result.js
Original file line number Diff line number Diff line change
Expand Up @@ -578,14 +578,97 @@ function setupResult(jobid, state, result, status_url) {
setInfoPanelClassName(state, result);
}

function loadEmbeddedLogFiles() {
function delay(callback, ms) {
let timer;
return function () {
clearTimeout(timer);
timer = setTimeout(callback.bind(this, ...arguments), ms || 0);
};
}

function filterLogLines(input) {
if (input === undefined) {
return;
}
const string = input.value;
let regex = undefined;
const match = string.match(/^\/(.*)\/([i]*)$/);
if (match) {
regex = new RegExp(match[1], match[2]);
}
displaySearchInfo('Searching…');
$('.embedded-logfile').each(function (index, logFileElement) {
let content = logFileElement.dataset.content;
if (content === undefined) {
return;
}
if (string.length > 0) {
const lines = content.split(/\r?\n/);
const wanted = [];
for (const line of lines) {
if (regex) {
// For searching for /^something/ we need to remove ansi control characters
const text = ansiToText(line);
if (text.match(regex)) {
wanted.push(line);
}
continue;
}
if (line.includes(string)) {
wanted.push(line);
}
}
content = wanted.join('\n');
displaySearchInfo(`Showing ${wanted.length} / ${lines.length} lines`);
} else {
displaySearchInfo('');
}
logFileElement.innerHTML = ansiToHtml(content);
});
const fullCurrentUrl = window.location.href;
const urlParts = fullCurrentUrl.split('#');
const currentUrl = urlParts[0];
const fragment = urlParts[1];
if (string.length > 0) {
window.location.href = `${currentUrl}#filter=${encodeURIComponent(string)}`;
} else if (fragment) {
// leaving off the # here would reload the page
window.location.href = currentUrl + '#';
}
}

function filterEmbeddedLogFiles() {
const searchBox = document.getElementById('filter-log-file');
if (searchBox) {
const currentUrl = window.location.href;
const fragment = currentUrl.split('#')[1];
if (fragment) {
const params = fragment.split('&');
for (let i = 0; i < params.length; i++) {
const keyval = params[i].split('=');
if (keyval[0] === 'filter') {
searchBox.value = decodeURIComponent(keyval[1]);
}
}
}
}
const filter = filterLogLines.bind(null, searchBox);
loadEmbeddedLogFiles(filter);
}

function loadEmbeddedLogFiles(filter) {
$('.embedded-logfile').each(function (index, logFileElement) {
if (logFileElement.dataset.contentsLoaded) {
return;
}
$.ajax(logFileElement.dataset.src)
.done(function (response) {
logFileElement.innerHTML = ansiToHtml(response);
logFileElement.dataset.content = response;
if (filter) {
filter();
} else {
logFileElement.innerHTML = ansiToHtml(response);
}
logFileElement.dataset.contentsLoaded = true;
})
.fail(function (jqXHR, textStatus, errorThrown) {
Expand All @@ -594,6 +677,20 @@ function loadEmbeddedLogFiles() {
});
}

window.onload = function () {
const searchBox = document.getElementById('filter-log-file');
if (!searchBox) {
return;
}
const filter = filterLogLines.bind(null, searchBox);
searchBox.addEventListener('keyup', delay(filter), 1000);
searchBox.addEventListener('change', filter, false);
};

function displaySearchInfo(text) {
document.getElementById('filter-info').innerHTML = text;
}

function setCurrentPreviewFromStepLinkIfPossible(stepLink) {
if (tabConfiguration.details.hasContents && !stepLink.parent().is('.current_preview')) {
setCurrentPreview(stepLink.parent());
Expand Down
12 changes: 12 additions & 0 deletions t/ui/18-tests-details.t
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,18 @@ subtest 'misc details: title, favicon, go back, go to source view, go to log vie

wait_for_ajax msg => 'log contents';
like $driver->find_element('.embedded-logfile .ansi-blue-fg')->get_text, qr/send(autotype|key)/, 'log is colorful';
like $driver->find_element('.embedded-logfile')->get_text, qr{/usr/bin/qemu-kvm}, 'qemu-kvm is shown in log viewer';

$driver->find_element('#filter-log-file')->send_keys('kate');
like $driver->find_element('#filter-info')->get_text, qr{Showing 3 / 1292 lines},
'Showing filter result info for substring';
unlike $driver->find_element('.embedded-logfile')->get_text, qr{/usr/bin/qemu-kvm},
'qemu-kvm is not shown when filtering for something else';
$driver->find_element('#filter-log-file')->clear;
like $driver->find_element('#filter-info')->get_text, qr{^$}, 'Filter result info cleared';
$driver->find_element('#filter-log-file')->send_keys('/kate-[12]/');
like $driver->find_element('#filter-info')->get_text, qr{Showing 2 / 1292 lines},
'Showing filter result info for regex';
};

my $t = Test::Mojo->new('OpenQA::WebAPI');
Expand Down
4 changes: 3 additions & 1 deletion templates/webapi/test/logfile.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
%= asset $_ for qw(test_result.js anser.js ansi-colors.css)
% end
% content_for 'ready_function' => begin
loadEmbeddedLogFiles();
filterEmbeddedLogFiles();
% end

% my $url = url_for('test_file', testid => $testid, filename => $filename);
<div class="corner-buttons" style="margin-top: -5px;">
<span id="filter-info"></span>
<input id="filter-log-file" placeholder="substring or /regex/i" type="search">
<a class="btn btn-light" href=".#downloads">
<i class="fa fa-chevron-left"></i> Back to job <%= $testid %>
</a>
Expand Down

0 comments on commit ab9f78b

Please sign in to comment.