Eventlog¶
pkg/eventlog shows events and lines read in order from a source too large to
hold: an AWX job's events, an Elasticsearch index, a run's logs. It's
LogView's counterpart for data fetched in pages rather than
streamed whole.
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 draws as a block; an item
with no lines draws as a dim · no output. The cursor moves item by item.
There's no sort: the order is the timeline.
Usage¶
Bind it to a source with pkg/remote:
s.log = remote.NewEventlog(t.Eventlog(), remote.Seekable[eventlog.Item]{
Page: s.page, // func(ctx, remote.Window) ([]eventlog.Item, total int, error)
Find: s.find, // optional: search past what's loaded
})
func (s *Screen) Init() tea.Cmd { return tea.Batch(s.log.Init(), s.log.SetGrowing(s.jobRunning)) }
func (s *Screen) Update(msg tea.Msg) (screen.Screen, tea.Cmd) {
if s.log.IsActivate(msg) {
if it, ok := s.log.Selected(); ok {
return s, screen.Push(newEventDetail(it.Data, s.t))
}
}
return s, s.log.Update(msg)
}
func (s *Screen) SetTheme(t theme.Theme) { s.log.Restyle(t.Eventlog()) }
Set Filterable and Searchable on the options to enable the two fields.
Seekable and Anchored¶
| Seekable | Anchored | |
|---|---|---|
| Data | item N fetchable, with a total | walked from an anchor, no total |
| Options | default | Anchored: true |
| Feed | SetPage(items, offset, total, answered): adjacent pages merge, a far page replaces |
Append / Prepend(items, answered): grown at either edge |
| Gutter | position (or Item.Mark) |
Item.Mark only |
| Source | source.Model with MaxHeld |
source.Anchored |
Either way the eventlog holds at most MaxItems, trimming the end furthest
from the viewport.
Item¶
| Field | Meaning |
|---|---|
Key |
Identity across fetches; for anchored data, its cursor. |
Lines |
What it draws as, oldest first. None draws · no output. |
Data |
Carried to ActivatedMsg for an inspector. |
Hole |
A position the source has no item for yet (an event saved out of order). |
Mark |
Gutter label: a timestamp, id or counter, always the source's own. Leave empty if the line text already has the time. |
Options¶
| Field | Type | Default | Meaning |
|---|---|---|---|
Title |
string |
"events" |
Border title. |
Anchored |
bool |
false |
Hold a span grown with Append/Prepend instead of offset pages. |
Filterable |
bool |
false |
A filter (f) that narrows the query on the server. |
Searchable |
bool |
false |
Search (/) that jumps to matches. |
MaxItems |
int |
5000 | Resident cap. |
Placeholder |
string |
· |
Drawn for items not yet fetched. |
NoGutter |
bool |
false |
Hide the position/mark gutter. |
NewStyle, NewFor |
theme, 2s | Briefly highlight items that just loaded beside ones already on screen. Negative NewFor disables. |
|
MatchStyle, SelectedStyle, CellStyle, GutterStyle |
lipgloss.Style |
theme | |
Filter |
filter.Options |
theme | Styles both the filter and search fields. |
Keys |
eventlog.Keys |
DefaultKeys() |
Key bindings. |
| pane pass-throughs | theme | See Components. |
Keys¶
| Key | Binding field | Action |
|---|---|---|
↑/k, ↓/j |
Up, Down |
previous / next item |
g |
Top |
first item |
G |
Bottom |
newest item, and follow |
ctrl+u, ctrl+d |
HalfUp, HalfDown |
half a page |
enter |
Open |
activate the item |
f |
Filter |
filter (narrows the query) |
/ |
Search |
search (jumps; highlights resident matches as you type) |
n, N |
NextMatch, PrevMatch |
next / previous match, past what's loaded via Find |
←/h, →/l, 0, $ |
Pane.* |
horizontal scroll |
Search jumps, filter narrows¶
They're separate controls on purpose. The filter is part of the query: it
returns fewer items, and committing it emits QueryChangedMsg. Search
moves the view to the next match and keeps the context around it. n/N
step through resident matches, then emit FindMsg for the source to answer
(Found(ok, at) for seekable data, FoundAt(ok, key) for anchored). A hit
lands once its item is loaded.
Following growing data¶
SetGrowing(true) says items are still arriving at the newest end. While the
view is on the newest item it follows; scroll away and new items are counted
on the border (↓ 42 new) instead; G returns. Before the first answer,
SetFollow(false) makes the view open at the first item, which is where to
start reading a finished job.
Slow sources¶
Shared with Table: items answering an older query stay
on screen dimmed, the border names what they answer and what's loading,
Loading shows only before the first answer, and a failure reads ✗ failed.
Methods¶
| Method | Does |
|---|---|
SetPage, Append, Prepend, Reanchor, SetMore, Edges |
Feed data (see above). |
Selected() (Item, bool), Items(), Cursor(), SetCursor(i) |
Read and move. |
SetGrowing, SetFollow, Following(), SetNew(n, more) |
Follow. |
Value(), SetValue(s), Query() |
Filter. |
Term(), SetTerm(s), SetMatchTotal(n), Found, FoundAt |
Search. |
SetFailed(answer), Stale(), Failed(), Answered(), Committed() |
Remote state. |
Focus, Blur, FocusFilter, FocusSearch, BlurFilter, IsCapturingKeys, IsActivate |
Focus and input. |
Messages¶
| Message | When |
|---|---|
eventlog.ActivatedMsg{Key, Data, Token} |
enter or double-click on an item |
eventlog.QueryChangedMsg{Raw, Terms} |
a filter was committed |
eventlog.FindMsg{Term, Newer, From, FromKey, Token} |
n/N ran past resident items |
eventlog.ViewportChangedMsg{…} |
what's on screen and what's held; feed it to the source |
pkg/remote handles all of these for you.
State¶
State() / Restore(st) carry items, query, failure, cursor, scroll, follow,
growth, filter and search. With pkg/remote, use Restyle.
See examples/patterns/eventlog (seekable, growing),
examples/patterns/anchored (anchored) and the
remote data design note.