logbuffer

package
v0.13.3 Latest Latest
Warning

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

Go to latest
Published: May 9, 2026 License: GPL-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package logbuffer persists graywolf's slog records to a bounded circular buffer in a standalone SQLite database (graywolf-logs.db).

It is wired in cmd/graywolf/main.go as a slog.Handler that wraps the existing console TextHandler: every record continues to print to the console at the operator's selected level (INFO, or DEBUG with -debug), and is also persisted at DEBUG level so a later "graywolf flare" submission can attach recent history regardless of how the operator configured the console.

The DB lives in a separate file from the main configstore to avoid write contention on the main app DB; on Raspberry Pi / SD-card-rooted systems the file is placed on tmpfs to avoid SD-card wear.

Design: .context/2026-04-25-graywolf-flare-system-design.md

§ "Subsystem 1 — Circular Log Persistence".

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BackingDeviceFor

func BackingDeviceFor(p string) (string, error)

BackingDeviceFor exposes backingDeviceForPath under an exported name.

func IsRamdiskPath

func IsRamdiskPath(p string) bool

IsRamdiskPath reports whether p was placed under one of the tmpfs candidates ResolvePath tries (i.e. /run/graywolf or /dev/shm/graywolf). Used by cmd/graywolf to detect a "wanted ramdisk but fell back to disk" outcome and surface the spec-required WARN. Kept here so the candidate list stays the single source of truth.

func IsRaspberryPiHost

func IsRaspberryPiHost() bool

IsRaspberryPiHost is the production-default wrapper around isRaspberryPi that reads /sys/firmware/devicetree/base/model. Exposed so cmd/graywolf can drive the path picker without re-implementing the detection.

func IsSDCardDevice

func IsSDCardDevice(dev string) bool

IsSDCardDevice exposes isSDCardDevice under an exported name.

func ResolvePath

func ResolvePath(opts ResolveOptions) (string, error)

ResolvePath returns the absolute path where graywolf-logs.db should live. The returned directory is NOT guaranteed to exist — Open() creates it.

Types

type Config

type Config struct {
	RingSize         int
	MaintenanceEvery int
}

Config tunes the Handler.

RingSize is the maximum number of rows retained. <=0 disables persistence entirely (Handler still forwards to the inner handler).

MaintenanceEvery controls how often eviction runs (every Nth Handle call). 0 means "never trigger from Handle" (used by tests that drive eviction manually). Wired to 200 in production by cmd/graywolf/main.go.

type DB

type DB struct {
	Path string
	// contains filtered or unexported fields
}

DB is the standalone graywolf-logs.db handle. It deliberately exposes no application-level methods beyond Close — the handler reaches into gorm directly so we don't carry a duplicate insert API.

func Open

func Open(path string) (*DB, error)

Open opens (or creates) the log buffer database at path. The parent directory is created if missing; the SQLite file is chmod-ed 0600 since log content can include hostnames, paths, and other operator-private detail.

func (*DB) Close

func (d *DB) Close() error

Close releases the underlying connection.

type Handler

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

Handler is a slog.Handler that forwards every record to an inner handler (typically the console TextHandler) and tees it to a logbuffer DB. Capture is always at DEBUG regardless of the inner handler's threshold so a future flare submission has full detail.

func New

func New(inner slog.Handler, db *DB, cfg Config) *Handler

New returns a Handler that wraps inner and tees to db.

func (*Handler) Enabled

func (h *Handler) Enabled(_ context.Context, level slog.Level) bool

Enabled returns true for every level >= Debug. The inner handler is asked separately inside Handle so the console keeps its configured threshold.

func (*Handler) Handle

func (h *Handler) Handle(ctx context.Context, r slog.Record) error

Handle forwards the record to the inner handler (subject to the inner handler's own Enabled check) and persists it to the DB at DEBUG-and-above.

func (*Handler) WithAttrs

func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns a new Handler whose subsequent records carry attrs.

func (*Handler) WithGroup

func (h *Handler) WithGroup(name string) slog.Handler

WithGroup returns a new Handler scoped under the named group.

type ResolveOptions

type ResolveOptions struct {
	// ConfigDBPath is the path the operator gave for graywolf.db. Used as
	// the disk-backed fallback location (logs land in the same directory
	// under graywolf-logs.db).
	ConfigDBPath string

	// PreferRamdisk forces ramdisk preference even on non-SD systems.
	// Wired from --logbuffer-ramdisk.
	PreferRamdisk bool

	// IsRaspberryPi mirrors isRaspberryPi() — kept as a separate field so
	// callers can override for tests and so the structured form documents
	// the inputs explicitly.
	IsRaspberryPi bool

	// BackingIsSDCard is true when the directory holding the config DB is
	// backed by an mmcblk/mtdblock device.
	BackingIsSDCard bool

	// WritableProbe is invoked for each candidate ramdisk directory. The
	// first directory the probe accepts wins. In production this is
	// defaultWritableProbe (creates and removes a temp file).
	WritableProbe func(dir string) error
}

ResolveOptions are the inputs to the path picker. All fields are either CLI-flag-derived or detector outputs so the picker itself stays pure and testable.

Jump to

Keyboard shortcuts

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