From ad680d8a487263d0fc80f2e75f2939d1196a53b7 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Fri, 21 Nov 2025 11:31:50 -0500 Subject: [PATCH] fix: don't expose the old log file time format string Signed-off-by: Xe Iaso --- docs/docs/admin/policies.mdx | 20 ++++++------- lib/config/logging.go | 41 +++++++++++--------------- lib/config/logging_test.go | 56 ++++++++++++------------------------ lib/policy/policy.go | 3 +- 4 files changed, 46 insertions(+), 74 deletions(-) diff --git a/docs/docs/admin/policies.mdx b/docs/docs/admin/policies.mdx index 044bd628..a3a2e7d4 100644 --- a/docs/docs/admin/policies.mdx +++ b/docs/docs/admin/policies.mdx @@ -372,15 +372,14 @@ This isn't currently used by Anubis, but will be in the future for "slightly imp The `file` sink makes Anubis write its logs to the filesystem and rotate them out when the log file meets certain thresholds. This logging sink takes the following parameters: -| Name | Type | Example | Description | -| :------------------ | :-------------------- | :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `file` | string | `/var/log/anubis.log` | The file where Anubis logs should be written to. Make sure the user Anubis is running as has write and file creation permissions to this directory. | -| `maxBackups` | number | `3` | The number of old log files that should be maintained when log files are rotated out. | -| `maxBytes` | number of bytes | `67108864` (64Mi) | The maximum size of each log file before it is rotated out. | -| `maxAge` | number of days | `7` | If a log file is more than this many days old, rotate it out. | -| `oldFileTimeFormat` | Go time format string | `2006-01-02T15-04-05` | A [Go time format string](https://pkg.go.dev/time#Layout) that describes how the filenames of old log files should be constructed. This default somewhat conforms to [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339). | -| `compress` | boolean | `true` | If true, compress old log files with gzip. This should be set to `true` and is only exposed as an option for dealing with legacy workflows where there is pre-existing magical thinking about log files at play. | -| `useLocalTime` | boolean | `false` | If true, use the system local time zone to create log filenames instead of UTC. This should almost always be set to `false` and is only exposed for legacy workflows where there is pre-existing magical thinking about time zones at play. | +| Name | Type | Example | Description | +| :------------- | :-------------- | :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `file` | string | `/var/log/anubis.log` | The file where Anubis logs should be written to. Make sure the user Anubis is running as has write and file creation permissions to this directory. | +| `maxBackups` | number | `3` | The number of old log files that should be maintained when log files are rotated out. | +| `maxBytes` | number of bytes | `67108864` (64Mi) | The maximum size of each log file before it is rotated out. | +| `maxAge` | number of days | `7` | If a log file is more than this many days old, rotate it out. | +| `compress` | boolean | `true` | If true, compress old log files with gzip. This should be set to `true` and is only exposed as an option for dealing with legacy workflows where there is magical thinking about log files at play. | +| `useLocalTime` | boolean | `false` | If true, use the system local time zone to create log filenames instead of UTC. This should almost always be set to `false` and is only exposed for legacy workflows where there is magical thinking about time zones at play. | ```yaml logging: @@ -390,11 +389,12 @@ logging: maxBackups: 3 # keep at least 3 old copies maxBytes: 67108864 # each file can have up to 64 Mi of logs maxAge: 7 # rotate files out every n days - oldFileTimeFormat: 2006-01-02T15-04-05 # RFC 3339-ish compress: true # gzip-compress old log files useLocalTime: false # timezone for rotated files is UTC ``` +When files are rotated out, the old files will be named after the rotation timestamp in [RFC 3339 format](https://www.rfc-editor.org/rfc/rfc3339). + ### `stdio` sink By default, Anubis logs everything to the standard error stream of its process. This requires no configuration: diff --git a/lib/config/logging.go b/lib/config/logging.go index a0308d6f..b16a4ca5 100644 --- a/lib/config/logging.go +++ b/lib/config/logging.go @@ -4,15 +4,13 @@ import ( "errors" "fmt" "log/slog" - "time" ) var ( - ErrMissingLoggingFileConfig = errors.New("config.Logging: missing value parameters in logging block") - ErrInvalidLoggingSink = errors.New("config.Logging: invalid sink") - ErrInvalidLoggingFileConfig = errors.New("config.LoggingFileConfig: invalid parameters") - ErrInvalidLoggingFileConfigOldTimeFormat = errors.New("config.LoggingFileConfig: invalid old time format") - ErrOutOfRange = errors.New("config: error out of range") + ErrMissingLoggingFileConfig = errors.New("config.Logging: missing value parameters in logging block") + ErrInvalidLoggingSink = errors.New("config.Logging: invalid sink") + ErrInvalidLoggingFileConfig = errors.New("config.LoggingFileConfig: invalid parameters") + ErrOutOfRange = errors.New("config: error out of range") ) type Logging struct { @@ -58,13 +56,12 @@ func (Logging) Default() *Logging { } type LoggingFileConfig struct { - Filename string `json:"file"` - OldFileTimeFormat string `json:"oldFileTimeFormat"` - MaxBackups int `json:"maxBackups"` - MaxBytes int64 `json:"maxBytes"` - MaxAge int `json:"maxAge"` - Compress bool `json:"compress"` - UseLocalTime bool `json:"useLocalTime"` + Filename string `json:"file"` + MaxBackups int `json:"maxBackups"` + MaxBytes int64 `json:"maxBytes"` + MaxAge int `json:"maxAge"` + Compress bool `json:"compress"` + UseLocalTime bool `json:"useLocalTime"` } func (lfc *LoggingFileConfig) Valid() error { @@ -82,10 +79,6 @@ func (lfc *LoggingFileConfig) Valid() error { errs = append(errs, fmt.Errorf("%w: filename", ErrMissingValue)) } - if _, err := time.Parse(lfc.OldFileTimeFormat, time.Now().UTC().Format(time.RFC3339)); err != nil { - errs = append(errs, fmt.Errorf("%w: %w", ErrInvalidLoggingFileConfigOldTimeFormat, err)) - } - if lfc.MaxBackups < 0 { errs = append(errs, fmt.Errorf("%w: max backup count %d is not greater than or equal to zero", ErrOutOfRange, lfc.MaxBackups)) } @@ -105,7 +98,6 @@ func (lfc *LoggingFileConfig) Valid() error { func (lfc LoggingFileConfig) Zero() bool { for _, cond := range []bool{ lfc.Filename != "", - lfc.OldFileTimeFormat != "", lfc.MaxBackups != 0, lfc.MaxBytes != 0, lfc.MaxAge != 0, @@ -122,12 +114,11 @@ func (lfc LoggingFileConfig) Zero() bool { func (LoggingFileConfig) Default() *LoggingFileConfig { return &LoggingFileConfig{ - Filename: "./var/anubis.log", - OldFileTimeFormat: time.RFC3339, - MaxBackups: 3, - MaxBytes: 104857600, // 100 Mi - MaxAge: 7, // 7 days - Compress: true, - UseLocalTime: false, + Filename: "./var/anubis.log", + MaxBackups: 3, + MaxBytes: 104857600, // 100 Mi + MaxAge: 7, // 7 days + Compress: true, + UseLocalTime: false, } } diff --git a/lib/config/logging_test.go b/lib/config/logging_test.go index f1135037..c850cbd9 100644 --- a/lib/config/logging_test.go +++ b/lib/config/logging_test.go @@ -3,7 +3,6 @@ package config import ( "errors" "testing" - "time" ) func TestLoggingValid(t *testing.T) { @@ -50,45 +49,27 @@ func TestLoggingValid(t *testing.T) { input: &Logging{ Sink: LogSinkFile, Parameters: &LoggingFileConfig{ - Filename: "", - OldFileTimeFormat: time.RFC3339, - MaxBackups: 3, - MaxBytes: 104857600, // 100 Mi - MaxAge: 7, // 7 days - Compress: true, - UseLocalTime: false, + Filename: "", + MaxBackups: 3, + MaxBytes: 104857600, // 100 Mi + MaxAge: 7, // 7 days + Compress: true, + UseLocalTime: false, }, }, want: ErrMissingValue, }, - { - name: "file sink with wrong time format", - input: &Logging{ - Sink: LogSinkFile, - Parameters: &LoggingFileConfig{ - Filename: "./var/anubis.log", - OldFileTimeFormat: "2025-01-01", - MaxBackups: 3, - MaxBytes: 104857600, // 100 Mi - MaxAge: 7, // 7 days - Compress: true, - UseLocalTime: false, - }, - }, - want: ErrInvalidLoggingFileConfigOldTimeFormat, - }, { name: "file sink with negative max backups", input: &Logging{ Sink: LogSinkFile, Parameters: &LoggingFileConfig{ - Filename: "./var/anubis.log", - OldFileTimeFormat: time.RFC3339, - MaxBackups: -3, - MaxBytes: 104857600, // 100 Mi - MaxAge: 7, // 7 days - Compress: true, - UseLocalTime: false, + Filename: "./var/anubis.log", + MaxBackups: -3, + MaxBytes: 104857600, // 100 Mi + MaxAge: 7, // 7 days + Compress: true, + UseLocalTime: false, }, }, want: ErrOutOfRange, @@ -98,13 +79,12 @@ func TestLoggingValid(t *testing.T) { input: &Logging{ Sink: LogSinkFile, Parameters: &LoggingFileConfig{ - Filename: "./var/anubis.log", - OldFileTimeFormat: time.RFC3339, - MaxBackups: 3, - MaxBytes: 104857600, // 100 Mi - MaxAge: -7, // 7 days - Compress: true, - UseLocalTime: false, + Filename: "./var/anubis.log", + MaxBackups: 3, + MaxBytes: 104857600, // 100 Mi + MaxAge: -7, // 7 days + Compress: true, + UseLocalTime: false, }, }, want: ErrOutOfRange, diff --git a/lib/policy/policy.go b/lib/policy/policy.go index aa17c3c1..8f6dfaa3 100644 --- a/lib/policy/policy.go +++ b/lib/policy/policy.go @@ -8,6 +8,7 @@ import ( "log/slog" "os" "sync/atomic" + "time" "github.com/TecharoHQ/anubis/internal" "github.com/TecharoHQ/anubis/lib/config" @@ -216,7 +217,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic case config.LogSinkFile: out := &logrotate.Logger{ Filename: c.Logging.Parameters.Filename, - FilenameTimeFormat: c.Logging.Parameters.OldFileTimeFormat, + FilenameTimeFormat: time.RFC3339, MaxBytes: c.Logging.Parameters.MaxBytes, MaxAge: c.Logging.Parameters.MaxAge, MaxBackups: c.Logging.Parameters.MaxBackups,