diff options
-rw-r--r-- | src/journal/browse.html | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/src/journal/browse.html b/src/journal/browse.html new file mode 100644 index 0000000000..b901d7a908 --- /dev/null +++ b/src/journal/browse.html @@ -0,0 +1,282 @@ +<!DOCTYPE html> +<html> +<head> + <title>Journal</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <style type="text/css"> + div#logs { + font-family: monospace; + font-size: 8pt; + background-color: #ffffff; + padding: 1em; + margin: 2em 0em; + border-radius: 10px 10px 10px 10px; + border: 1px solid threedshadow; + white-space: nowrap; + overflow-x: scroll; + } + body { + background-color: #ededed; + color: #313739; + font: message-box; + margin: 5em; + } + + .log-error { + color: red; + font-weight: bold; + } + .log-highlight { + font-weight: bold; + } + </style> +</head> + +<body> + <!-- TODO: + + - seek to back properly + - handle seek before front properly + - show red lines for reboots + - show contents of entries --> + + <h1 id="title"></h1> + + <div id="os"></div> + <div id="virtualization"></div> + <div id="cutoff"></div> + <div id="machine"></div> + <div id="usage"></div> + <div id="showing"></div> + + <div id="logs"></div> + + <form> + <input id="head" type="button" value="|<" onclick="entriesLoadHead();"/> + <input id="previous" type="button" value="<<" onclick="entriesLoadPrevious();"/> + <input id="next" type="button" value=">>" onclick="entriesLoadNext();"/> + <input id="tail" type="button" value=">|" onclick="entriesLoadTail();"/> + + <input id="more" type="button" value="More" onclick="entriesMore();"/> + <input id="less" type="button" value="Less" onclick="entriesLess();"/> + </form> + + <script type="text/javascript"> + var first_cursor = null; + var last_cursor = null; + + function setCookie(name, value, msec) { + var d = new Date(); + d.setMilliseconds(d.getMilliseconds() + msec); + var v = escape(value) + "; expires=" + d.toUTCString(); + document.cookie = name + "=" + value; + } + + function getCookie(name) { + var i, l; + l = document.cookie.split(";"); + for (i in l) { + var x, y, j; + j = l[i].indexOf("="); + x = l[i].substr(0, j); + y = l[i].substr(j+1); + if (x == name) + return unescape(y); + } + return null; + } + + function getNEntries() { + var n; + n = getCookie("n_entries"); + if (n == null) + return 50; + return parseInt(n); + } + + function showNEntries(n) { + var showing = document.getElementById("showing"); + showing.innerHTML = "Showing <b>" + n.toString() + "</b> entries."; + } + + function setNEntries(n) { + if (n < 10) + n = 10; + else if (n > 1000) + n = 1000; + + setCookie("n_entries", n.toString(), 30*24*60*60*1000); + showNEntries(n); + } + + function machineLoad() { + var request = new XMLHttpRequest(); + request.open("GET", "/machine"); + request.onreadystatechange = machineOnResult; + request.setRequestHeader("Accept", "application/json"); + request.send(null); + } + + function formatBytes(u) { + if (u >= 1024*1024*1024*1024) + return (u/1024/1024/1024/1024).toFixed(1) + " TiB"; + else if (u >= 1024*1024*1024) + return (u/1024/1024/1024).toFixed(1) + " GiB"; + else if (u >= 1024*1024) + return (u/1024/1024).toFixed(1) + " MiB"; + else if (u >= 1024) + return (u/1024).toFixed(1) + " KiB"; + else + return u.toString() + " B"; + } + + function machineOnResult(event) { + if ((event.currentTarget.readyState != 4) || + (event.currentTarget.status != 200 && event.currentTarget.status != 0)) + return; + + var d = JSON.parse(event.currentTarget.responseText); + + var title = document.getElementById("title"); + title.innerHTML = 'Journal of ' + d.hostname; + document.title = 'Journal of ' + d.hostname; + + var machine = document.getElementById("machine"); + machine.innerHTML = 'Machine ID is <b>' + d.machine_id + '</b>, current boot ID is <b>' + d.boot_id + '</b>.'; + + var cutoff = document.getElementById("cutoff"); + var from = new Date(parseInt(d.cutoff_from_realtime) / 1000); + var to = new Date(parseInt(d.cutoff_to_realtime) / 1000); + cutoff.innerHTML = 'Journal begins at <b>' + from.toLocaleString() + '</b> and ends at <b>' + to.toLocaleString() + '</b>.'; + + var usage = document.getElementById("usage"); + usage.innerHTML = 'Disk usage is <b>' + formatBytes(parseInt(d.usage)) + '</b>.'; + + var os = document.getElementById("os"); + os.innerHTML = 'Operating system is <b>' + d.os_pretty_name + '</b>.'; + + var virtualization = document.getElementById("virtualization"); + virtualization.innerHTML = d.virtualization == "bare" ? "Running on <b>bare metal</b>." : "Running on virtualization <b>" + d.virtualization + "</b>."; + } + + function entriesLoad(range) { + var request = new XMLHttpRequest(); + request.open("GET", "/entries"); + request.onreadystatechange = entriesOnResult; + request.setRequestHeader("Accept", "application/json"); + request.setRequestHeader("Range", "entries=" + range + ":" + getNEntries().toString()); + request.send(null); + } + + function entriesLoadNext() { + if (last_cursor == null) + entriesLoad(""); + else + entriesLoad(last_cursor + ":1"); + } + + function entriesLoadPrevious() { + if (first_cursor == null) + entriesLoad(""); + else + entriesLoad(first_cursor + ":-" + getNEntries().toString()); + } + + function entriesLoadHead() { + entriesLoad(""); + } + + function entriesLoadTail() { + entriesLoad(":-" + getNEntries().toString()); + } + + function entriesOnResult(event) { + + if ((event.currentTarget.readyState != 4) || + (event.currentTarget.status != 200 && event.currentTarget.status != 0)) + return; + + var logs = document.getElementById("logs"); + logs.innerHTML = ""; + + var lc = null; + var fc = null; + + var i; + var l = event.currentTarget.responseText.split('\n'); + + if (l.length <= 1) { + logs.innerHTML = "<i>No further entries...</i>"; + return; + } + + for (i in l) { + + if (l[i] == '') + continue; + + var d = JSON.parse(l[i]); + if (d.MESSAGE == undefined || d.__CURSOR == undefined) + continue; + + if (fc == null) + fc = d.__CURSOR; + lc = d.__CURSOR; + + var priority; + if (d.PRIORITY != undefined) + priority = parseInt(d.PRIORITY); + else + priority = 6; + + if (priority <= 3) + clazz = "log-error"; + else if (priority <= 5) + clazz = "log-highlight"; + else + clazz = "log-normal"; + + var line = '<div class="' + clazz + '">'; + + if (d.SYSLOG_IDENTIFIER != undefined) + line += d.SYSLOG_IDENTIFIER; + else if (d._COMM != undefined) + line += d._COMM; + + if (d._PID != undefined) + line += "[" + d._PID + "]"; + else if (d.SYSLOG_PID != undefined) + line += "[" + d.SYSLOG_PID + "]"; + + if (d.MESSAGE == null) + line += ": [blob data]</div>"; + else if (d.MESSAGE instanceof Array) + line += ": [" + formatBytes(d.MESSAGE.length) + " blob data]</div>"; + else + line += ": " + d.MESSAGE + "</div>"; + + logs.innerHTML += line; + } + + if (fc != null) + first_cursor = fc; + if (lc != null) + last_cursor = lc; + } + + function entriesMore() { + setNEntries(getNEntries() + 10); + entriesLoad(""); + } + + function entriesLess() { + setNEntries(getNEntries() - 10); + entriesLoad(""); + } + + machineLoad(); + entriesLoad(""); + showNEntries(getNEntries()); + </script> +</body> +</html> |