LogViewer

Molecule

A log list for many lines: severity as a text label and colour, search with highlight, severity and field facet chips, a wrap toggle, copy line, context lines pulled in around a selected line when the list is filtered, and a follow mode for a live tail (pauses when the user scrolls up, counts new lines, shows a drop counter). Same locals, DOM and classes as kui-react. The server draws the first window of rows; the lines travel as JSON next to it (at most `maxLines`, default 10 000: the newest are kept and the rest is added to the drop counter) and `LogViewer/scripts/log-viewer.js` windows, filters, highlights and follows in the browser. React's callbacks are the bubbling `kui:log-select`, `kui:log-copy`, `kui:log-query-change`, `kui:log-wrap-change` and `kui:log-follow-change` events; `query`, `wrap` and `follow` (controlled in React) are the state at render time and make the script only emit them. React's `useLogStream` is `KuiLogViewer.push(root, lines, { dropped })`, which appends, keeps the newest `maxLines` and counts what it dropped.

2 000 lines (windowed)

Preview
severity
region
service
status
TRACE handled request 0 in 20 ms
DEBUG handled request 1 in 21 ms
INFO handled request 2 in 22 ms
INFO handled request 3 in 23 ms
INFO handled request 4 in 24 ms
INFO handled request 5 in 25 ms
WARN slow query on request 6 (1.2 s)
INFO handled request 7 in 27 ms
ERROR request 8 failed: upstream timeout after 3000 ms
INFO handled request 9 in 29 ms
TRACE handled request 10 in 30 ms
DEBUG handled request 11 in 31 ms
INFO handled request 12 in 32 ms
INFO handled request 13 in 33 ms
INFO handled request 14 in 34 ms
INFO handled request 15 in 35 ms
WARN slow query on request 16 (1.2 s)
INFO handled request 17 in 37 ms
ERROR request 18 failed: upstream timeout after 3000 ms
INFO handled request 19 in 39 ms
TRACE handled request 20 in 40 ms
DEBUG handled request 21 in 41 ms
INFO handled request 22 in 42 ms
INFO handled request 23 in 43 ms
INFO handled request 24 in 44 ms
Code
<%- include('modules/ui/LogViewer', { lines: lines, height: 320 }) %>
<script>
  document.addEventListener('kui:log-select', (e) => openLine(e.detail.id));
</script>

Highlight mode, wrapped

Preview
1 of 40
400 of 400 lines
severity
region
service
status
TRACE handled request 0 in 20 ms
DEBUG handled request 1 in 21 ms
INFO handled request 2 in 22 ms
INFO handled request 3 in 23 ms
INFO handled request 4 in 24 ms
INFO handled request 5 in 25 ms
WARN slow query on request 6 (1.2 s)
INFO handled request 7 in 27 ms
ERROR request 8 failed: upstream timeout after 3000 ms
INFO handled request 9 in 29 ms
TRACE handled request 10 in 30 ms
DEBUG handled request 11 in 31 ms
INFO handled request 12 in 32 ms
INFO handled request 13 in 33 ms
INFO handled request 14 in 34 ms
INFO handled request 15 in 35 ms
WARN slow query on request 16 (1.2 s)
INFO handled request 17 in 37 ms
ERROR request 18 failed: upstream timeout after 3000 ms
INFO handled request 19 in 39 ms
TRACE handled request 20 in 40 ms
DEBUG handled request 21 in 41 ms
INFO handled request 22 in 42 ms
INFO handled request 23 in 43 ms
INFO handled request 24 in 44 ms
Code
<%- include('modules/ui/LogViewer', { lines: lines, searchMode: 'highlight', defaultQuery: 'timeout', defaultWrap: true }) %>

Live tail with a drop counter

Preview
severity
region
service
status
TRACE handled request 0 in 20 ms
DEBUG handled request 1 in 21 ms
INFO handled request 2 in 22 ms
INFO handled request 3 in 23 ms
INFO handled request 4 in 24 ms
INFO handled request 5 in 25 ms
WARN slow query on request 6 (1.2 s)
INFO handled request 7 in 27 ms
ERROR request 8 failed: upstream timeout after 3000 ms
INFO handled request 9 in 29 ms
TRACE handled request 10 in 30 ms
DEBUG handled request 11 in 31 ms
INFO handled request 12 in 32 ms
INFO handled request 13 in 33 ms
INFO handled request 14 in 34 ms
INFO handled request 15 in 35 ms
WARN slow query on request 16 (1.2 s)
INFO handled request 17 in 37 ms
ERROR request 18 failed: upstream timeout after 3000 ms
INFO handled request 19 in 39 ms
TRACE handled request 20 in 40 ms
DEBUG handled request 21 in 41 ms
INFO handled request 22 in 42 ms
INFO handled request 23 in 43 ms
INFO handled request 24 in 44 ms
Code
<%- include('modules/ui/LogViewer', { lines: initialLines, maxLines: 400, defaultFollow: true }) %>
<script>
  // The producer side of useLogStream: append, keep the newest maxLines, count the drops.
  const viewer = document.querySelector('[data-lv-root]');
  socket.onmessage = (e) => KuiLogViewer.push(viewer, JSON.parse(e.data), { dropped: 0 });
</script>
Source modules/ui/LogViewer.ejs