5 <meta http-equiv=
"Content-Type" content=
"text/html; charset=utf-8"/>
6 <style type=
"text/css">
7 div#divlogs, div#diventry {
8 font-family: monospace;
10 background-color: #ffffff;
13 border-radius:
10px
10px
10px
10px;
14 border:
1px solid threedshadow;
25 background-color: #ededed;
32 border-right:
1px dotted lightgrey;
36 border-right:
1px dotted lightgrey;
43 td.message
> a:link, td.message
> a:visited {
44 text-decoration: none;
52 td.message-error
> a:link, td.message-error
> a:visited {
53 text-decoration: none;
56 td.message-highlight {
60 td.message-highlight
> a:link, td.message-highlight
> a:visited {
61 text-decoration: none;
64 td
> a:hover, td
> a:active {
65 text-decoration: underline;
68 table#tablelogs, table#tableentry {
69 border-collapse: collapse;
73 border-right:
1px dotted lightgrey;
96 - show red lines for reboots -->
101 <div id=
"virtualization"></div>
102 <div id=
"cutoff"></div>
103 <div id=
"machine"></div>
104 <div id=
"usage"></div>
105 <div id=
"showing"></div>
107 <div id=
"divlogs"><table id=
"tablelogs"></table></div>
109 <div id=
"diventry"><table id=
"tableentry"></table></div>
112 <input id=
"head" type=
"button" value=
"|<" onclick=
"entriesLoadHead();"/>
113 <input id=
"previous" type=
"button" value=
"<<" onclick=
"entriesLoadPrevious();"/>
114 <input id=
"next" type=
"button" value=
">>" onclick=
"entriesLoadNext();"/>
115 <input id=
"tail" type=
"button" value=
">|" onclick=
"entriesLoadTail();"/>
116
117 <input id=
"more" type=
"button" value=
"More" onclick=
"entriesMore();"/>
118 <input id=
"less" type=
"button" value=
"Less" onclick=
"entriesLess();"/>
122 <span class=
"key">→, j, SPACE
</span>: Next Page
123 <span class=
"key">←, k, BACKSPACE
</span>: Previous Page
124 <span class=
"key">g
</span>: First Page
125 <span class=
"key">G
</span>: Last Page
126 <span class=
"key">+
</span>: More entries
127 <span class=
"key">-
</span>: Fewer entries
130 <script type=
"text/javascript">
131 var first_cursor = null;
132 var last_cursor = null;
134 function setCookie(name, value, msec) {
136 d.setMilliseconds(d.getMilliseconds() + msec);
137 var v = escape(value) +
"; expires=" + d.toUTCString();
138 document.cookie = name +
"=" + value;
141 function getCookie(name) {
143 l = document.cookie.split(
";");
146 j = l[i].indexOf(
"=");
147 x = l[i].substr(
0, j);
148 y = l[i].substr(j+
1);
155 function getNEntries() {
157 n = getCookie(
"n_entries");
163 function showNEntries(n) {
164 var showing = document.getElementById(
"showing");
165 showing.innerHTML =
"Showing <b>" + n.toString() +
"</b> entries.";
168 function setNEntries(n) {
174 setCookie(
"n_entries", n.toString(),
30*
24*
60*
60*
1000);
178 function machineLoad() {
179 var request = new XMLHttpRequest();
180 request.open(
"GET",
"/machine");
181 request.onreadystatechange = machineOnResult;
182 request.setRequestHeader(
"Accept",
"application/json");
186 function formatBytes(u) {
187 if (u
>=
1024*
1024*
1024*
1024)
188 return (u/
1024/
1024/
1024/
1024).toFixed(
1) +
" TiB";
189 else if (u
>=
1024*
1024*
1024)
190 return (u/
1024/
1024/
1024).toFixed(
1) +
" GiB";
191 else if (u
>=
1024*
1024)
192 return (u/
1024/
1024).toFixed(
1) +
" MiB";
194 return (u/
1024).toFixed(
1) +
" KiB";
196 return u.toString() +
" B";
199 function escapeHTML(s) {
200 return s.replace(/&/g,
"&").replace(/
</g,
"<").replace(
/>/g,
">");
203 function machineOnResult(event) {
204 if ((event.currentTarget.readyState !=
4) ||
205 (event.currentTarget.status !=
200 && event.currentTarget.status !=
0))
208 var d = JSON.parse(event.currentTarget.responseText);
210 var title = document.getElementById(
"title");
211 title.innerHTML = 'Journal of ' + escapeHTML(d.hostname);
212 document.title = 'Journal of ' + escapeHTML(d.hostname);
214 var machine = document.getElementById(
"machine");
215 machine.innerHTML = 'Machine ID is
<b>' + d.machine_id + '
</b>, current boot ID is
<b>' + d.boot_id + '
</b>.';
217 var cutoff = document.getElementById(
"cutoff");
218 var from = new Date(parseInt(d.cutoff_from_realtime) /
1000);
219 var to = new Date(parseInt(d.cutoff_to_realtime) /
1000);
220 cutoff.innerHTML = 'Journal begins at
<b>' + from.toLocaleString() + '
</b> and ends at
<b>' + to.toLocaleString() + '
</b>.';
222 var usage = document.getElementById(
"usage");
223 usage.innerHTML = 'Disk usage is
<b>' + formatBytes(parseInt(d.usage)) + '
</b>.';
225 var os = document.getElementById(
"os");
226 os.innerHTML = 'Operating system is
<b>' + escapeHTML(d.os_pretty_name) + '
</b>.';
228 var virtualization = document.getElementById(
"virtualization");
229 virtualization.innerHTML = d.virtualization ==
"bare" ?
"Running on <b>bare metal</b>." :
"Running on virtualization <b>" + escapeHTML(d.virtualization) +
"</b>.";
232 function entriesLoad(range) {
233 var request = new XMLHttpRequest();
234 request.open(
"GET",
"/entries");
235 request.onreadystatechange = entriesOnResult;
236 request.setRequestHeader(
"Accept",
"application/json");
237 request.setRequestHeader(
"Range",
"entries=" + range +
":" + getNEntries().toString());
241 function entriesLoadNext() {
242 if (last_cursor == null)
245 entriesLoad(last_cursor +
":1");
248 function entriesLoadPrevious() {
249 if (first_cursor == null)
252 entriesLoad(first_cursor +
":-" + getNEntries().toString());
255 function entriesLoadHead() {
259 function entriesLoadTail() {
260 entriesLoad(
":-" + getNEntries().toString());
263 function entriesOnResult(event) {
265 if ((event.currentTarget.readyState !=
4) ||
266 (event.currentTarget.status !=
200 && event.currentTarget.status !=
0))
269 var logs = document.getElementById(
"tablelogs");
275 var l = event.currentTarget.responseText.split('\n');
278 logs.innerHTML = '
<tbody><tr><td colspan=
"3"><i>No further entries...
</i></td></tr></tbody>';
289 var d = JSON.parse(l[i]);
290 if (d.MESSAGE == undefined || d.__CURSOR == undefined)
298 if (d.PRIORITY != undefined)
299 priority = parseInt(d.PRIORITY);
304 clazz =
"message-error";
305 else if (priority <=
5)
306 clazz =
"message-highlight";
310 buf += '
<tr><td class=
"timestamp">';
312 if (d.__REALTIME_TIMESTAMP != undefined) {
313 var timestamp = new Date(parseInt(d.__REALTIME_TIMESTAMP) /
1000);
314 buf += timestamp.toLocaleString();
317 buf += '
</td><td class=
"process">';
319 if (d.SYSLOG_IDENTIFIER != undefined)
320 buf += escapeHTML(d.SYSLOG_IDENTIFIER);
321 else if (d._COMM != undefined)
322 buf += escapeHTML(d._COMM);
324 if (d._PID != undefined)
325 buf +=
"[" + escapeHTML(d._PID) +
"]";
326 else if (d.SYSLOG_PID != undefined)
327 buf +=
"[" + escapeHTML(d.SYSLOG_PID) +
"]";
329 buf += '
</td><td class=
"' + clazz + '"><a href=
"#entry" onclick=
"onMessageClick(\'' + lc + '\');">';
331 if (d.MESSAGE == null)
332 buf +=
"[blob data]";
333 else if (d.MESSAGE instanceof Array)
334 buf +=
"[" + formatBytes(d.MESSAGE.length) +
" blob data]";
336 buf += escapeHTML(d.MESSAGE);
338 buf += '
</a></td></tr>';
341 logs.innerHTML = '
<tbody>' + buf + '
</tbody>';
349 function entriesMore() {
350 setNEntries(getNEntries() +
10);
351 entriesLoad(first_cursor);
354 function entriesLess() {
355 setNEntries(getNEntries() -
10);
356 entriesLoad(first_cursor);
359 function onResultMessageClick(event) {
360 if ((event.currentTarget.readyState !=
4) ||
361 (event.currentTarget.status !=
200 && event.currentTarget.status !=
0))
364 var d = JSON.parse(event.currentTarget.responseText);
366 document.getElementById(
"diventry").style.display =
"block";
367 entry = document.getElementById(
"tableentry");
374 data =
"[blob data]";
375 else if (data instanceof Array)
376 data =
"[" + formatBytes(data.length) +
" blob data]";
378 data = escapeHTML(data);
380 buf += '
<tr><td class=
"field">' + key + '
</td><td class=
"data">' + data + '
</td></tr>';
382 entry.innerHTML = '
<tbody>' + buf + '
</tbody>';
385 function onMessageClick(t) {
386 var request = new XMLHttpRequest();
387 request.open(
"GET",
"/entries?discrete");
388 request.onreadystatechange = onResultMessageClick;
389 request.setRequestHeader(
"Accept",
"application/json");
390 request.setRequestHeader(
"Range",
"entries=" + t +
":0:1");
394 function onKeyUp(event) {
395 switch (event.keyCode) {
399 entriesLoadPrevious();
422 function onMouseWheel(event) {
423 if (event.detail <
0 || event.wheelDelta
> 0)
424 entriesLoadPrevious();
431 showNEntries(getNEntries());
432 document.onkeyup = onKeyUp;
434 logs = document.getElementById(
"tablelogs");
435 logs.addEventListener(
"mousewheel", onMouseWheel, false);
436 logs.addEventListener(
"DOMMouseScroll", onMouseWheel, false);