Documentation
¶
Overview ¶
Package sink provides a generic record-and-close interface for writing JSON-marshalable payloads to a destination, and the concrete implementations (file, nop) the rest of the codebase consumes.
The interface is deliberately payload-agnostic: callers pass any value that json.Marshal can handle, and the sink takes responsibility for serialisation, transport, and durability semantics. This lets unrelated subsystems (audit, future activity/telemetry channels, etc) share the same plumbing -- file rotation, GC, alternate transports plug in once and benefit everyone.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type FileConfig ¶
type FileConfig struct {
// Path is the absolute or relative path to the log file. When set,
// Dir and DefaultFilename are ignored.
Path string `json:"path,omitempty" yaml:"path,omitempty"`
// Dir is the directory in which the sink writes the log when Path is
// empty. Must be set in that case. Relative directories are resolved
// against cwd at NewFileSink time.
Dir string `json:"dir,omitempty" yaml:"dir,omitempty"`
// MaxSizeMB triggers rotation when the file grows past this size.
// Zero means lumberjack's default (100 MB).
MaxSizeMB int `json:"max_size_mb,omitempty" yaml:"max_size_mb,omitempty"`
// MaxBackups is the number of rotated files to keep.
// Zero means keep all (lumberjack default).
MaxBackups int `json:"max_backups,omitempty" yaml:"max_backups,omitempty"`
// MaxAgeDays is the maximum age in days for rotated files.
// Zero means no age-based deletion (lumberjack default).
MaxAgeDays int `json:"max_age_days,omitempty" yaml:"max_age_days,omitempty"`
// DefaultFilename is consulted when Path is empty. It returns just the
// basename; the sink joins it with Dir. When nil, a generic
// "sink_<RFC3339-utc-second>.log" filename is used. Made a function so
// callers can encode their own naming convention (eg
// "stackql_mcp_server_<timestamp>.log") without bringing the format
// string into the sink package.
DefaultFilename func(time.Time) string `json:"-" yaml:"-"`
}
FileConfig is the on-disk file sink configuration.
Either Path (a complete file path) or Dir (a directory in which the sink will pick a filename via DefaultFilename) must be set. NewFileSink errors when both are empty; the sink never silently picks a directory of its own. The caller -- not the sink -- owns the "where do logs land" decision.
type Sink ¶
type Sink interface {
// Record serialises and writes one payload. Errors include transport
// failures (full disk, broken pipe, etc) and marshalling failures.
Record(ctx context.Context, payload any) error
// Close flushes any buffered state and releases the underlying resource.
Close() error
}
Sink is the generic destination contract. Implementations must be safe for concurrent calls from multiple goroutines.
func NewFileSink ¶
func NewFileSink(cfg FileConfig) (Sink, error)
NewFileSink constructs a file-backed sink. Exactly one of cfg.Path or cfg.Dir must be supplied:
- cfg.Path set: used as-is. Relative paths are resolved against cwd.
- cfg.Path empty + cfg.Dir set: the sink picks the basename via cfg.DefaultFilename (or the package-default fallback) and joins it with Dir.
The resolved absolute path is logged to stderr at startup so operators can find the file later.