tail

package
v0.0.9 Latest Latest
Warning

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

Go to latest
Published: Aug 23, 2026 License: AGPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package tail follows log files the way the spec demands (SPEC §5.1): file identity is (device, inode), never the path; rotation hands over to the successor only after the old file is drained; a size below the current offset means truncation and resets it; and every line carries the position to resume from, so the caller can persist it and re-read nothing after a restart.

Reading is poll-driven: Poll is synchronous and cheap when nothing changed, and Follow wraps it in a ticker loop. No inotify — polling behaves identically on every filesystem and is invisible at our intervals.

Index

Constants

View Source
const DefaultMaxLine = 256 * 1024

DefaultMaxLine bounds a single line. Log lines are attacker-controlled input and must be bounded in size (SPEC §9); anything longer is emitted truncated to this many bytes.

Variables

This section is empty.

Functions

This section is empty.

Types

type File

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

File follows one path. Not safe for concurrent use; one goroutine polls.

func NewFile

func NewFile(input, path string, opts Options) *File

NewFile prepares to follow path for the log_input named input. A live tail joins the present: the first file it opens is read from its end, and every file it meets afterwards — a rotation's successor — from the beginning, because that one is new. Reading a log's past is a separate, deliberate act with its own command.

func (*File) Close

func (f *File) Close() error

Close releases the underlying file, flushing nothing: an unterminated line stays unread and the position stays before it.

func (*File) Follow

func (f *File) Follow(ctx context.Context, interval time.Duration, emit func(Line)) error

Follow polls at the given interval until the context ends.

func (*File) Poll

func (f *File) Poll(emit func(Line)) error

Poll reads what is available now and returns — it drains up to the file's size at entry, detects truncation, and hands over to a rotated-in successor after draining the old file. Bounding the drain to the size at entry is what keeps one hot input from starving the loop: a file written faster than it is read leaves its tail for the next Poll, so the caller still ticks, heartbeats and reads its other inputs. A missing path is not an error — the file may not exist yet, or may be mid-rotation; Poll keeps trying.

func (*File) Position

func (f *File) Position() Position

Position reports the current resume point.

type Identity

type Identity struct {
	Dev uint64
	Ino uint64
}

Identity is what makes a file the same file across renames.

type Line

type Line struct {
	Input     string
	Pos       Position
	Text      string
	Truncated bool // longer than MaxLine; Text holds the head
}

Line is one log line and the position to resume from after it.

type Options

type Options struct {
	// FromStart reads the first file from its beginning instead of its
	// end — what a replay wants, and what a live tail never does.
	FromStart bool
	// Resume starts the first file at a known position — the hand-off
	// from a replay that has just read it, inside one process's life.
	// It only holds if the path still names the same file: a different
	// identity means rotation happened in between, and the successor is
	// all new and read whole. This is not persistence; nothing outside
	// the running process may supply it (a live tail joins the present).
	Resume  *Position
	MaxLine int
}

Options tunes a File. The zero value is fine.

type Position

type Position struct {
	Identity
	Offset int64
}

Position is the durable resume point: this exact file, this offset.

Jump to

Keyboard shortcuts

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