Add automatic log rotation for daemon (bd-154)
- Integrated lumberjack library for production-ready log rotation - Configurable via env vars: BEADS_DAEMON_LOG_MAX_SIZE, BEADS_DAEMON_LOG_MAX_BACKUPS, BEADS_DAEMON_LOG_MAX_AGE, BEADS_DAEMON_LOG_COMPRESS - Defaults: 10MB max size, 3 backups, 7 day retention, compression enabled - Added comprehensive tests for env var parsing and rotation config - Updated README.md and CHANGELOG.md with rotation documentation - Prevents unbounded log growth for long-running daemons Amp-Thread-ID: https://ampcode.com/threads/T-8232d41a-6872-4f4c-962c-7fae8f5e83b7 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/steveyegge/beads/internal/storage"
|
||||
"github.com/steveyegge/beads/internal/storage/sqlite"
|
||||
"github.com/steveyegge/beads/internal/types"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
var daemonCmd = &cobra.Command{
|
||||
@@ -182,6 +183,24 @@ func boolToFlag(condition bool, flag string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// getEnvInt reads an integer from environment variable with a default value
|
||||
func getEnvInt(key string, defaultValue int) int {
|
||||
if val := os.Getenv(key); val != "" {
|
||||
if parsed, err := strconv.Atoi(val); err == nil {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// getEnvBool reads a boolean from environment variable with a default value
|
||||
func getEnvBool(key string, defaultValue bool) bool {
|
||||
if val := os.Getenv(key); val != "" {
|
||||
return val == "true" || val == "1"
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func getPIDFilePath(global bool) (string, error) {
|
||||
var beadsDir string
|
||||
var err error
|
||||
@@ -606,10 +625,18 @@ func importToJSONLWithStore(ctx context.Context, store storage.Storage, jsonlPat
|
||||
}
|
||||
|
||||
func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, pidFile string, global bool) {
|
||||
logF, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error opening log file: %v\n", err)
|
||||
os.Exit(1)
|
||||
// Configure log rotation with lumberjack
|
||||
maxSizeMB := getEnvInt("BEADS_DAEMON_LOG_MAX_SIZE", 10)
|
||||
maxBackups := getEnvInt("BEADS_DAEMON_LOG_MAX_BACKUPS", 3)
|
||||
maxAgeDays := getEnvInt("BEADS_DAEMON_LOG_MAX_AGE", 7)
|
||||
compress := getEnvBool("BEADS_DAEMON_LOG_COMPRESS", true)
|
||||
|
||||
logF := &lumberjack.Logger{
|
||||
Filename: logPath,
|
||||
MaxSize: maxSizeMB, // MB
|
||||
MaxBackups: maxBackups, // number of rotated files
|
||||
MaxAge: maxAgeDays, // days
|
||||
Compress: compress, // compress old logs
|
||||
}
|
||||
defer logF.Close()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user