Browse code

logger: fix follow logs for max-file=1

In case jsonlogfile is used with max-file=1 and max-size set,
the log rotation is not perfomed; instead, the log file is closed
and re-open with O_TRUNC.

This situation is not handled by the log reader in follow mode,
leading to an issue of log reader being stuck forever.

This situation (file close/reopen) could be handled in waitRead(),
but fsnotify library chose to not listen to or deliver this event
(IN_CLOSE_WRITE in inotify lingo).

So, we have to handle this by checking the file size upon receiving
io.EOF from the log reader, and comparing the size with the one received
earlier. In case the new size is less than the old one, the file was
truncated and we need to seek to its beginning.

Fixes #39235.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>

Kir Kolyshkin authored on 2019/09/21 07:50:10
Showing 1 changed files
... ...
@@ -265,7 +265,7 @@ func compressFile(fileName string, lastTimestamp time.Time) {
265 265
 	compressWriter := gzip.NewWriter(outFile)
266 266
 	defer compressWriter.Close()
267 267
 
268
-	// Add the last log entry timestramp to the gzip header
268
+	// Add the last log entry timestamp to the gzip header
269 269
 	extra := rotateFileMetadata{}
270 270
 	extra.LastTime = lastTimestamp
271 271
 	compressWriter.Header.Extra, err = json.Marshal(&extra)
... ...
@@ -614,11 +614,25 @@ func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan int
614 614
 		}
615 615
 	}
616 616
 
617
+	oldSize := int64(-1)
617 618
 	handleDecodeErr := func(err error) error {
618 619
 		if errors.Cause(err) != io.EOF {
619 620
 			return err
620 621
 		}
621 622
 
623
+		// Handle special case (#39235): max-file=1 and file was truncated
624
+		st, stErr := f.Stat()
625
+		if stErr == nil {
626
+			size := st.Size()
627
+			defer func() { oldSize = size }()
628
+			if size < oldSize { // truncated
629
+				f.Seek(0, 0)
630
+				return nil
631
+			}
632
+		} else {
633
+			logrus.WithError(stErr).Warn("logger: stat error")
634
+		}
635
+
622 636
 		for {
623 637
 			err := waitRead()
624 638
 			if err == nil {