2883: Added big red "show failed tasks" button.
[arvados.git] / apps / workbench / app / assets / javascripts / log_viewer.js
index d6c611bf78ab9beaab874b81ba4fcd47f6ade978..e51b4223c4b9e19448a5f7f8bf3259044c4e2666 100644 (file)
@@ -1,3 +1,11 @@
+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+)? (.*)/;
     for (var a in lines) {
@@ -8,12 +16,21 @@ function addToLogViewer(logViewer, lines, taskState) {
 
             v11 = v[11];
             if (typeof v[11] === 'undefined') {
-                v11 = ' ';
+                v11 = "";
+            } else {
+                v11 = Number(v11);
             }
 
             var message = v[12];
             var type = "";
-            if (v11 != ' ') {
+            var node = "";
+            var slot = "";
+            if (v11 !== "") {
+                if (!taskState.hasOwnProperty(v11)) {
+                    taskState[v11] = {};
+                    taskState.task_count += 1;
+                }
+
                 if (/^stderr /.test(message)) {
                     message = message.substr(7);
                     if (/^crunchstat: /.test(message)) {
@@ -25,27 +42,54 @@ function addToLogViewer(logViewer, lines, taskState) {
                         type = "task-output";
                     }
                 } else {
-                    if (/^success in (\d+)/) {
-                        taskState[v11] = "success";
+                    var m;
+                    if (m = /^success in (\d+) second/.exec(message)) {
+                        taskState[v11].outcome = "success";
+                        taskState[v11].runtime = Number(m[1]);
+                        taskState.complete_count += 1;
+                        console.log(taskState[v11].runtime);
+                    }
+                    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;
+                        }
+                        console.log(taskState[v11].runtime);
                     }
-                    if (/^failure \([^)]+\) (\d+)/) {
-                        taskState[v11] = "failure";
+                    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 logViewer.items) {
+                            if (i > 0) {
+                                var val = logViewer.items[i].values();
+                                if (val.taskid === v11) {
+                                    val.node = m[1];
+                                    val.slot = m[2];
+                                    logViewer.items[i].values(val);
+                                }
+                            }
+                        }
                     }
                     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,
+                ts: ts,
                 timestamp: ts.toLocaleDateString() + " " + ts.toLocaleTimeString(),
                 taskid: v11,
+                node: node,
+                slot: slot,
                 message: message,
                 type: type
             });
@@ -56,3 +100,135 @@ function addToLogViewer(logViewer, lines, taskState) {
     }
     logViewer.update();
 }
+
+function sortById(a, b, opt) {
+    a = a.values();
+    b = b.values();
+
+    if (a["id"] > b["id"]) {
+        return 1;
+    }
+    if (a["id"] < b["id"]) {
+        return -1;
+    }
+    return 0;
+}
+
+function sortByTask(a, b, opt) {
+    var aa = a.values();
+    var bb = b.values();
+
+    if (aa["taskid"] === "" && bb["taskid"] !== "") {
+        return -1;
+    }
+    if (aa["taskid"] !== "" && bb["taskid"] === "") {
+        return 1;
+    }
+
+    if (aa["taskid"] !== "" && bb["taskid"] !== "") {
+        if (aa["taskid"] > bb["taskid"]) {
+            return 1;
+        }
+        if (aa["taskid"] < bb["taskid"]) {
+            return -1;
+        }
+    }
+
+    return sortById(a, b, opt);
+}
+
+function sortByNode(a, b, opt) {
+    var aa = a.values();
+    var bb = b.values();
+
+    if (aa["node"] === "" && bb["node"] !== "") {
+        return -1;
+    }
+    if (aa["node"] !== "" && bb["node"] === "") {
+        return 1;
+    }
+
+    if (aa["node"] !== "" && bb["node"] !== "") {
+        if (aa["node"] > bb["node"]) {
+            return 1;
+        }
+        if (aa["node"] < bb["node"]) {
+            return -1;
+        }
+    }
+
+    if (aa["slot"] !== "" && bb["slot"] !== "") {
+        if (aa["slot"] > bb["slot"]) {
+            return 1;
+        }
+        if (aa["slot"] < bb["slot"]) {
+            return -1;
+        }
+    }
+
+    return sortById(a, b, opt);
+}
+
+
+function dumbPluralize(n, s, p) {
+    if (typeof p === 'undefined') {
+        p = "s";
+    }
+    if (n == 0 || n > 1) {
+        return n + " " + (s + p);
+    } else {
+        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;
+
+        var duration = (last.values().ts.getTime() - first.values().ts.getTime()) / 1000;
+
+        var hours = 0;
+        var minutes = 0;
+        var seconds;
+
+        if (duration >= 3600) {
+            hours = Math.floor(duration / 3600);
+            duration -= (hours * 3600);
+        }
+        if (duration >= 60) {
+            minutes = Math.floor(duration / 60);
+            duration -= (minutes * 60);
+        }
+        seconds = duration;
+
+        var tcount = taskState.task_count;
+
+        html += ".  Ran " + dumbPluralize(tcount, " task") + " over ";
+        if (hours > 0) {
+            html += dumbPluralize(hours, " hour");
+        }
+        if (minutes > 0) {
+            html += " " + dumbPluralize(minutes, " minute");
+        }
+        if (seconds > 0) {
+            html += " " + dumbPluralize(seconds, " second");
+        }
+
+        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 += "</div>";
+    }
+
+    $(id).html(html);
+}
\ No newline at end of file