Skia has proposed merging ~hyask/autopkgtest-cloud:skia/logs_viewer into autopkgtest-cloud:master.
Requested reviews: Canonical's Ubuntu QA (canonical-ubuntu-qa) For more details, see: https://code.launchpad.net/~hyask/autopkgtest-cloud/+git/autopkgtest-cloud/+merge/463108 Adding a log viewer as userscript. -- Your team Canonical's Ubuntu QA is requested to review the proposed merge of ~hyask/autopkgtest-cloud:skia/logs_viewer into autopkgtest-cloud:master.
diff --git a/charms/focal/autopkgtest-web/webcontrol/static/logs-viewer.user.js b/charms/focal/autopkgtest-web/webcontrol/static/logs-viewer.user.js new file mode 100644 index 0000000..27c9349 --- /dev/null +++ b/charms/focal/autopkgtest-web/webcontrol/static/logs-viewer.user.js @@ -0,0 +1,263 @@ +// ==UserScript== +// @name Autopkgtest Logs Enhancer +// @namespace http://tampermonkey.net/ +// @version 2024-03-25 +// @description Does some processing to beautify the tests logs on https://autopkgtest.ubuntu.com +// @author Corentin -Cajuteq- Jacquet, Point Vermeil, https://pointvermeil.fr/ +// @match objectstorage.prodstack5.canonical.com/* +// @match autopkgtest.ubuntu.com/* +// @icon https://www.google.com/s2/favicons?sz=64&domain=mozilla.org +// @grant GM_addStyle +// ==/UserScript== + +(function() { + 'use strict'; + + addEventListener("load", main) + + function main() { + add_surrounding(); + } + + function add_surrounding() { + const css = ` +.button-bar { + position: sticky; + top: 0; + background: #222; +} + +.button-bar button { + margin: 0.5em; +} + +/* ----------------------------------------------------------------- + * Log viewer + * ----------------------------------------------------------------- */ +.log-view .log-divider { + background-color: #2e3436; +} + +.log-view .log-divider a { + font-family: monospace; + font-size: smaller; + color: #66ff66; + font-weight: bold; + padding-left: 50px; +} + +.log-view .log-divider-fail a { + color: #ff6666; +} + +.log-view .log-divider .log-open { + display: none; +} + +.log-view .line-number { + float: left; + width: 50px; + font-family: monospace; + font-size: smaller; + text-align: right; + color: #eeeeec; + user-select: none; +} + +.line-number a, +.line-number a:visited { + padding-right: 0.5em; + display: block; + color: #eeeeec; +} +.line-number a:hover { + background-color: #ffc; + color: #888a85; +} + +.log-view .log-line { + margin-left: 50px; + padding-left: 0.5em; + padding-right: 0.5em; + font-family: monospace; + font-size: smaller; + background-color: #2e3436; + color: #eeeeec; + white-space: pre-wrap; +} + +.log-section > .line-number:first-child + .log-line, +.log-section > .line-number:first-child { + padding-top: 0.5em; +} + +.log-section .log-line:last-child { + padding-bottom: 0.5em; +} + +.log-view { + border: 1px solid #040000; +} + +.log-section { + background-color: #555753; +} + +.log-view .log-nav { + float: right; + margin-right: 1em; +} + +#logview-index .section-index-group { + margin-top: 1em; +} + +#logview-index a:hover { + background-color: #ffc; +} + ` + GM_addStyle(css) + const rawlog = document.getElementsByTagName("pre")[0] + const newDiv = document.createElement("div"); + newDiv.className = "log-view"; + + const buttonBar = document.createElement("div"); + buttonBar.className = "button-bar"; + + const foldAllButton = document.createElement("button"); + foldAllButton.innerText = "fold all" + foldAllButton.addEventListener('click', () => { + var sections = document.getElementsByClassName("log-section") + for (var section of sections) { + section.style.display = "none"; + } + var sectionsArrowLeft = document.getElementsByClassName("log-open") + for (var sectionArrowLeft of sectionsArrowLeft) { + sectionArrowLeft.style.display = "inherit"; + } + var sectionsArrowDown = document.getElementsByClassName("log-close") + for (var sectionArrowDown of sectionsArrowDown) { + sectionArrowDown.style.display = "none"; + } + }) + buttonBar.appendChild(foldAllButton) + const unfoldAllButton = document.createElement("button"); + unfoldAllButton.innerText = "unfold all" + unfoldAllButton.addEventListener('click', () => { + var sections = document.getElementsByClassName("log-section") + for (var section of sections) { + section.style.display = "inherit"; + } + var sectionsArrowLeft = document.getElementsByClassName("log-open") + for (var sectionArrowLeft of sectionsArrowLeft) { + sectionArrowLeft.style.display = "none"; + } + var sectionsArrowDown = document.getElementsByClassName("log-close") + for (var sectionArrowDown of sectionsArrowDown) { + sectionArrowDown.style.display = "inherit"; + } + }) + buttonBar.appendChild(unfoldAllButton) + newDiv.appendChild(buttonBar) + + + const linedLog = rawlog.innerText.split("\n"); + + function toggleLogSection(section) { + var arrows = section.getElementsByClassName("log-toggle") + if (arrows[0].style.display == "none") { + arrows[0].style.display = "inline"; + arrows[1].style.display = "none"; + section.parentElement.nextSibling.style.display = "none"; + + } else { + arrows[0].style.display = "none"; + arrows[1].style.display = "inline"; + section.parentElement.nextSibling.style.display = "inherit"; + + } + }; + + + var logSection + var logDivider + + var logSectionNb = 0; + function createSection(text){ + logSectionNb+=1; + logDivider = document.createElement("div"); + logDivider.className = "log-divider log-divider-"; + newDiv.appendChild(logDivider); + + const dividerAnchor = document.createElement("a"); + dividerAnchor.href = "#S"+logSectionNb; + dividerAnchor.onclick = function() {return toggleLogSection(this)} + const dividerArrowLeft = document.createElement("span"); + dividerArrowLeft.className = "log-toggle log-open" + dividerArrowLeft.style.display = "none"; + const dividerArrowDown = document.createElement("span"); + dividerArrowDown.className = "log-toggle log-close" + dividerArrowDown.style.display = "inline"; + const dividerArrowLeftContent = document.createTextNode(" ▸ "); + dividerArrowLeft.appendChild(dividerArrowLeftContent) + const dividerArrowDownContent = document.createTextNode(" ▾ "); + dividerArrowDown.appendChild(dividerArrowDownContent) + const dividerName = document.createElement("span"); + dividerName.className = "log-section-name" + const dividerContent = document.createTextNode(text); + dividerName.appendChild(dividerContent) + + dividerAnchor.appendChild(dividerArrowLeft) + dividerAnchor.appendChild(dividerArrowDown) + dividerAnchor.appendChild(dividerName) + logDivider.appendChild(dividerAnchor); + + logSection = document.createElement("div"); + logSection.className = "log-section"; + newDiv.appendChild(logSection); + }; + + for (const line in linedLog) { + switch (true) { + case /autopkgtest.*: starting date/.test(linedLog[line]): + createSection("start run"); + break; + case /autopkgtest.*: @@@@@@@@@@@@@@@@@@@@ test bed setup/.test(linedLog[line]): + createSection("test bed setup"); + break; + case /autopkgtest.*: @@@@@@@@@@@@@@@@@@@@ apt-source/.test(linedLog[line]): + createSection("apt-source"); + break; + case /autopkgtest.*: test(.*)testbed/.test(linedLog[line]): + var group = linedLog[line].match(/autopkgtest.*: test(.*)testbed/) + createSection(" test " + group[1] + " preparing testbed"); + break; + case /autopkgtest.*: @@@@@@@@@@@@@@@@@@@@ summary/.test(linedLog[line]): + createSection("summary"); + break; + default: + break; + } + + const lineNumber = document.createElement("span"); + lineNumber.id = line; + lineNumber.className = "line-number"; + const lineAnchor = document.createElement("a"); + lineAnchor.href = "#"+line; + const lineNb = document.createTextNode(line); + lineAnchor.appendChild(lineNb) + lineNumber.appendChild(lineAnchor); + logSection.appendChild(lineNumber); + + const logLine = document.createElement("div"); + logLine.className = "log-line"; + const newContent = document.createTextNode(linedLog[line]); + logLine.appendChild(newContent); + + logSection.appendChild(logLine); + } + + document.body.insertBefore(newDiv, rawlog); + rawlog.remove(); + } +})(); diff --git a/charms/focal/autopkgtest-web/webcontrol/templates/browse-results.html b/charms/focal/autopkgtest-web/webcontrol/templates/browse-results.html index 05a3c2e..fadff6d 100644 --- a/charms/focal/autopkgtest-web/webcontrol/templates/browse-results.html +++ b/charms/focal/autopkgtest-web/webcontrol/templates/browse-results.html @@ -60,6 +60,9 @@ </td> </tr> {% endfor %} - </table> + + <p> + To ease the browsing of logs, you can use <a href="{{ url_for('static', filename='logs-viewer.user.js') }}">this userscript</a> with any extension supporting that, like <a href="https://www.tampermonkey.net/">TamperMonkey</a>. + </p> {% endblock %}
-- Mailing list: https://launchpad.net/~canonical-ubuntu-qa Post to : canonical-ubuntu-qa@lists.launchpad.net Unsubscribe : https://launchpad.net/~canonical-ubuntu-qa More help : https://help.launchpad.net/ListHelp