diff --git a/klog.go b/klog.go index 69e6e1768..153828695 100644 --- a/klog.go +++ b/klog.go @@ -410,6 +410,9 @@ func InitFlags(flagset *flag.FlagSet) { } flagset.StringVar(&logging.logDir, "log_dir", "", "If non-empty, write log files in this directory") flagset.StringVar(&logging.logFile, "log_file", "", "If non-empty, use this log file") + flagset.Uint64Var(&logging.logFileMaxSize, "log_file_max_size", 0, + "Defines the maximum size a log file can grow to. Unit is megabytes. " + + "When giving a zero, there's no file size limitations.") flagset.BoolVar(&logging.toStderr, "logtostderr", true, "log to standard error instead of files") flagset.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files") flagset.Var(&logging.verbosity, "v", "number for the log level verbosity") @@ -472,6 +475,10 @@ type loggingT struct { // with the log-dir option. logFile string + // When logFile is specified, this limiter makes sure the logFile won't exceeds a certain size. When exceeds, the + // logFile will be cleaned up. If this value is negative, no size limitation will be applied to logFile. + logFileMaxSize uint64 + // If true, do not add the prefix headers, useful when used with SetOutput skipHeaders bool @@ -874,8 +881,17 @@ func (sb *syncBuffer) Sync() error { return sb.file.Sync() } +func IsFileReachedMaxSize(bufferSize uint64) bool { + if logging.logFile != "" { + // If logFileMaxSize is zero, we don't have limitations on the log size. + return logging.logFileMaxSize > 0 && bufferSize >= logging.logFileMaxSize + } + // If "log_file" flag is not specified, the log files will be cleaned up when reaches a fixed size. + return bufferSize >= MaxSize +} + func (sb *syncBuffer) Write(p []byte) (n int, err error) { - if sb.nbytes+uint64(len(p)) >= MaxSize { + if IsFileReachedMaxSize(sb.nbytes+uint64(len(p))) { if err := sb.rotateFile(time.Now(), false); err != nil { sb.logger.exit(err) } @@ -890,7 +906,7 @@ func (sb *syncBuffer) Write(p []byte) (n int, err error) { // rotateFile closes the syncBuffer's file and starts a new one. // The startup argument indicates whether this is the initial startup of klog. -// If startup is true, existing files are opened for apending instead of truncated. +// If startup is true, existing files are opened for appending instead of truncated. func (sb *syncBuffer) rotateFile(now time.Time, startup bool) error { if sb.file != nil { sb.Flush() diff --git a/klog_file.go b/klog_file.go index 1c4897f4f..e4010ad4d 100644 --- a/klog_file.go +++ b/klog_file.go @@ -98,7 +98,7 @@ var onceLogDirs sync.Once // successfully, create also attempts to update the symlink for that tag, ignoring // errors. // The startup argument indicates whether this is the initial startup of klog. -// If startup is true, existing files are opened for apending instead of truncated. +// If startup is true, existing files are opened for appending instead of truncated. func create(tag string, t time.Time, startup bool) (f *os.File, filename string, err error) { if logging.logFile != "" { f, err := openOrCreate(logging.logFile, startup) diff --git a/klog_test.go b/klog_test.go index b5f25c328..fb41c9fd0 100644 --- a/klog_test.go +++ b/klog_test.go @@ -487,3 +487,50 @@ func BenchmarkHeader(b *testing.B) { logging.putBuffer(buf) } } + +// Test the logic on checking log size limitation. +func TestLogFileReachesMaxSize(t *testing.T) { + setFlags() + testData := map[string] struct{ + testLogFile string + testLogFileMaxSize uint64 + testCurrentSize uint64 + expectedResult bool + }{ + "logFile not specified, exceeds max size": { + testLogFile: "", + testLogFileMaxSize: 1, + testCurrentSize: 1024 * 1024 * 2000, //exceeds the maxSize + expectedResult: true, + }, + + "logFile not specified, not exceeds max size": { + testLogFile: "", + testLogFileMaxSize: 1, + testCurrentSize: 1024 * 1024 * 1000, // smaller than the maxSize + expectedResult: false, + }, + "logFile specified, exceeds max size": { + testLogFile: "/tmp/test.log", + testLogFileMaxSize: 1024 * 1024 * 500, + testCurrentSize: 1024 * 1024 * 1000, //exceeds the logFileMaxSize + expectedResult: true, + }, + "logFile specified, not exceeds max size": { + testLogFile: "/tmp/test.log", + testLogFileMaxSize: 1024 * 1024 * 500, + testCurrentSize: 1024 * 1024 * 300, //exceeds the logFileMaxSize + expectedResult: false, + }, + } + + for name, test := range testData { + logging.logFile = test.testLogFile + logging.logFileMaxSize = test.testLogFileMaxSize + actualResult := IsFileReachedMaxSize(test.testCurrentSize) + if test.expectedResult != actualResult { + t.Fatalf("Error on test case '%v': Was expecting result equals %v, got %v", + name, test.expectedResult, actualResult) + } + } +}