prevent active log from being overwritten when agent starts (#11386)

This commit is contained in:
Luiz Aoqui 2021-10-26 20:57:07 -04:00 committed by GitHub
parent ecc7a288ec
commit b463715a98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 82 additions and 7 deletions

3
.changelog/11386.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
agent: Fixed an issue that could cause previous log lines to be overwritten
```

View File

@ -62,18 +62,23 @@ func (l *logFile) fileNamePattern() string {
}
func (l *logFile) openNew() error {
createTime := now()
newfilePath := filepath.Join(l.logPath, l.fileName)
// 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
}
stat, err := filePointer.Stat()
if err != nil {
return err
}
l.FileInfo = filePointer
// New file, new bytes tracker, new creation time :)
l.LastCreated = createTime
l.BytesWritten = 0
l.BytesWritten = stat.Size()
l.LastCreated = l.createTime(stat)
return nil
}

View File

@ -0,0 +1,16 @@
//go:build darwin || freebsd || netbsd || openbsd
// +build darwin freebsd netbsd openbsd
package agent
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(createTime.Sec, createTime.Nsec)
}

View File

@ -0,0 +1,17 @@
//go:build dragonfly || linux || solaris
// +build dragonfly linux solaris
package agent
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
}

View File

@ -50,13 +50,33 @@ func TestLogFile_openNew(t *testing.T) {
require.NoError(err)
defer os.Remove(tempDir)
logFile := logFile{fileName: testFileName, logPath: tempDir, duration: testDuration}
filt := LevelFilter()
filt.MinLevel = logutils.LogLevel("INFO")
logFile := logFile{
logFilter: filt,
fileName: testFileName,
logPath: tempDir,
MaxBytes: testBytes,
duration: 24 * time.Hour,
}
require.NoError(logFile.openNew())
_, err = ioutil.ReadFile(logFile.FileInfo.Name())
require.NoError(err)
require.Equal(logFile.FileInfo.Name(), filepath.Join(tempDir, testFileName))
// Check if create time and bytes written are kept when opening the active
// log file again.
bytesWritten, err := logFile.Write([]byte("test"))
require.NoError(err)
time.Sleep(2 * time.Second)
require.NoError(logFile.openNew())
timeDelta := time.Now().Sub(logFile.LastCreated)
require.GreaterOrEqual(timeDelta, 2*time.Second)
require.Equal(logFile.BytesWritten, int64(bytesWritten))
}
func TestLogFile_byteRotation(t *testing.T) {

View File

@ -0,0 +1,14 @@
package agent
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()
}