Documentation
¶
Overview ¶
Package eventlog records and queries notification execution history.
Index ¶
- Constants
- Variables
- func Close()
- func DayCutoff(days int) time.Time
- func ExtractTimestamp(line string) (time.Time, bool)
- func FilterBlocksByDays(content string, days int) string
- func FilterBlocksByProfile(content string, profile string) (string, int)
- func KindString(k EntryKind) string
- func Log(action string, steps []config.Step, afk bool, vars tmpl.Vars, desktop *int)
- func LogCooldown(profile, action string, cooldownSeconds int)
- func LogCooldownRecord(profile, action string, cooldownSeconds int)
- func LogSilent(profile, action string)
- func LogSilentDisable()
- func LogSilentEnable(d time.Duration)
- func OpenDefault(storage string)
- func ReadContent() (string, error)
- func SetRetention(days int)
- func SplitBlocks(content string) []string
- func StepSummary(s config.Step, vars *tmpl.Vars) string
- type ActionKey
- type AggregatedData
- type Counts
- type DayGroup
- type DaySummary
- type Entry
- type EntryKind
- type FileStore
- func (f *FileStore) Clean(days int) (int, error)
- func (f *FileStore) Clear() error
- func (f *FileStore) Entries(days int) ([]Entry, error)
- func (f *FileStore) EntriesSince(cutoff time.Time) ([]Entry, error)
- func (f *FileStore) Log(action string, steps []config.Step, afk bool, vars tmpl.Vars, desktop *int) error
- func (f *FileStore) LogCooldown(profile, action string, seconds int) error
- func (f *FileStore) LogCooldownRecord(profile, action string, seconds int) error
- func (f *FileStore) LogSilent(profile, action string) error
- func (f *FileStore) LogSilentDisable() error
- func (f *FileStore) LogSilentEnable(d time.Duration) error
- func (f *FileStore) Path() string
- func (f *FileStore) ReadContent() (string, error)
- func (f *FileStore) RemoveProfile(name string) (int, error)
- func (f *FileStore) VoiceLines(days int) ([]VoiceLine, error)
- type HourProfile
- type HourlyData
- type SQLiteStore
- func (s *SQLiteStore) Clean(days int) (int, error)
- func (s *SQLiteStore) Clear() error
- func (s *SQLiteStore) Close() error
- func (s *SQLiteStore) Entries(days int) ([]Entry, error)
- func (s *SQLiteStore) EntriesSince(cutoff time.Time) ([]Entry, error)
- func (s *SQLiteStore) Log(action string, steps []config.Step, afk bool, vars tmpl.Vars, desktop *int) error
- func (s *SQLiteStore) LogCooldown(profile, action string, seconds int) error
- func (s *SQLiteStore) LogCooldownRecord(profile, action string, seconds int) error
- func (s *SQLiteStore) LogSilent(profile, action string) error
- func (s *SQLiteStore) LogSilentDisable() error
- func (s *SQLiteStore) LogSilentEnable(d time.Duration) error
- func (s *SQLiteStore) Path() string
- func (s *SQLiteStore) ReadContent() (string, error)
- func (s *SQLiteStore) RemoveProfile(name string) (int, error)
- func (s *SQLiteStore) VoiceLines(days int) ([]VoiceLine, error)
- type Store
- type TimeSpentData
- type TimeSpentProfile
- type VoiceLine
Constants ¶
const GapThreshold = 5 * time.Minute
GapThreshold is the maximum gap between consecutive entries that is still counted as active time in time-spent calculations.
Variables ¶
var LogPath = func() string { return filepath.Join(paths.DataDir(), paths.LogFileName) }
LogPath returns the log file location (~/.config/notify/notify.log).
This is a variable so tests can override it.
Functions ¶
func Close ¶ added in v0.2.31
func Close()
Close closes the Default store if it implements io.Closer.
func DayCutoff ¶ added in v0.2.29
DayCutoff returns midnight N days ago (inclusive) in the local timezone. For days=1 it returns today at midnight, for days=7 it returns 6 days ago, etc.
func ExtractTimestamp ¶ added in v0.2.17
ExtractTimestamp parses the RFC3339 timestamp at the start of a log line (everything before the first " " double-space separator). Returns the parsed time and true on success, or zero time and false on failure.
func FilterBlocksByDays ¶ added in v0.2.26
FilterBlocksByDays returns only log blocks whose timestamp falls within the last N calendar days. Each block is separated by a blank line.
func FilterBlocksByProfile ¶ added in v0.2.28
FilterBlocksByProfile removes all log blocks belonging to the named profile. Returns the filtered content and the number of removed blocks.
func KindString ¶ added in v0.2.12
KindString returns a human-readable string for an EntryKind.
func Log ¶
Log appends to the log file a summary line followed by one detail line per step. Errors are printed to stderr but never returned — logging is best-effort.
func LogCooldown ¶ added in v0.2.3
LogCooldown appends a single line noting that an invocation was skipped due to cooldown. Best-effort, same as Log.
func LogCooldownRecord ¶ added in v0.2.3
LogCooldownRecord appends a single line noting that cooldown state was updated for an action. Best-effort, same as Log.
func LogSilent ¶ added in v0.2.7
func LogSilent(profile, action string)
LogSilent appends a single line noting that an invocation was skipped due to silent mode. Best-effort, same as Log.
func LogSilentDisable ¶ added in v0.2.7
func LogSilentDisable()
LogSilentDisable appends a single line noting that silent mode was disabled. Best-effort, same as Log.
func LogSilentEnable ¶ added in v0.2.7
LogSilentEnable appends a single line noting that silent mode was enabled. Best-effort, same as Log.
func OpenDefault ¶ added in v0.2.31
func OpenDefault(storage string)
OpenDefault initializes Default with the configured storage backend. Pass "file" for the flat-file backend, or "" / "sqlite" for SQLite. If SQLite fails to open, falls back to FileStore with a warning.
func ReadContent ¶ added in v0.2.31
ReadContent returns the raw log file content.
func SetRetention ¶ added in v0.2.34
func SetRetention(days int)
SetRetention configures automatic log cleanup. When days > 0, old entries are pruned after every write operation.
func SplitBlocks ¶ added in v0.2.29
SplitBlocks splits log content on blank lines, trims whitespace from each block, and returns only non-empty blocks.
func StepSummary ¶ added in v0.2.17
StepSummary returns a human-readable description of what a step does. When vars is non-nil, template variables are expanded (logging mode). When vars is nil, raw values are shown (dry-run mode). When/volume suffixes are always appended if present.
Types ¶
type ActionKey ¶ added in v0.2.21
type ActionKey struct{ Profile, Action string }
ActionKey identifies a profile/action pair for aggregation.
type AggregatedData ¶ added in v0.2.21
type AggregatedData struct {
PerAction map[ActionKey]*Counts
PerProfile map[string]*Counts
ProfileOrder []string
ActionsByProfile map[string][]ActionKey
HasSkipped bool
}
AggregatedData holds the result of aggregating day groups into per-action and per-profile counts.
func AggregateGroups ¶ added in v0.2.21
func AggregateGroups(groups []DayGroup) AggregatedData
AggregateGroups collects per-action and per-profile counts from day groups.
type Counts ¶ added in v0.2.21
type Counts struct{ Exec, Skip int }
Counts holds execution and skip totals for a profile or action.
type DayGroup ¶ added in v0.2.11
type DayGroup struct {
Date time.Time
Summaries []DaySummary
}
DayGroup holds all summaries for a single calendar day.
func SummarizeByDay ¶ added in v0.2.11
SummarizeByDay filters entries to the last N calendar days (local time), groups by date + profile/action, and returns day groups sorted descending with summaries sorted alphabetically. Pass days=0 to include all entries.
type DaySummary ¶ added in v0.2.11
DaySummary holds execution and skip counts for one profile/action pair.
type Entry ¶ added in v0.2.11
type Entry struct {
Time time.Time
Profile string
Action string
Kind EntryKind
ClaudeHook string // from claude_hook= field (optional)
ClaudeMessage string // from claude_message= field (optional)
}
Entry is a single parsed log entry.
func Entries ¶ added in v0.2.31
Entries returns parsed log entries filtered to the last N days (0 = all).
func EntriesSince ¶ added in v0.2.31
EntriesSince returns parsed log entries after the given cutoff time.
func ParseEntries ¶ added in v0.2.11
ParseEntries splits log content on blank lines and parses summary lines into entries. Each block may contain multiple summary lines (e.g. a cooldown=recorded line followed by an execution line) plus step detail lines (indented with "step["). Step detail lines are skipped. Each summary line produces one Entry. Malformed lines are silently skipped.
type EntryKind ¶ added in v0.2.11
type EntryKind int
EntryKind classifies a log entry.
const ( KindExecution EntryKind = iota // A notification pipeline was fully executed KindCooldown // Invocation was skipped due to cooldown KindSilent // Invocation was suppressed by silent mode KindOther // Informational record (not counted in summaries) )
Entry classification constants. KindExecution and KindCooldown/KindSilent represent "real" events that appear in history summaries. KindOther covers informational records (cooldown=recorded, silent=enabled/disabled) that are stored for audit but excluded from aggregation counts.
type FileStore ¶ added in v0.2.31
type FileStore struct {
// contains filtered or unexported fields
}
FileStore implements Store using a flat log file. Note: FileStore has no file locking. Concurrent writes from multiple processes rely on OS-level O_APPEND atomicity. Use SQLiteStore (the default) for guaranteed concurrent safety.
func NewFileStore ¶ added in v0.2.31
NewFileStore returns a FileStore that reads and writes the given log file.
func (*FileStore) Clean ¶ added in v0.2.31
Clean removes log blocks older than N calendar days. It works by splitting the file on double-newline boundaries (SplitBlocks), filtering blocks by their first-line timestamp, counting the difference between original and kept block counts, and rewriting the file with only recent blocks.
func (*FileStore) Clear ¶ added in v0.2.31
Clear deletes the entire log file. Silently succeeds if already absent.
func (*FileStore) Entries ¶ added in v0.2.31
Entries reads the entire log file, parses it into entries, and optionally filters to the last N calendar days. Pass days=0 to return all entries.
func (*FileStore) EntriesSince ¶ added in v0.2.31
EntriesSince returns all entries with timestamps at or after cutoff.
func (*FileStore) Log ¶ added in v0.2.31
func (f *FileStore) Log(action string, steps []config.Step, afk bool, vars tmpl.Vars, desktop *int) error
Log appends an execution event to the log file: a summary line with profile, action, step types, and metadata, followed by one detail line per step, terminated by a blank line to separate blocks.
func (*FileStore) LogCooldown ¶ added in v0.2.31
LogCooldown records that an invocation was skipped because the action's cooldown period had not yet elapsed. Ends with "\n\n" (blank line) so this event forms its own block in SplitBlocks.
func (*FileStore) LogCooldownRecord ¶ added in v0.2.31
LogCooldownRecord records that a cooldown timer was started/updated for an action. Unlike LogCooldown, this writes a single "\n" (not "\n\n"), so the line merges into the same SplitBlocks block as the execution entry that follows it. This is intentional: cooldown=recorded events are grouped with the execution they precede, keeping related log lines together.
func (*FileStore) LogSilent ¶ added in v0.2.31
LogSilent records that an invocation was suppressed by silent mode.
func (*FileStore) LogSilentDisable ¶ added in v0.2.31
LogSilentDisable records that silent mode was turned off.
func (*FileStore) LogSilentEnable ¶ added in v0.2.31
LogSilentEnable records that silent mode was turned on for duration d.
func (*FileStore) ReadContent ¶ added in v0.2.31
ReadContent returns the raw text content of the log file. Returns "" with no error if the file does not exist.
func (*FileStore) RemoveProfile ¶ added in v0.2.31
RemoveProfile deletes all log blocks belonging to the named profile. Returns the number of blocks removed.
type HourProfile ¶ added in v0.2.21
HourProfile is the key for per-cell hourly data.
type HourlyData ¶ added in v0.2.21
type HourlyData struct {
Profiles []string
PerCell map[HourProfile]int
PerHour map[int]int
ProfileTotals []int // parallel to Profiles
MinHour int
MaxHour int
GrandTotal int
}
HourlyData holds computed hourly breakdown data for a single day.
func ComputeHourly ¶ added in v0.2.21
ComputeHourly computes per-hour activity breakdown for a target date. Only entries matching targetDate in the given location are included. Entries with KindOther are excluded.
type SQLiteStore ¶ added in v0.2.31
type SQLiteStore struct {
// contains filtered or unexported fields
}
SQLiteStore implements Store using a SQLite database.
func NewSQLiteStore ¶ added in v0.2.31
func NewSQLiteStore(path string) (*SQLiteStore, error)
NewSQLiteStore opens (or creates) a SQLite database at path, creates tables and indexes, and performs one-time migration from notify.log if it exists in the same directory.
func (*SQLiteStore) Clean ¶ added in v0.2.31
func (s *SQLiteStore) Clean(days int) (int, error)
Clean deletes events older than N calendar days. Returns the number of deleted rows. Associated step_details rows are automatically removed via ON DELETE CASCADE on the event_id foreign key.
func (*SQLiteStore) Clear ¶ added in v0.2.31
func (s *SQLiteStore) Clear() error
Clear deletes all events. Step_details rows are automatically removed via ON DELETE CASCADE when their parent events are deleted.
func (*SQLiteStore) Close ¶ added in v0.2.31
func (s *SQLiteStore) Close() error
Close closes the database connection.
func (*SQLiteStore) Entries ¶ added in v0.2.31
func (s *SQLiteStore) Entries(days int) ([]Entry, error)
Entries returns parsed execution/cooldown/silent entries, optionally filtered to the last N calendar days. Pass days=0 for all entries.
func (*SQLiteStore) EntriesSince ¶ added in v0.2.31
func (s *SQLiteStore) EntriesSince(cutoff time.Time) ([]Entry, error)
EntriesSince returns entries with timestamps at or after cutoff. Same profile/action filter as Entries for consistency.
func (*SQLiteStore) Log ¶ added in v0.2.31
func (s *SQLiteStore) Log(action string, steps []config.Step, afk bool, vars tmpl.Vars, desktop *int) error
Log inserts an execution event into the events table, then inserts one step_details row per step in the same transaction. For voice-capable step types (say, discord_voice, telegram_audio, telegram_voice), the expanded text is stored in voice_text for later frequency queries.
func (*SQLiteStore) LogCooldown ¶ added in v0.2.31
func (s *SQLiteStore) LogCooldown(profile, action string, seconds int) error
LogCooldown records that an invocation was skipped due to cooldown. Uses KindCooldown so the event appears in Entries/EntriesSince queries (which filter on profile != ” AND action != ”).
func (*SQLiteStore) LogCooldownRecord ¶ added in v0.2.31
func (s *SQLiteStore) LogCooldownRecord(profile, action string, seconds int) error
LogCooldownRecord records that a cooldown timer was started/updated. Uses KindOther (not KindCooldown) so these events are excluded from history queries -- Entries/EntriesSince filter on profile != ” AND action != ”, but KindOther entries with profile/action set still pass that filter. The key difference is that KindOther events are skipped by SummarizeByDay and other aggregation functions, preventing cooldown-recorded events from inflating execution or skip counts.
func (*SQLiteStore) LogSilent ¶ added in v0.2.31
func (s *SQLiteStore) LogSilent(profile, action string) error
LogSilent records that an invocation was suppressed by silent mode.
func (*SQLiteStore) LogSilentDisable ¶ added in v0.2.31
func (s *SQLiteStore) LogSilentDisable() error
LogSilentDisable records that silent mode was turned off.
func (*SQLiteStore) LogSilentEnable ¶ added in v0.2.31
func (s *SQLiteStore) LogSilentEnable(d time.Duration) error
LogSilentEnable records that silent mode was turned on for duration d. No profile/action is set, so this event is excluded from Entries queries.
func (*SQLiteStore) Path ¶ added in v0.2.31
func (s *SQLiteStore) Path() string
Path returns the filesystem path of the SQLite database file.
func (*SQLiteStore) ReadContent ¶ added in v0.2.31
func (s *SQLiteStore) ReadContent() (string, error)
ReadContent reconstructs the flat-file log format from SQL rows. This provides backward compatibility with code that expects text-based log parsing (e.g. historyExport, ParseVoiceLines in FileStore mode). The output matches what FileStore.Log/LogCooldown/etc. would have written.
func (*SQLiteStore) RemoveProfile ¶ added in v0.2.31
func (s *SQLiteStore) RemoveProfile(name string) (int, error)
RemoveProfile deletes all events for the named profile. Step details are cascade-deleted. Returns the number of removed event rows.
func (*SQLiteStore) VoiceLines ¶ added in v0.2.31
func (s *SQLiteStore) VoiceLines(days int) ([]VoiceLine, error)
VoiceLines queries the step_details table for distinct TTS texts and their usage counts. Uses the partial index on voice_text (WHERE voice_text IS NOT NULL) for efficient lookups. Pass days=0 for all history.
type Store ¶ added in v0.2.31
type Store interface {
// Write — returns error for correctness; FileStore prints to stderr (best-effort).
Log(action string, steps []config.Step, afk bool, vars tmpl.Vars, desktop *int) error
LogCooldown(profile, action string, seconds int) error
LogCooldownRecord(profile, action string, seconds int) error
LogSilent(profile, action string) error
LogSilentEnable(d time.Duration) error
LogSilentDisable() error
// Read
Entries(days int) ([]Entry, error) // parsed entries, 0 = all
EntriesSince(cutoff time.Time) ([]Entry, error) // entries after cutoff
VoiceLines(days int) ([]VoiceLine, error) // TTS text frequency
ReadContent() (string, error) // raw log text
// Maintenance
Clean(days int) (int, error) // remove old entries, return removed count
RemoveProfile(name string) (int, error) // remove profile entries, return removed count
Clear() error // delete all data
// Metadata
Path() string
}
Store abstracts event log storage. Implementations: FileStore (flat log file) and SQLiteStore (indexed SQL queries). Selected via config "storage" option.
var Default Store
Default is the package-level Store used by the convenience functions below. Set by OpenDefault() at program startup, or overridden in tests.
type TimeSpentData ¶ added in v0.2.21
type TimeSpentData struct {
Profiles []TimeSpentProfile
Total int
}
TimeSpentData holds approximate time spent across all profiles.
func ComputeTimeSpent ¶ added in v0.2.21
ComputeTimeSpent estimates approximate time spent per profile on a target date. It walks consecutive entry timestamps per profile; gaps of 5 minutes or less are counted as active time.
type TimeSpentProfile ¶ added in v0.2.21
TimeSpentProfile holds approximate time spent for one profile.
type VoiceLine ¶ added in v0.2.23
VoiceLine holds a unique voice step text and its usage count.
func ParseVoiceLines ¶ added in v0.2.23
ParseVoiceLines scans log content for TTS step detail lines and returns unique texts sorted by frequency (descending), then alphabetically.
func VoiceLines ¶ added in v0.2.31
VoiceLines returns TTS text frequency data, optionally filtered to the last N days (0 = all).