mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-08 22:31:04 +00:00
cmd/syncthing: Do not truncate/rotate logs at start (#6359)
This commit is contained in:
parent
4e4b9a872a
commit
299a80d328
@ -55,28 +55,32 @@ func monitorMain(runtimeOptions RuntimeOptions) {
|
|||||||
logFile = expanded
|
logFile = expanded
|
||||||
}
|
}
|
||||||
var fileDst io.Writer
|
var fileDst io.Writer
|
||||||
|
var err error
|
||||||
|
open := func(name string) (io.WriteCloser, error) {
|
||||||
|
return newAutoclosedFile(name, logFileAutoCloseDelay, logFileMaxOpenTime)
|
||||||
|
}
|
||||||
if runtimeOptions.logMaxSize > 0 {
|
if runtimeOptions.logMaxSize > 0 {
|
||||||
open := func(name string) (io.WriteCloser, error) {
|
fileDst, err = newRotatedFile(logFile, open, int64(runtimeOptions.logMaxSize), runtimeOptions.logMaxFiles)
|
||||||
return newAutoclosedFile(name, logFileAutoCloseDelay, logFileMaxOpenTime), nil
|
|
||||||
}
|
|
||||||
fileDst = newRotatedFile(logFile, open, int64(runtimeOptions.logMaxSize), runtimeOptions.logMaxFiles)
|
|
||||||
} else {
|
} else {
|
||||||
fileDst = newAutoclosedFile(logFile, logFileAutoCloseDelay, logFileMaxOpenTime)
|
fileDst, err = open(logFile)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
if runtime.GOOS == "windows" {
|
l.Warnln("Failed to setup logging to file, proceeding with logging to stdout only:", err)
|
||||||
// Translate line breaks to Windows standard
|
} else {
|
||||||
fileDst = osutil.ReplacingWriter{
|
if runtime.GOOS == "windows" {
|
||||||
Writer: fileDst,
|
// Translate line breaks to Windows standard
|
||||||
From: '\n',
|
fileDst = osutil.ReplacingWriter{
|
||||||
To: []byte{'\r', '\n'},
|
Writer: fileDst,
|
||||||
|
From: '\n',
|
||||||
|
To: []byte{'\r', '\n'},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log to both stdout and file.
|
||||||
|
dst = io.MultiWriter(dst, fileDst)
|
||||||
|
|
||||||
|
l.Infof(`Log output saved to file "%s"`, logFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log to both stdout and file.
|
|
||||||
dst = io.MultiWriter(dst, fileDst)
|
|
||||||
|
|
||||||
l.Infof(`Log output saved to file "%s"`, logFile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args := os.Args
|
args := os.Args
|
||||||
@ -353,16 +357,30 @@ type rotatedFile struct {
|
|||||||
currentSize int64
|
currentSize int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// the createFn should act equivalently to os.Create
|
|
||||||
type createFn func(name string) (io.WriteCloser, error)
|
type createFn func(name string) (io.WriteCloser, error)
|
||||||
|
|
||||||
func newRotatedFile(name string, create createFn, maxSize int64, maxFiles int) *rotatedFile {
|
func newRotatedFile(name string, create createFn, maxSize int64, maxFiles int) (*rotatedFile, error) {
|
||||||
return &rotatedFile{
|
var size int64
|
||||||
name: name,
|
if info, err := os.Lstat(name); err != nil {
|
||||||
create: create,
|
if !os.IsNotExist(err) {
|
||||||
maxSize: maxSize,
|
return nil, err
|
||||||
maxFiles: maxFiles,
|
}
|
||||||
|
size = 0
|
||||||
|
} else {
|
||||||
|
size = info.Size()
|
||||||
}
|
}
|
||||||
|
writer, err := create(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &rotatedFile{
|
||||||
|
name: name,
|
||||||
|
create: create,
|
||||||
|
maxSize: maxSize,
|
||||||
|
maxFiles: maxFiles,
|
||||||
|
currentFile: writer,
|
||||||
|
currentSize: size,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rotatedFile) Write(bs []byte) (int, error) {
|
func (r *rotatedFile) Write(bs []byte) (int, error) {
|
||||||
@ -370,19 +388,13 @@ func (r *rotatedFile) Write(bs []byte) (int, error) {
|
|||||||
// file so we'll start on a new one.
|
// file so we'll start on a new one.
|
||||||
if r.currentSize+int64(len(bs)) > r.maxSize {
|
if r.currentSize+int64(len(bs)) > r.maxSize {
|
||||||
r.currentFile.Close()
|
r.currentFile.Close()
|
||||||
r.currentFile = nil
|
|
||||||
r.currentSize = 0
|
r.currentSize = 0
|
||||||
}
|
|
||||||
|
|
||||||
// If we have no current log, rotate old files out of the way and create
|
|
||||||
// a new one.
|
|
||||||
if r.currentFile == nil {
|
|
||||||
r.rotate()
|
r.rotate()
|
||||||
fd, err := r.create(r.name)
|
f, err := r.create(r.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
r.currentFile = fd
|
r.currentFile = f
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := r.currentFile.Write(bs)
|
n, err := r.currentFile.Write(bs)
|
||||||
@ -435,7 +447,7 @@ type autoclosedFile struct {
|
|||||||
mut sync.Mutex
|
mut sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAutoclosedFile(name string, closeDelay, maxOpenTime time.Duration) *autoclosedFile {
|
func newAutoclosedFile(name string, closeDelay, maxOpenTime time.Duration) (*autoclosedFile, error) {
|
||||||
f := &autoclosedFile{
|
f := &autoclosedFile{
|
||||||
name: name,
|
name: name,
|
||||||
closeDelay: closeDelay,
|
closeDelay: closeDelay,
|
||||||
@ -444,8 +456,13 @@ func newAutoclosedFile(name string, closeDelay, maxOpenTime time.Duration) *auto
|
|||||||
closed: make(chan struct{}),
|
closed: make(chan struct{}),
|
||||||
closeTimer: time.NewTimer(time.Minute),
|
closeTimer: time.NewTimer(time.Minute),
|
||||||
}
|
}
|
||||||
|
f.mut.Lock()
|
||||||
|
defer f.mut.Unlock()
|
||||||
|
if err := f.ensureOpenLocked(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
go f.closerLoop()
|
go f.closerLoop()
|
||||||
return f
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *autoclosedFile) Write(bs []byte) (int, error) {
|
func (f *autoclosedFile) Write(bs []byte) (int, error) {
|
||||||
@ -453,7 +470,7 @@ func (f *autoclosedFile) Write(bs []byte) (int, error) {
|
|||||||
defer f.mut.Unlock()
|
defer f.mut.Unlock()
|
||||||
|
|
||||||
// Make sure the file is open for appending
|
// Make sure the file is open for appending
|
||||||
if err := f.ensureOpen(); err != nil {
|
if err := f.ensureOpenLocked(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,22 +500,14 @@ func (f *autoclosedFile) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Must be called with f.mut held!
|
// Must be called with f.mut held!
|
||||||
func (f *autoclosedFile) ensureOpen() error {
|
func (f *autoclosedFile) ensureOpenLocked() error {
|
||||||
if f.fd != nil {
|
if f.fd != nil {
|
||||||
// File is already open
|
// File is already open
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We open the file for write only, and create it if it doesn't exist.
|
// We open the file for write only, and create it if it doesn't exist.
|
||||||
flags := os.O_WRONLY | os.O_CREATE
|
flags := os.O_WRONLY | os.O_CREATE | os.O_APPEND
|
||||||
if f.opened.IsZero() {
|
|
||||||
// This is the first time we are opening the file. We should truncate
|
|
||||||
// it to better emulate an os.Create() call.
|
|
||||||
flags |= os.O_TRUNC
|
|
||||||
} else {
|
|
||||||
// The file was already opened once, so we should append to it.
|
|
||||||
flags |= os.O_APPEND
|
|
||||||
}
|
|
||||||
|
|
||||||
fd, err := os.OpenFile(f.name, flags, 0644)
|
fd, err := os.OpenFile(f.name, flags, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -33,7 +33,10 @@ func TestRotatedFile(t *testing.T) {
|
|||||||
maxSize := int64(len(testData) + len(testData)/2)
|
maxSize := int64(len(testData) + len(testData)/2)
|
||||||
|
|
||||||
// We allow the log file plus two rotated copies.
|
// We allow the log file plus two rotated copies.
|
||||||
rf := newRotatedFile(logName, open, maxSize, 2)
|
rf, err := newRotatedFile(logName, open, maxSize, 2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Write some bytes.
|
// Write some bytes.
|
||||||
if _, err := rf.Write(testData); err != nil {
|
if _, err := rf.Write(testData); err != nil {
|
||||||
@ -140,7 +143,10 @@ func TestAutoClosedFile(t *testing.T) {
|
|||||||
data := []byte("hello, world\n")
|
data := []byte("hello, world\n")
|
||||||
|
|
||||||
// An autoclosed file that closes very quickly
|
// An autoclosed file that closes very quickly
|
||||||
ac := newAutoclosedFile(file, time.Millisecond, time.Millisecond)
|
ac, err := newAutoclosedFile(file, time.Millisecond, time.Millisecond)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Write some data.
|
// Write some data.
|
||||||
if _, err := ac.Write(data); err != nil {
|
if _, err := ac.Write(data); err != nil {
|
||||||
@ -182,21 +188,23 @@ func TestAutoClosedFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open the file again.
|
// Open the file again.
|
||||||
ac = newAutoclosedFile(file, time.Second, time.Second)
|
ac, err = newAutoclosedFile(file, time.Second, time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Write something
|
// Write something
|
||||||
if _, err := ac.Write(data); err != nil {
|
if _, err := ac.Write(data); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// It should now contain only one write, because the first open
|
// It should now contain three writes, as the file is always opened for appending
|
||||||
// should be a truncate.
|
|
||||||
bs, err = ioutil.ReadFile(file)
|
bs, err = ioutil.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if len(bs) != len(data) {
|
if len(bs) != 3*len(data) {
|
||||||
t.Fatalf("Write failed, expected %d bytes, not %d", len(data), len(bs))
|
t.Fatalf("Write failed, expected %d bytes, not %d", 3*len(data), len(bs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close.
|
// Close.
|
||||||
|
Loading…
Reference in New Issue
Block a user