diff --git a/logging/logfile.go b/logging/logfile.go index 65de0f871eb5..f84d12de4b19 100644 --- a/logging/logfile.go +++ b/logging/logfile.go @@ -60,19 +60,24 @@ func (l *LogFile) fileNamePattern() string { } func (l *LogFile) openNew() error { - createTime := now() newfileName := l.fileName newfilePath := filepath.Join(l.logPath, newfileName) - // Try creating a file. We truncate the file because we are the only authority to write the logs - filePointer, err := os.OpenFile(newfilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640) + // Try creating or opening the active log file. Since the active log file + // always has the same name, append log entries to prevent overwriting + // previous log data. + filePointer, err := os.OpenFile(newfilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0640) if err != nil { return err } l.FileInfo = filePointer + stat, err := filePointer.Stat() + if err != nil { + return err + } // New file, new bytes tracker, new creation time :) - l.LastCreated = createTime + l.LastCreated = l.createTime(stat) l.BytesWritten = 0 return nil } diff --git a/logging/logfile_bsd.go b/logging/logfile_bsd.go new file mode 100644 index 000000000000..d81d065be1ce --- /dev/null +++ b/logging/logfile_bsd.go @@ -0,0 +1,16 @@ +//go:build darwin || freebsd || netbsd || openbsd +// +build darwin freebsd netbsd openbsd + +package logging + +import ( + "os" + "syscall" + "time" +) + +func (l *LogFile) createTime(stat os.FileInfo) time.Time { + stat_t := stat.Sys().(*syscall.Stat_t) + createTime := stat_t.Ctimespec + return time.Unix(int64(createTime.Sec), int64(createTime.Nsec)) +} diff --git a/logging/logfile_linux.go b/logging/logfile_linux.go new file mode 100644 index 000000000000..6cdacfe80e22 --- /dev/null +++ b/logging/logfile_linux.go @@ -0,0 +1,17 @@ +//go:build dragonfly || linux +// +build dragonfly linux + +package logging + +import ( + "os" + "syscall" + "time" +) + +func (l *LogFile) createTime(stat os.FileInfo) time.Time { + stat_t := stat.Sys().(*syscall.Stat_t) + createTime := stat_t.Ctim + // Sec and Nsec are int32 in 32-bit architectures. + return time.Unix(int64(createTime.Sec), int64(createTime.Nsec)) //nolint:unconvert +} diff --git a/logging/logfile_solaris.go b/logging/logfile_solaris.go new file mode 100644 index 000000000000..b64610cc38fc --- /dev/null +++ b/logging/logfile_solaris.go @@ -0,0 +1,17 @@ +//go:build solaris +// +build solaris + +package logging + +import ( + "os" + "syscall" + "time" +) + +func (l *LogFile) createTime(stat os.FileInfo) time.Time { + stat_t := stat.Sys().(*syscall.Stat_t) + createTime := stat_t.Ctim + // Sec and Nsec are int32 in 32-bit architectures. + return time.Unix(int64(createTime.Sec), int64(createTime.Nsec)) //nolint:unconvert +} diff --git a/logging/logfile_windows.go b/logging/logfile_windows.go new file mode 100644 index 000000000000..688a8351cdbe --- /dev/null +++ b/logging/logfile_windows.go @@ -0,0 +1,14 @@ +package logging + +import ( + "os" + "time" +) + +func (l *LogFile) createTime(stat os.FileInfo) time.Time { + // Use `ModTime` as an approximation if the exact create time is not + // available. + // On Windows, the file create time is not updated after the active log + // rotates, so use `ModTime` as an approximation as well. + return stat.ModTime() +}