Documentation
¶
Overview ¶
Package logfile provides file-based logging for bldr via logrus hooks.
Each log file destination is described by a spec string that can be passed via the --log-file CLI flag or the BLDR_LOG_FILE environment variable.
Spec Syntax ¶
A spec string uses semicolon-separated key=value pairs:
level=DEBUG;format=json;path=.bldr/logs/{ts}.log
Keys:
- level: logrus level threshold (default: DEBUG)
- format: "text" or "json" (default: text)
- path: file path, supports timestamp templates
A short form with just the path is also accepted:
.bldr/logs/{ts}.log
The special value "none" disables file logging (useful to override dev mode auto-enable via BLDR_LOG_FILE=none).
Timestamp Templates ¶
Templates in the path are expanded once at process start:
- {ts}: YYYYMMDD-HHMMSS (e.g., 20260222-143052)
- {YYYY}: 4-digit year
- {MM}: 2-digit month (zero-padded)
- {DD}: 2-digit day (zero-padded)
- {HH}: 2-digit hour (zero-padded, 24h)
- {mm}: 2-digit minute (zero-padded)
- {ss}: 2-digit second (zero-padded)
Dev Mode ¶
In dev mode (--build-type dev), file logging is auto-enabled with the default spec "level=DEBUG;path=.bldr/logs/{ts}.log". Set BLDR_LOG_FILE=none or --log-file none to disable.
Index ¶
- Constants
- Variables
- func AttachLogFiles(logger *logrus.Logger, specs []LogFileSpec) (func(), error)
- func BuildLogFileFlag(dest *cli.StringSlice) *cli.StringSliceFlag
- func DiscardConsoleOutput(logger *logrus.Logger)
- func EnableAutoDefault(logger *logrus.Logger, storageRoot string, retentionEnv string, now time.Time) (func(), error)
- func EnsureLoggerLevel(logger *logrus.Logger, specs []LogFileSpec)
- func ExpandTemplate(path string, ts time.Time) string
- func PruneOldLogs(dir string, maxAge time.Duration, keep int, now time.Time) (int, error)
- func ResolveLogLevel(envChain []string, fallback logrus.Level) logrus.Level
- func ResolveRetention(env, raw string) (dur time.Duration, warn string)
- type ConsoleHook
- type FileHook
- type LogFileSpec
Constants ¶
const AutoDefaultEnvVar = "BLDR_LOG_FILE"
AutoDefaultEnvVar is the environment variable that controls the file logging spec. When set to a non-empty value, including "none", the user's configuration wins and BuildAutoDefaultSpec returns no spec.
const DefaultKeepLogs = 8
DefaultKeepLogs is the number of newest prior logs kept regardless of age. Each process start writes a new log, so frequent restarts would otherwise accumulate logs for the whole retention window.
const DefaultRetention = 7 * 24 * time.Hour
DefaultRetention is the on-disk retention duration applied when no project-scoped override resolves to a positive duration.
Variables ¶
var ErrDisabled = errors.New("log file disabled")
ErrDisabled is returned by ParseLogFileSpec when the spec is "none".
Functions ¶
func AttachLogFiles ¶
func AttachLogFiles(logger *logrus.Logger, specs []LogFileSpec) (func(), error)
AttachLogFiles opens log files and attaches hooks to the logger. Returns a cleanup function that closes all hooks and files.
func BuildLogFileFlag ¶
func BuildLogFileFlag(dest *cli.StringSlice) *cli.StringSliceFlag
BuildLogFileFlag returns a CLI flag for --log-file / --log-files.
func DiscardConsoleOutput ¶ added in v0.56.1
DiscardConsoleOutput silences direct and level-filtered console sinks while leaving non-console hooks active.
func EnableAutoDefault ¶ added in v0.51.2
func EnableAutoDefault( logger *logrus.Logger, storageRoot string, retentionEnv string, now time.Time, ) (func(), error)
EnableAutoDefault enables file logging at the storage-root-relative default location when BLDR_LOG_FILE is unset. It prunes stale logs, attaches the file hook, and raises the logger level so console filtering applies via EnsureLoggerLevel.
Returns a cleanup function that closes the file hook (nil when no hook was attached). When BLDR_LOG_FILE is set or storageRoot is empty, this is a no-op and returns (nil, nil).
retentionEnv names the project-scoped retention env var (e.g. "SPACEWAVE_LOG_RETENTION_DAYS"); pass "" to skip the override and always use DefaultRetention. logger receives the retention warning (if any) before the hook is attached so it lands in stderr but not in the about-to-be-created file.
func EnsureLoggerLevel ¶
func EnsureLoggerLevel(logger *logrus.Logger, specs []LogFileSpec)
EnsureLoggerLevel raises the logger level to the most verbose hook level. If the logger level is already sufficient, this is a no-op. Otherwise it redirects the logger's console output through a level-filtered hook so that --log-level controls console verbosity independently of file hooks.
func ExpandTemplate ¶
ExpandTemplate expands timestamp templates in the given path string.
Supported templates:
- {ts} -> YYYYMMDD-HHMMSS
- {YYYY} -> 4-digit year
- {MM} -> 2-digit month (zero-padded)
- {DD} -> 2-digit day (zero-padded)
- {HH} -> 2-digit hour (zero-padded, 24h)
- {mm} -> 2-digit minute (zero-padded)
- {ss} -> 2-digit second (zero-padded)
func PruneOldLogs ¶ added in v0.51.2
PruneOldLogs deletes regular .log files under dir whose mtime is older than maxAge relative to now, and all but the keep newest of the rest. A non-positive keep disables the count limit. Logs held open by a running writer (see AttachLogFiles) are never removed. Returns the number of files removed and the first error encountered (other failures are still attempted).
Non-existent dir is treated as success with zero removed files. Subdirectories and non-.log entries are skipped. Symlinks are not followed; their own metadata is consulted via os.Lstat semantics from os.ReadDir's DirEntry.
func ResolveLogLevel ¶ added in v0.51.2
ResolveLogLevel walks envChain in order, returning the first parseable logrus level found. Empty / unset values are skipped; a value that fails to parse is also skipped (callers receive fallback in that case). Returns fallback when no env var resolves.
func ResolveRetention ¶ added in v0.51.2
ResolveRetention returns the configured on-disk log retention duration. It reads the project-scoped retention env var (e.g. SPACEWAVE_LOG_RETENTION_DAYS) and falls back to DefaultRetention when the variable is unset, blank, non-positive, or unparseable as a non-negative integer.
When the variable is set but cannot be parsed, the returned warn message is non-empty so callers can emit one logrus.Warn at startup. A successful parse always returns warn == "".
Types ¶
type ConsoleHook ¶
type ConsoleHook struct {
// contains filtered or unexported fields
}
ConsoleHook is a logrus hook that writes synchronously to a writer with its own level threshold, independent of the Logger level.
func NewConsoleHook ¶
NewConsoleHook creates a hook that writes synchronously to w.
func (*ConsoleHook) Fire ¶
func (h *ConsoleHook) Fire(entry *logrus.Entry) error
Fire formats and writes the entry synchronously.
func (*ConsoleHook) Levels ¶
func (h *ConsoleHook) Levels() []logrus.Level
Levels returns the log levels this hook is interested in.
type FileHook ¶
type FileHook struct {
// contains filtered or unexported fields
}
FileHook is a logrus hook that writes log entries to a file.
func NewFileHook ¶
NewFileHook creates a hook that writes to the given writer. Exported for testing with bytes.Buffer.
func (*FileHook) Close ¶
func (h *FileHook) Close()
Close signals the writer goroutine to drain and stop, then waits for completion. If the writer implements io.Closer, it is closed. Close is idempotent.
type LogFileSpec ¶
type LogFileSpec struct {
// Level is the logrus level threshold.
Level logrus.Level
// Format is the output format ("text" or "json").
Format string
// Path is the expanded file path (templates already resolved).
Path string
}
LogFileSpec describes a log file destination.
func BuildAutoDefaultSpec ¶ added in v0.51.2
func BuildAutoDefaultSpec(storageRoot string, now time.Time) (LogFileSpec, bool)
BuildAutoDefaultSpec returns the auto-default LogFileSpec for an entrypoint that has no explicit BLDR_LOG_FILE configuration.
The resolved spec writes DEBUG-level text records to <storageRoot>/logs/{ts}.log, where {ts} is expanded against now. If BLDR_LOG_FILE is set to a non-empty value (including "none"), the user's configuration takes precedence and this function returns ok=false so the caller defers to the existing parsing path. Empty values behave like the variable is unset and still get the auto-default.
Callers receive the spec but are responsible for opening the file via AttachLogFiles and pruning old logs via PruneOldLogs.
func ParseLogFileSpec ¶
func ParseLogFileSpec(spec string, ts time.Time) (LogFileSpec, error)
ParseLogFileSpec parses a log file spec string into a LogFileSpec.
Spec syntax (semicolon-delimited key=value pairs):
- Full form: level=DEBUG;format=json;path=./.bldr/logs/{ts}.log
- Short form: ./.bldr/logs/{ts}.log (path only, defaults apply)
- "none" -> returns ErrDisabled
Default level: DEBUG. Default format: text. Unknown keys produce an error. Missing path produces an error.
func ParseLogFileSpecs ¶
func ParseLogFileSpecs(raw []string, ts time.Time) ([]LogFileSpec, error)
ParseLogFileSpecs parses a list of raw spec strings into LogFileSpecs. Entries with value "none" are filtered out.