+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+function newTaskState() {
+ return {"complete_count": 0,
+ "failure_count": 0,
+ "task_count": 0,
+ "incomplete_count": 0,
+ "nodes": []};
+}
+
function addToLogViewer(logViewer, lines, taskState) {
var re = /((\d\d\d\d)-(\d\d)-(\d\d))_((\d\d):(\d\d):(\d\d)) ([a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{15}) (\d+) (\d+)? (.*)/;
+
+ var items = [];
+ var count = logViewer.items.length;
for (var a in lines) {
var v = lines[a].match(re);
if (v != null) {
- var ts = new Date(Date.UTC(v[2], v[3], v[4], v[6], v[7], v[8]));
+ var ts = new Date(Date.UTC(v[2], v[3]-1, v[4], v[6], v[7], v[8]));
v11 = v[11];
if (typeof v[11] === 'undefined') {
var message = v[12];
var type = "";
var node = "";
+ var slot = "";
if (v11 !== "") {
if (!taskState.hasOwnProperty(v11)) {
taskState[v11] = {};
+ taskState.task_count += 1;
}
if (/^stderr /.test(message)) {
} else if (/^srun: /.test(message) || /^slurmd/.test(message)) {
type = "task-dispatch";
} else {
- type = "task-output";
+ type = "task-print";
}
} else {
- if (/^success /.test(message)) {
+ var m;
+ if (m = /^success in (\d+) second/.exec(message)) {
taskState[v11].outcome = "success";
- taskState.success_count += 1;
+ taskState[v11].runtime = Number(m[1]);
+ taskState.complete_count += 1;
}
- else if (/^failure /.test(message)) {
+ else if (m = /^failure \(\#\d+, (temporary|permanent)\) after (\d+) second/.exec(message)) {
taskState[v11].outcome = "failure";
+ taskState[v11].runtime = Number(m[2]);
taskState.failure_count += 1;
+ if (m[1] == "permanent") {
+ taskState.incomplete_count += 1;
+ }
}
- else {
- var child = message.match(/^child \d+ started on (.*)/);
- if (child != null) {
- taskState[v11].node = child[1];
- for (var i in logViewer.items) {
- if (i > 0) {
- var val = logViewer.items[i].values();
- if (val.taskid === v11) {
- val.node = child[1];
- logViewer.items[i].values(val);
- }
+ else if (m = /^child \d+ started on ([^.]*)\.(\d+)/.exec(message)) {
+ taskState[v11].node = m[1];
+ taskState[v11].slot = m[2];
+ if (taskState.nodes.indexOf(m[1], 0) == -1) {
+ taskState.nodes.push(m[1]);
+ }
+ for (var i in items) {
+ if (i > 0) {
+ if (items[i].taskid === v11) {
+ items[i].node = m[1];
+ items[i].slot = m[2];
}
}
}
type = "task-dispatch";
}
node = taskState[v11].node;
+ slot = taskState[v11].slot;
} else {
- if (/^status: /.test(message)) {
- type = "job-status";
- message = message.substr(8);
- } else {
- type = "crunch";
- }
+ type = "crunch";
}
- logViewer.add({
- id: logViewer.items.length,
+ items.push({
+ id: count,
ts: ts,
timestamp: ts.toLocaleDateString() + " " + ts.toLocaleTimeString(),
taskid: v11,
node: node,
- message: message,
+ slot: slot,
+ message: message.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'),
type: type
});
-
+ count += 1;
} else {
- console.log("Did not parse: " + lines[a]);
+ console.log("Did not parse line " + a + ": " + lines[a]);
}
}
- logViewer.update();
+ logViewer.add(items);
}
function sortById(a, b, opt) {
}
}
+ if (aa["slot"] !== "" && bb["slot"] !== "") {
+ if (aa["slot"] > bb["slot"]) {
+ return 1;
+ }
+ if (aa["slot"] < bb["slot"]) {
+ return -1;
+ }
+ }
+
return sortById(a, b, opt);
}
p = "s";
}
if (n == 0 || n > 1) {
- return (s + p);
+ return n + " " + (s + p);
} else {
- return s;
+ return n + " " + s;
}
}
function generateJobOverview(id, logViewer, taskState) {
var html = "";
- var first = logViewer.items[1];
- var last = logViewer.items[logViewer.items.length-1];
-
- {
- html += "<div>";
- html += "Started at " + first.values().timestamp;
-
+ if (logViewer.items.length > 2) {
+ var first = logViewer.items[1];
+ var last = logViewer.items[logViewer.items.length-1];
var duration = (last.values().ts.getTime() - first.values().ts.getTime()) / 1000;
var hours = 0;
}
seconds = duration;
- var tcount = taskState.success_count + taskState.failure_count;
+ var tcount = taskState.task_count;
- html += ". " + tcount + dumbPluralize(tcount, " task") + " completed in ";
+ html += "<p>";
+ html += "Started at " + first.values().timestamp + ". ";
+ html += "Ran " + dumbPluralize(tcount, " task") + " over ";
if (hours > 0) {
- html += hours + dumbPluralize(hours, " hour");
+ html += dumbPluralize(hours, " hour");
}
if (minutes > 0) {
- html += " " + minutes + dumbPluralize(minutes, " minute");
+ html += " " + dumbPluralize(minutes, " minute");
}
if (seconds > 0) {
- html += " " + seconds + dumbPluralize(seconds, " second");
+ html += " " + dumbPluralize(seconds, " second");
}
- html += ". " + taskState.success_count + dumbPluralize(taskState.success_count, " success", "es");
- html += ", " + taskState.failure_count + dumbPluralize(taskState.failure_count, " failure");
- html += ". Completed at " + last.values().timestamp;
- html += "</div>";
+ html += " using " + dumbPluralize(taskState.nodes.length, " node");
+
+ html += ". " + dumbPluralize(taskState.complete_count, "task") + " completed";
+ html += ", " + dumbPluralize(taskState.incomplete_count, "task") + " incomplete";
+ html += " (" + dumbPluralize(taskState.failure_count, " failure") + ")";
+
+ html += ". Finished at " + last.values().timestamp + ".";
+ html += "</p>";
+ } else {
+ html = "<p>Job log is empty or failed to load.</p>";
}
$(id).html(html);
-}
\ No newline at end of file
+}
+
+function gotoPage(n, logViewer, page, id) {
+ if (n < 0) { return; }
+ if (n*page > logViewer.matchingItems.length) { return; }
+ logViewer.page_offset = n;
+ logViewer.show(n*page, page);
+}
+
+function updatePaging(id, logViewer, page) {
+ var p = "";
+ var i = logViewer.matchingItems.length;
+ var n;
+ for (n = 0; (n*page) < i; n += 1) {
+ if (n == logViewer.page_offset) {
+ p += "<span class='log-viewer-page-num'>" + (n+1) + "</span> ";
+ } else {
+ p += "<a href=\"#\" class='log-viewer-page-num log-viewer-page-" + n + "'>" + (n+1) + "</a> ";
+ }
+ }
+ $(id).html(p);
+ for (n = 0; (n*page) < i; n += 1) {
+ (function(n) {
+ $(".log-viewer-page-" + n).on("click", function() {
+ gotoPage(n, logViewer, page, id);
+ return false;
+ });
+ })(n);
+ }
+
+ if (logViewer.page_offset == 0) {
+ $(".log-viewer-page-up").addClass("text-muted");
+ } else {
+ $(".log-viewer-page-up").removeClass("text-muted");
+ }
+
+ if (logViewer.page_offset == (n-1)) {
+ $(".log-viewer-page-down").addClass("text-muted");
+ } else {
+ $(".log-viewer-page-down").removeClass("text-muted");
+ }
+}
+
+function nextPage(logViewer, page, id) {
+ gotoPage(logViewer.page_offset+1, logViewer, page, id);
+}
+
+function prevPage(logViewer, page, id) {
+ gotoPage(logViewer.page_offset-1, logViewer, page, id);
+}