eventlog

package
v0.35.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package eventlog shows Events and Lines read in order from a remote source too large to hold: an AWX job's events, an Elasticsearch index, a Prefect run's logs. It is pkg/logview's counterpart for data that is fetched in pages rather than streamed — logview stays the component for a stream held whole (CLAUDE.md rule 34).

The item is the unit. An Item has a Key, the Lines it draws as, and optional Data for an inspector: a multi-line event is drawn as a block, a 0-line item draws as a dim "· no output" line — it still happened, and may carry fields worth opening — and the cursor moves item by item. There is no sort — the order is the timeline.

Two kinds of source, one component:

  • Seekable data (item N fetchable, with a total) arrives through SetPage at logical offsets. Adjacent pages merge into one contiguous range; a far jump replaces it. Drive it with source.Model and Options.MaxHeld.
  • Anchored data (walked from an anchor, no total) is a Span: New with Options.Anchored, then Append and Prepend. Items are keyed by their cursors, and Edges gives the cursors to extend from. Drive it with source.Anchored.

Either way it holds at most Options.MaxItems, trimming the end furthest from the viewport, and reports what it holds in ViewportChangedMsg so the source can mirror it.

It shares its remote machinery with pkg/table: items that answer a query other than the committed one stay on screen dimmed, the border names what they answer and what is loading, and nothing blanks after the first answer. On top of that:

  • Follow keeps the view on the newest item while data is Growing. Move away and new items are counted instead ("↓ 42 new"); G returns.
  • Search jumps. "/" highlights resident items as you type; n/N jump among them, and past what is held emit FindMsg for the source to answer. The filter narrows the query instead (QueryChangedMsg) — they are separate controls.
  • Enter or a double click emits ActivatedMsg with the item's Key and Data, for the screen to open in an inspector.

Index

Constants

View Source
const DefaultMaxItems = 5000

DefaultMaxItems is the resident cap when Options.MaxItems is zero.

Variables

This section is empty.

Functions

This section is empty.

Types

type ActivatedMsg

type ActivatedMsg struct {
	Key   string
	Data  any
	Token focus.Token
}

ActivatedMsg reports enter or a double click on an item.

type Answer

type Answer = remoteview.Answer

Answer names the query a set of items answers. See table.Answer.

type FindMsg

type FindMsg struct {
	Term  string
	Newer bool
	// From is the logical index to search beyond (Seekable). Anchored
	// sources start from the edge in the requested direction.
	From int
	// FromKey is the key of the item at From — what an API that searches
	// by its own ids (AWX's counter__gt) needs, since positions stop
	// matching ids once a filter is applied.
	FromKey string
	Token   focus.Token
}

FindMsg asks for the next match beyond what is held — n or N ran out of resident items. Hand it to the source's Find; answer with Found.

type Item

type Item struct {
	// Key identifies the item across fetches — for Anchored data, its
	// cursor. Merges skip keys already held.
	Key string
	// Lines is what the item draws as, oldest first. With none, the item
	// draws as a dim "· no output" line.
	Lines []string
	// Data is carried to ActivatedMsg for the screen's inspector.
	Data any
	// Hole marks a position the source has no item for yet (an AWX event
	// saved out of order). It draws as a placeholder and is not resident.
	Hole bool
	// Mark labels the item in the gutter: its timestamp, id or counter —
	// what a reader would quote to find it again. Without one, Seekable
	// items show their position; Anchored items, which have none, show
	// nothing.
	//
	// A timestamp here is always the source's own — Elasticsearch's
	// @timestamp, the kubelet's line time — never when the client fetched
	// it. When the line's text already carries the time the application
	// wrote, leave Mark empty rather than show two times for one event.
	Mark string
}

Item is one entry in the timeline: an event or a line.

type Keys

type Keys struct {
	Up, Down, Top, Bottom, HalfUp, HalfDown key.Binding
	Open                                    key.Binding
	Filter, Search, NextMatch, PrevMatch    key.Binding
	Pane                                    pane.Keys
}

Keys is the eventlog's keymap. Horizontal scroll lives on Pane.

func DefaultKeys

func DefaultKeys() Keys

DefaultKeys returns the eventlog's stock keymap.

type Model

type Model struct {
	// contains filtered or unexported fields
}

Model is the eventlog. Embed by value; mutate through the setters.

func New

func New(opts Options) Model

New constructs an eventlog.

func (Model) Answered

func (m Model) Answered() (Answer, bool)

Answered returns the query the items answer.

func (*Model) Append

func (m *Model) Append(items []Item, answered Answer)

Append adds items at the newer edge of a span, oldest first, merged by key: known keys are skipped and a late item lands where the page puts it.

func (*Model) Blur

func (m *Model) Blur()

Blur releases the keyboard, clearing both input fields.

func (*Model) BlurFilter

func (m *Model) BlurFilter()

BlurFilter returns input from either field to the body.

func (Model) Committed

func (m Model) Committed() Answer

Committed returns the query the source was last asked for.

func (Model) Cursor

func (m Model) Cursor() int

Cursor returns the cursor's logical index.

func (Model) Edges

func (m Model) Edges() (older, newer string)

Edges returns the cursors of the oldest and newest items held.

func (Model) Failed

func (m Model) Failed() bool

Failed reports whether the committed query's fetch failed.

func (*Model) Focus

func (m *Model) Focus() tea.Cmd

Focus gives the eventlog the keyboard.

func (*Model) FocusFilter

func (m *Model) FocusFilter() tea.Cmd

FocusFilter moves input to the filter.

func (*Model) FocusSearch

func (m *Model) FocusSearch() tea.Cmd

FocusSearch moves input to the search field.

func (Model) FocusToken

func (m Model) FocusToken() focus.Token

FocusToken returns the eventlog's focus identity.

func (Model) Focused

func (m Model) Focused() bool

Focused reports whether the eventlog or one of its fields has input.

func (Model) Following

func (m Model) Following() bool

Following reports whether the view is on the newest item.

func (*Model) Found

func (m *Model) Found(ok bool, at int)

Found answers a FindMsg for Seekable data: the match is at logical index at, or there is none when ok is false. The cursor goes there and the source fetches around it.

func (*Model) FoundAt

func (m *Model) FoundAt(ok bool, k string)

FoundAt answers a FindMsg for Anchored data. Re-anchor the source at the match's cursor; the cursor lands on the item keyed k when it arrives.

func (Model) Help

func (m Model) Help() []key.Binding

Help returns the bindings the eventlog currently responds to.

func (Model) HelpSections

func (m Model) HelpSections() []help.Section

HelpSections groups the bindings by what they do (rule 10).

func (Model) Init

func (m Model) Init() tea.Cmd

Init satisfies tea.Model.

func (Model) IsActivate

func (m Model) IsActivate(msg tea.Msg) bool

IsActivate reports whether msg opens the selection: enter, or this eventlog's own ActivatedMsg.

func (Model) IsCapturingKeys

func (m Model) IsCapturingKeys() bool

IsCapturingKeys reports whether a field is swallowing printable keys.

func (Model) Items

func (m Model) Items() (start int, items []Item)

Items returns the resident items, oldest first, with where they start.

func (Model) Loading

func (m Model) Loading() bool

Loading reports whether the body shows its Loading spinner.

func (*Model) Prepend

func (m *Model) Prepend(items []Item, answered Answer)

Prepend adds items at the older edge of a span, oldest first.

func (Model) Query

func (m Model) Query() QueryChangedMsg

Query returns the committed filter as a QueryChangedMsg, for the first fetch.

func (*Model) Reanchor

func (m *Model) Reanchor()

Reanchor says the source is re-anchoring (source.Anchored.SetAnchor): the next page replaces the span instead of extending it. What is on screen stays until then, so a jump to a search hit never blanks.

func (*Model) Restore

func (m *Model) Restore(s State)

Restore puts s back onto an eventlog built with the same Anchored setting. Items, query and failure come back as they were; the new Options keep the say over everything they set.

func (Model) Selected

func (m Model) Selected() (Item, bool)

Selected returns the item under the cursor, and false when it isn't resident.

func (*Model) SetCursor

func (m *Model) SetCursor(i int)

SetCursor moves the cursor, leaving follow unless it lands on the newest.

func (*Model) SetFailed

func (m *Model) SetFailed(q Answer)

SetFailed tells the eventlog the fetch for q failed. It takes effect for the committed query only. While following, a failure is a failed poll and the border says so until the next success.

func (*Model) SetFollow

func (m *Model) SetFollow(b bool)

SetFollow pins the view to the newest item, or releases it. Before the first answer it decides where that answer lands: following (the default) lands on the newest item, not following on the first — the place to start reading a job that has already finished.

func (*Model) SetGrowing

func (m *Model) SetGrowing(b bool)

SetGrowing says whether items are still arriving at the newest end.

func (*Model) SetMatchTotal

func (m *Model) SetMatchTotal(n int)

SetMatchTotal supplies an exact match count from a source that can count; -1 clears it.

func (*Model) SetMore

func (m *Model) SetMore(older, newer bool)

SetMore sets whether each edge of a span has more beyond it — from the source after each page.

func (*Model) SetNew

func (m *Model) SetNew(n int, more bool)

SetNew reports what a probe found while the user is not following: n items newer than those held, and whether there are more than that.

func (*Model) SetPage

func (m *Model) SetPage(items []Item, offset, total int, answered Answer)

SetPage installs Seekable items at logical offset of a set total long, answering the query named by answered. A page touching what is held extends it; a far one replaces it. When the committed query's first answer lands, the cursor goes to its anchor: the newest item while following, else the top.

func (*Model) SetRect

func (m *Model) SetRect(r geom.Rect)

SetRect places the eventlog.

func (*Model) SetTerm

func (m *Model) SetTerm(s string)

SetTerm restores the search term.

func (*Model) SetTitle

func (m *Model) SetTitle(s string)

SetTitle sets the label on the border; while stale or loading an edge, a suffix follows it.

func (*Model) SetValue

func (m *Model) SetValue(s string)

SetValue restores the filter text silently, as a SetTheme rebuild does.

func (Model) Stale

func (m Model) Stale() bool

Stale reports whether the items answer a query other than the committed one. Stale items are real records of the previous query.

func (Model) State

func (m Model) State() State

State captures the eventlog's state. See State.

func (Model) Term

func (m Model) Term() string

Term returns the search term.

func (Model) Title

func (m Model) Title() string

Title returns the label alone.

func (Model) Update

func (m Model) Update(msg tea.Msg) (Model, tea.Cmd)

Update handles keys, mouse and the eventlog's own timers.

func (Model) Value

func (m Model) Value() string

Value returns the filter text.

func (Model) View

func (m Model) View() string

View renders the eventlog.

type Options

type Options struct {
	Width, Height int
	// Title labels the pane's border. Defaults to "events".
	Title string
	// Anchored makes the eventlog hold a span of Anchored data (Append /
	// Prepend) rather than a range at logical offsets (SetPage).
	Anchored bool
	// Filterable adds a filter that narrows the query (f by default).
	Filterable bool
	// Searchable adds search (/ by default), which jumps to matches.
	Searchable bool
	// MaxItems caps what is resident. Zero means DefaultMaxItems.
	MaxItems int
	// Placeholder is drawn for an item not yet fetched. Defaults to the
	// glyph set's placeholder.
	Placeholder string

	MatchStyle    lipgloss.Style
	SelectedStyle lipgloss.Style
	CellStyle     lipgloss.Style
	// GutterStyle draws the gutter of positions or marks down the left.
	GutterStyle lipgloss.Style
	// NoGutter hides the gutter. It is on by default: in a long timeline
	// the reader needs somewhere fixed to measure the cursor against.
	NoGutter bool
	// NewStyle draws the numbers of items that just loaded beside ones
	// already on screen — a page reached by scrolling or by a search, or
	// new items of Growing data — so the reader can tell what came in from
	// what was there. A load that replaces everything marks nothing.
	NewStyle lipgloss.Style
	// NewFor is how long loaded items stay marked. Zero means 2s;
	// negative never marks.
	NewFor time.Duration

	ActiveColor    lipgloss.TerminalColor
	InactiveColor  lipgloss.TerminalColor
	ActiveBorder   lipgloss.Border
	InactiveBorder lipgloss.Border
	Glyphs         glyph.Set
	SlotBrackets   pane.SlotBracketStyle
	HScrollbar     bool
	SpinnerStyle   lipgloss.Style
	LoadingLabel   string

	// Filter styles both the filter and the search field.
	Filter filter.Options
	Keys   Keys
}

Options configures an eventlog. Start from theme.Eventlog().

type QueryChangedMsg

type QueryChangedMsg struct {
	Raw   string
	Terms []query.Term
}

QueryChangedMsg reports a committed filter: enter, esc or blur, never per keystroke. Hand it to the source's SetQuery.

type State

type State struct {
	// contains filtered or unexported fields
}

State is what the source and the user did to an eventlog — the items it holds (a range or a span), the query they answer and whether it failed, the cursor and scroll, follow and growth, the filter and search — held across a rebuild. An eventlog built from new Options (a theme swap, rule 4) takes it back with Restore:

st := s.log.State()
s.log = eventlog.New(opts)
s.log.Restore(st)

A search or a hit still on its way is not carried: the rebuild answers neither, and a press after it asks again. A re-anchor waiting for its page is, so the page still replaces the span.

type ViewportChangedMsg

type ViewportChangedMsg struct {
	FirstVisible, LastVisible int
	HeldStart, HeldCount      int
	// ToOlder and ToNewer count resident items between the viewport and
	// each edge of what is held.
	ToOlder, ToNewer int
}

ViewportChangedMsg reports what is on screen and what is held. Feed the visible range to source.Model.Viewport and the held range to SetHeld — or, for a span, ToOlder/ToNewer to source.Anchored.Viewport.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL