iced-cube

Data

Log viewer

A live log that streams entries from threads or tasks, with level filters, search, follow, pause and copy, and a cap on how many lines it keeps.

use iced_cube::data::log_viewer::{self, Event, Level, LineId, MenuItem, Output, State, entry, log_viewer};
API reference
Live log: A simulated server writes lines through the log's channel, using futures-timer so it also runs in the browser. Scroll up to stop following, then jump back to the newest line.Live log: A simulated server writes lines through the log's channel, using futures-timer so it also runs in the browser. Scroll up to stop following, then jump back to the newest line.
Static preview
Live log. A simulated server writes lines through the log's channel, using futures-timer so it also runs in the browser. Scroll up to stop following, then jump back to the newest line.

Usage

A log viewer shows output from a running program as it happens. The app owns a log_viewer::State and routes the viewer’s events into it. log_viewer::subscription() owns a bounded channel and sends Event::Ready with its sender first; hand clones of the sender to threads or tasks and send entry(level, message) values through them. Entries arrive in batches, so a burst of lines costs one update rather than one per line.

The log keeps the newest 10,000 lines by default and drops the oldest after that, so memory stays bounded however long the program runs. Only the lines in view are built. It follows the newest line until you scroll up, then shows a button under the lines to jump back, with a count of the lines that arrived since. Pausing holds new lines back, bounded by the same limit, until you resume.

The level filters are a multiple-choice toggle group: each shows how many kept lines have its level, and is on while that level is shown. The search matches messages, ignoring the case of Latin letters, and marks every match. Typing moves to the nearest match at or after the highlighted line and scrolls it into view; with nothing highlighted it takes the newest match while following. The count beside the field reads “3 of 12” for the current match of all matches, “12 found” before one is current, and “None” when nothing matches, as in the JSON viewer. In the search field Enter or F3 moves to the next match and Shift+Enter or Shift+F3 to the previous, and F3 and Shift+F3 do the same anywhere in the log, wrapping at the ends. Ctrl+F in the field selects its text. Escape in the field clears the search, and a second Escape leaves the field. Long lines end in an ellipsis unless wrapping is on. Below 560 pixels the toolbar stacks and each message sits under its timestamp, level and target, so it keeps the full width.

Click, Shift and Ctrl select lines, as do Space and Shift with the arrows, and Ctrl+C or the copy button returns Output::Copy with them as plain text, one per line. The library never touches the clipboard itself: write the text with iced::clipboard::write or your own platform code. Ctrl+F returns Output::FocusSearch; answer it with log_viewer::focus_search(&state). Pause and wrap are toolbar buttons with no default shortcut; bind Action::TogglePause or Action::ToggleWrap in the keymap to add one.

.context_menu(&menu, on_event) gives every line a menu, keyed by its LineId, opened by a right-click, a press and hold or Shift+F10. The line it opened on carries the ring while the menu is open. log_viewer::menu() builds one that copies the line or its message and shows only the line’s level; turn the chosen entry into an event with MenuItem::event(id). A finger swipe scrolls the lines, and scrolling away from the newest line stops following.

The log resolves its keys while any part of it has focus, the search field included, which keeps the keys typing needs. Timestamps and levels sit in fixed columns so lines line up, and every part uses the font the app registers with theme::set_font.

Examples

Trace and debug lines are hidden and long lines wrap. The search marks every match, and Enter in the field, F3 or the arrows move between them.

Levels and search: Trace and debug lines are hidden and long lines wrap. The search marks every match, and Enter in the field, F3 or the arrows move between them.Levels and search: Trace and debug lines are hidden and long lines wrap. The search marks every match, and Enter in the field, F3 or the arrows move between them.
Static preview

Keyboard shortcuts

The default keymap with J and K added, and a context menu on every line. The log resolves keys while any part of it has focus, and copying hands the text to the app.

Keyboard shortcuts: The default keymap with J and K added, and a context menu on every line. The log resolves keys while any part of it has focus, and copying hands the text to the app.Keyboard shortcuts: The default keymap with J and K added, and a context menu on every line. The log resolves keys while any part of it has focus, and copying hands the text to the app.
Static preview

API

ItemDescription
State::new()An empty log that keeps 10,000 lines, shows every level and follows the newest line.
.with_limit(n) / .with_levels(levels) / .with_wrap(bool) / .with_search_id(id)The most lines kept, the levels shown, whether long lines wrap, and the search field's widget id when several logs share a screen.
entry(level, message)One line. Add .timestamp(text) and .target(text); the timestamp is shown as given, so the app picks the format.
state.update(Event)Handles arriving entries, presses, the search, filters, follow, pause, wrap, clear and the keyboard. Returns Output::Ready(sender) once the channel is open, Copy(text) for the clipboard and FocusSearch.
state.extend(entries)Appends entries directly, as the channel does. While paused they are held back.
log_viewer::subscription() / log_viewer::SenderThe channel entries arrive on. It sends Event::Ready(sender) first; producers send entries through clones of the sender, and they arrive in batches as Event::Received.
log_viewer::focus_search(&state)The task that focuses the search field, for answering Output::FocusSearch.
log_viewer::match_label(&state)The text beside the search field: "3 of 12" for the current match of all matches, "12 found" before one is current, or "None".
state.levels()The level filters as a multiple-choice toggle group, each labelled with its count.
state.entries() / state.visible() / state.entry(id)Every kept entry, the ids of the lines shown, and one entry by id.
state.count(level) / state.matches() / state.current_match()How many kept lines have a level, the lines matching the search, and the match the search last moved to with its position.
state.selected() / state.can_copy() / state.copy_text()The selected lines, whether there is anything to copy, and the text Event::CopySelection returns: the selection, or the highlighted line.
state.is_following() / state.is_paused() / state.pending() / state.unseen()Whether the log follows its newest line, whether it is paused, how many lines are held back, and how many arrived since it stopped following.
log_viewer(&state)Renders the toolbar and the lines. Everything renders disabled until .on_event is set.
.width(length) / .height(length)The log's size, toolbar included. It fills by default.
.toolbar(bool) / .placeholder(text) / .empty(text)Hides the toolbar, which leaves its actions on the keyboard, and sets the search placeholder and what shows with no lines.
.keymap(keymap)Replaces the default keymap the focused log resolves keys with.
.context_menu(&menu, on_event) / .context_menu_keymap(keymap)Gives every line a context menu keyed by its LineId, opened with a right-click, a long press or Shift+F10 on the highlighted line, and replaces the menu's keymap.
log_viewer::menu() / MenuItem::event(id)A ready-made menu (Copy line, Copy message, Show only this level), and the Event the chosen entry sends for the line it opened on.
log_viewer::default_keymap() / action.event(&state)The default shortcuts, and the Event a resolved Action sends. State::key_event does both.
log_viewer::level_colour(tokens, level) / line_style(tokens, level, current, Status)The colour of each level's tag, and a line's colours: list row colours, a tint on error lines and the search marks, stronger on the current match.

Keyboard

Default shortcuts. Every one can be changed or removed with a keymap; see Keyboard shortcuts.

KeysAction
ArrowDownNext Highlights the next line.
ArrowUpPrevious Highlights the previous line.
HomeFirst Highlights the oldest line.
EndLast Jumps to the newest line and follows new ones.
PageDownNextPage Moves the highlight down by a page of lines.
PageUpPreviousPage Moves the highlight up by a page of lines.
Shift+ArrowDownExtendNext Moves down and extends the selection.
Shift+ArrowUpExtendPrevious Moves up and extends the selection.
SpaceSelect Selects or deselects the highlighted line.
Ctrl+ASelectAll Selects every shown line.
Ctrl+CCopySelection Copies the selected lines, or the highlighted one.
Ctrl+FFocusSearch Focuses the search field.
F3NextMatch Moves to the next line matching the search.
Shift+F3PreviousMatch Moves to the previous line matching the search.
EscapeClearSearch Clears the search.
Ctrl+LClear Removes every line.
Enter / Shift+Enter, F3 / Shift+F3In the search field, moves to the next or previous match.
Ctrl+F (Cmd+F on macOS)In the search field, selects its text.
EscapeIn the search field, clears the text; a second Escape leaves the field.
Esc