-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Log rotation by time interval #8349
Conversation
libbeat/common/file/rotator.go
Outdated
@@ -263,6 +293,81 @@ func (r *Rotator) closeFile() error { | |||
} | |||
|
|||
func (r *Rotator) purgeOldBackups() error { | |||
if (r.daily) { | |||
return r.purgeOldDailyBackups() | |||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if block ends with a return statement, so drop this else and outdent its block
this can be time based instead of daily where the time is defaulted to |
auditbeat/auditbeat.reference.yml
Outdated
@@ -1101,6 +1101,10 @@ logging.files: | |||
# Must be a valid Unix-style file permissions mask expressed in octal notation. | |||
#permissions: 0600 | |||
|
|||
# Enable daily log file rotation in addition to size-based rotation. Defaults to | |||
# disabled. | |||
#daily: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please set this value to false
as it is the default value.
return errors.Wrap(err, "failed to rotate backups") | ||
} | ||
|
||
if r.log != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not move logging in rotateByDay
and rotateBySize
?
libbeat/common/file/rotator.go
Outdated
type Rotator struct { | ||
filename string | ||
maxSizeBytes uint | ||
maxBackups uint | ||
permissions os.FileMode | ||
log Logger // Optional Logger (may be nil). | ||
daily bool | ||
lastYear int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you store date in separately instead of a time.Time
struct? It would make easier to check if the log needs to be rotated or not by using Since
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool feature! However, I am not sure if it 100% addresses the initial issue. I would prefer to have time based log rotation where the rotation interval is configurable. For example adding a new option rotation_interval
which is 0 by default, meaning there is no rotation. If someone wants to use it, he/she can specify an time interval. So the daily rotation would look like rotation_interval: 1d
, weekly could be rotation_interval: 7d
, and so on.
Also, please add a new entry to |
1f1cf94
to
a3b9859
Compare
libbeat/common/file/rotator.go
Outdated
@@ -108,13 +115,22 @@ func WithLogger(l Logger) RotatorOption { | |||
} | |||
} | |||
|
|||
// Daily enables or disables log rotation by time interval in addition to log |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment on exported function Interval should be of the form "Interval ..."
return "" | ||
} | ||
|
||
// Given a log filename in the form [prefix]-[formattedDate]-n, returns n as int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment on exported function IntervalLogIndex should be of the form "IntervalLogIndex ..."
) | ||
} | ||
|
||
// Given a log filename in the form [prefix]-[formattedDate]-n, returns the filename after |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment on exported function OrderIntervalLogs should be of the form "OrderIntervalLogs ..."
return time.Now() | ||
} | ||
|
||
func NewIntervalRotator(interval time.Duration) (*intervalRotator, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported function NewIntervalRotator should have comment or be unexported
exported func NewIntervalRotator returns unexported type *file.intervalRotator, which can be annoying to use
@kvch, thanks for the review. I've updated the PR to allow for rotation on arbitrary time intervals as explained in the edited PR description above. |
My concern about this feature is that we add more logging logic to our code but are in the progress of more moving to popular libraries at least for the internal logging. I wonder if we could do the same for writing to file/stdout etc. too? @andrewkroh Thoughts? |
If there is some popular well-tested library for this sort of thing then I would consider using it, but I didn't find much last time I looked. So I think we have to roll our own here. Is there a use-case for enabling it on the file output? I've never used the file output for anything other than testing and debugging. |
I also looked around for a library that did this and didn't see one. The https://github.com/natefinch/lumberjack library seems to be the most popular library for log rotation, but it does not support time-interval rotation and will not based on the authors comments in issue 17. This PR doesn't suffer from his main criticisms of time-interval rotation in that both size limits and time intervals are considered for rotation, so running out of disk space wouldn't be an issue. |
newInterval func(lastTime time.Time, currentTime time.Time) bool | ||
} | ||
|
||
type clock interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this interface exists? What's the reason of having a realClock
? Why not simply call time.Now
directly instead of through an interface?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume it's used during unit testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's only for testing. I'm happy to do it differently if there's a better or more idiomatic way in Go.
return u64, i, err | ||
} | ||
|
||
func newSecond(lastTime time.Time, currentTime time.Time) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit1: It would be more readable if you called these interval function from each other.
Example:
func newSecond(lastTime, currentTime time.Time) bool {
return lastTime.Second() != currentTime.Second || newMinute(lastTime, currentTime)
}
Nit2: It's a bit confusing/requires a bit more effort to read the code, because the order of the parameters are differs from the order during comparison.
func ...(lastTime, currentTime time.Time) bool {
return lastTime.Seconds() != currentTime.Seconds()
}
I am willing to let the second nit go, because it might be a personal preference.
return u64, i, err | ||
} | ||
|
||
func newSecond(lastTime time.Time, currentTime time.Time) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be sure that nothing can go wrong here, you could add a sanity check to see if currentTime
is indeed later in time than lastTime
. Otherwise the checks only check if the two times are different, not later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was to accommodate cases where the system clock goes backward in calendar time which may occur during daylight savings transitions or when the clock is updated. If that is not desirable, I can change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I also had concerns about that. I'm fine with this.
The unrelated failing tests are all due to an updated geoip database. |
(cherry picked from commit 7b4cb29)
Adds optional log rotation by time interval in addition to size-based log rotation. It's modeled after ES's log rotation which defaults to daily log rotation in which the current log file is rotated to filename-yyyy-MM-dd-n where n is incremented if either the max file size is reached or a beat is started more than once per day. The rotation interval is configurable down to
1s
. Values of1m
,1h
,24h
,7*24h
,30*24h
, and365*24h
are treated specially by being boundary-aligned with minutes, hours, days, weeks, months, and years as reported by the local system clock.The
keepfiles
setting is also honored as the oldest backup files are removed during rotation.Fixes #7990.