diff --git a/contrib/log_visualizer.html b/contrib/log_visualizer.html
index b590a74d582c..3e05bfae0d3d 100644
--- a/contrib/log_visualizer.html
+++ b/contrib/log_visualizer.html
@@ -154,7 +154,108 @@
document.getElementById('filter_error').innerText = error.message;
}
}
-function do_render(logs, area)
+function tab_option(type_str, regex_prefix, regex_postfix, nodes, logs)
+{
+ str = type_str + " log with multiple nodes detected.\n\n";
+ str += "Would you like to open them all with new tabs?\n\n";
+ str += "Nodes detected:\n" + nodes.join("\n");
+
+ function make_regex(key) {
+ return new RegExp(regex_prefix + key + regex_postfix, "g");
+ }
+
+ if(!confirm(str))
+ return null;
+
+ function load_next_tab() {
+ if (!nodes.length)
+ return;
+ window.addEventListener('message', on_recv_msg);
+ w = window.open(window.location.href, '_blank');
+ w.blur();
+ window.focus();
+ }
+ function on_recv_msg(msg) {
+ if(msg.data == "v0.1-ready") {
+ msg.source.postMessage({"version": "v0.1-data", "logs": logs, "prefix": make_regex(nodes.shift())}, "*");
+ window.removeEventListener('message', on_recv_msg);
+ load_next_tab();
+ }
+ }
+ var result = make_regex(nodes.shift());
+ load_next_tab();
+ return result;
+}
+function single_option(type_str, regex_prefix, regex_postfix, nodes)
+{
+ str = type_str + " log with multiple nodes detected.\n\n";
+ str += "Which would you like rendered?\n\n";
+ str += "Nodes detected:\n" + nodes.join("\n");
+
+ function make_regex(key) {
+ return new RegExp(regex_prefix + key + regex_postfix, "g");
+ }
+
+ var result = prompt(str, nodes[0]);
+
+ return result ? make_regex(result.trim()) : null;
+}
+function detect_ci_logs(logs)
+{
+ nodes = new Set()
+ Array.from(logs.matchAll(/[0-9\-T:.Z]+ (lightningd-[0-9]+) /g)).forEach(match => {
+ nodes.add(match[1]);
+ });
+ var keys = [...nodes];
+
+ if (keys.length > 1)
+ return tab_option("Continous Integration", "[0-9\-T:.Z]+ ", " ", keys, logs)
+ || single_option("Continous Integration", "[0-9\-T:.Z]+ ", " ", keys);
+
+ return keys.at(0);
+}
+function detect_pytest_logs(logs)
+{
+ nodes = new Set()
+ Array.from(logs.matchAll(/(lightningd-[0-9]+) /g)).forEach(match => {
+ nodes.add(match[1]);
+ });
+ var keys = [...nodes];
+
+ if (keys.length > 1)
+ return tab_option("Python Test", "", " ", keys, logs)
+ || single_option("Python Test", "", " ", keys);
+
+ return keys.at(0);
+}
+window.onload = function() {
+ if (window.opener) {
+ function receive_data_message(msg) {
+ if (!msg.data || msg.data.version != "v0.1-data") {
+ console.log("Unrecognized data message");
+ console.log(msg);
+ }
+ else {
+ do_render(msg.data.logs, document.getElementById('area'), msg.data.prefix);
+ window.removeEventListener('message', receive_data_message);
+ }
+ }
+ window.addEventListener('message', receive_data_message);
+ console.log(window.opener);
+ window.opener.postMessage("v0.1-ready", "*");
+ }
+}
+function detect_log_prefix(logs)
+{
+ var ci = detect_ci_logs(logs)
+ if (ci)
+ return ci;
+ var pytest = detect_pytest_logs(logs)
+ if (pytest)
+ return pytest;
+ return null;
+}
+function do_render(logs, area, prefix)
{
var d = document;
var sheet = d.getElementById('logStyleSheet').sheet;
@@ -168,11 +269,22 @@
while(sheet.cssRules.length)
sheet.deleteRule(0);
+ if(!prefix)
+ prefix = detect_log_prefix(logs);
+
for(line of logs.split("\n")) {
line = line.trim()
if(!line.length)
continue;
+ /* Detect and eat node prefix. If no prefix match, ignore line */
+ if (prefix) {
+ prefix_match = line.match(prefix);
+ if(!prefix_match)
+ continue;
+ line = line.slice(prefix_match[0].length);
+ }
+
info = parseLogLine(line);
if(info.msg.startsWith('Server started with public key'))