From 78fafb5ada4925c774248e646d553f01c2f74bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9mi=20V=C3=A1nyi?= Date: Thu, 9 Apr 2020 18:07:24 +0200 Subject: [PATCH] Do not rotate log files on startup when interval is configured and rotateonstartup is disabled (#17613) ## What does this PR do? This PR modifies the interval rotator which is responsible for rotating log files of Filebeat after the specified interval. From now on `rotateonstartup` option is taken into account when setting up this rotator. If the option is set to `false`, Filebeat tries to set the `lastRotate` time to the log file configured. If it cannot be found, Filebeat will not attempt to set the variable. But it is not a problem, as there is no file to rotate. If the user restarts filebeat right before it is able to rotate the first log file, it won't get rotated when Filebeat restarts. For example, the interval is set to 24h, and the user restarts Filebeat after 23 hours, the log file will not be rotated after one more hour. It will be rotated after the 24 hours of runtime has elapsed, as `lastRotate` is set the modification time of the file. ## Why is it important? Previously, if both `logging.files.interval` was configured and `logging.files.rotateonstartup` was disabled, Filebeat rotated output log files regardless of the `rotateonstartup` options. --- CHANGELOG.next.asciidoc | 1 + libbeat/common/file/interval_rotator.go | 19 ++++++++++++---- libbeat/common/file/interval_rotator_test.go | 24 ++++++++++++-------- libbeat/common/file/rotator.go | 2 +- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 4e8a363ef01..55de0e08f3b 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -74,6 +74,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d - Fix concurrency issues in convert processor when used in the global context. {pull}17032[17032] - Fix bug with `monitoring.cluster_uuid` setting not always being exposed via GET /state Beats API. {issue}16732[16732] {pull}17420[17420] - Fix building on FreeBSD by removing build flags from `add_cloudfoundry_metadata` processor. {pull}17486[17486] +- Do not rotate log files on startup when interval is configured and rotateonstartup is disabled. {pull}17613[17613] *Auditbeat* diff --git a/libbeat/common/file/interval_rotator.go b/libbeat/common/file/interval_rotator.go index b531acca237..2fb9f89aee8 100644 --- a/libbeat/common/file/interval_rotator.go +++ b/libbeat/common/file/interval_rotator.go @@ -20,6 +20,7 @@ package file import ( "errors" "fmt" + "os" "sort" "strconv" "time" @@ -45,7 +46,7 @@ func (realClock) Now() time.Time { return time.Now() } -func newIntervalRotator(interval time.Duration) (*intervalRotator, error) { +func newIntervalRotator(log Logger, interval time.Duration, rotateOnStartup bool, filename string) (*intervalRotator, error) { if interval == 0 { return nil, nil } @@ -54,11 +55,11 @@ func newIntervalRotator(interval time.Duration) (*intervalRotator, error) { } ir := &intervalRotator{interval: (interval / time.Second) * time.Second} // drop fractional seconds - ir.initialize() + ir.initialize(log, rotateOnStartup, filename) return ir, nil } -func (r *intervalRotator) initialize() error { +func (r *intervalRotator) initialize(log Logger, rotateOnStartup bool, filename string) { r.clock = realClock{} switch r.interval { @@ -93,7 +94,17 @@ func (r *intervalRotator) initialize() error { return lastInterval != currentInterval } } - return nil + + if !rotateOnStartup { + fi, err := os.Stat(filename) + if err != nil { + if log != nil { + log.Debugw("Not attempting to find last rotated time, configured logs dir cannot be opened: %v", err) + } + return + } + r.lastRotate = fi.ModTime() + } } func (r *intervalRotator) LogPrefix(filename string, modTime time.Time) string { diff --git a/libbeat/common/file/interval_rotator_test.go b/libbeat/common/file/interval_rotator_test.go index fda516d8627..b31592677d6 100644 --- a/libbeat/common/file/interval_rotator_test.go +++ b/libbeat/common/file/interval_rotator_test.go @@ -25,7 +25,7 @@ import ( ) func TestSecondRotator(t *testing.T) { - a, err := newIntervalRotator(time.Second) + a, err := newMockIntervalRotator(time.Second) if err != nil { t.Fatal(err) } @@ -51,7 +51,7 @@ func TestSecondRotator(t *testing.T) { } func TestMinuteRotator(t *testing.T) { - a, err := newIntervalRotator(time.Minute) + a, err := newMockIntervalRotator(time.Minute) if err != nil { t.Fatal(err) } @@ -77,7 +77,7 @@ func TestMinuteRotator(t *testing.T) { } func TestHourlyRotator(t *testing.T) { - a, err := newIntervalRotator(time.Hour) + a, err := newMockIntervalRotator(time.Hour) if err != nil { t.Fatal(err) } @@ -103,7 +103,7 @@ func TestHourlyRotator(t *testing.T) { } func TestDailyRotator(t *testing.T) { - a, err := newIntervalRotator(24 * time.Hour) + a, err := newMockIntervalRotator(24 * time.Hour) if err != nil { t.Fatal(err) } @@ -129,7 +129,7 @@ func TestDailyRotator(t *testing.T) { } func TestWeeklyRotator(t *testing.T) { - a, err := newIntervalRotator(7 * 24 * time.Hour) + a, err := newMockIntervalRotator(7 * 24 * time.Hour) if err != nil { t.Fatal(err) } @@ -158,7 +158,7 @@ func TestWeeklyRotator(t *testing.T) { } func TestMonthlyRotator(t *testing.T) { - a, err := newIntervalRotator(30 * 24 * time.Hour) + a, err := newMockIntervalRotator(30 * 24 * time.Hour) if err != nil { t.Fatal(err) } @@ -184,7 +184,7 @@ func TestMonthlyRotator(t *testing.T) { } func TestYearlyRotator(t *testing.T) { - a, err := newIntervalRotator(365 * 24 * time.Hour) + a, err := newMockIntervalRotator(365 * 24 * time.Hour) if err != nil { t.Fatal(err) } @@ -210,7 +210,7 @@ func TestYearlyRotator(t *testing.T) { } func TestArbitraryIntervalRotator(t *testing.T) { - a, err := newIntervalRotator(3 * time.Second) + a, err := newMockIntervalRotator(3 * time.Second) if err != nil { t.Fatal(err) } @@ -253,7 +253,7 @@ func TestArbitraryIntervalRotator(t *testing.T) { } func TestIntervalIsTruncatedToSeconds(t *testing.T) { - a, err := newIntervalRotator(2345 * time.Millisecond) + a, err := newMockIntervalRotator(2345 * time.Millisecond) if err != nil { t.Fatal(err) } @@ -261,7 +261,7 @@ func TestIntervalIsTruncatedToSeconds(t *testing.T) { } func TestZeroIntervalIsNil(t *testing.T) { - a, err := newIntervalRotator(0) + a, err := newMockIntervalRotator(0) if err != nil { t.Fatal(err) } @@ -275,3 +275,7 @@ type testClock struct { func (t testClock) Now() time.Time { return t.time } + +func newMockIntervalRotator(interval time.Duration) (*intervalRotator, error) { + return newIntervalRotator(nil, interval, false, "foo") +} diff --git a/libbeat/common/file/rotator.go b/libbeat/common/file/rotator.go index fa4b5114b2b..0e8e369ff5f 100644 --- a/libbeat/common/file/rotator.go +++ b/libbeat/common/file/rotator.go @@ -166,7 +166,7 @@ func NewFileRotator(filename string, options ...RotatorOption) (*Rotator, error) return nil, errors.Errorf("file rotator permissions mask of %o is invalid", r.permissions) } var err error - r.intervalRotator, err = newIntervalRotator(r.interval) + r.intervalRotator, err = newIntervalRotator(r.log, r.interval, r.rotateOnStartup, r.filename) if err != nil { return nil, err }