canonical-ubuntu-qa team mailing list archive
-
canonical-ubuntu-qa team
-
Mailing list archive
-
Message #03533
[Merge] ~hyask/autopkgtest-cloud:skia/logs_viewer into autopkgtest-cloud:master
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 %}