<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Exchange Server">
<!-- converted from rtf -->
<style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style>
</head>
<body>
<font face="Calibri" size="2"><span style="font-size:11pt;">
<div>Hi All,</div>
<div> </div>
<div>We noticed that `tail -F` has a problem with losing data when watching a log file when it rotates.  With high logging rates for debugging, this can be a real problem if the logs are being captured from the console output of tail.  </div>
<div> </div>
<div>The code shows that the current method for follow/retry in the file is to cycle through the list of files, first verifying the file descriptor hasn’t changed, then reading any data, sleep after all files are handled, and repeat.  The problem is that data
is missed when this happens since the check for fd changes is after a sleep, but as soon as tail sees the name references a different file, it switches over and gets data from that file instead of making sure it shows all the data in the first one.  For log
rotations, this will miss data from the end of the rotated logfile (e.g., <font face="Courier New">/var/log/</font><font face="Courier New">messages.</font><font face="Courier New">1</font>).</div>
<div> </div>
<div>Patch included below.  Now when it sees that the fd has changed it will save the new one (if opened), process the rest of the data from the current fd, and then skip the next sleep to start processing the new file if it has one (it seemed prudent with
the high data rates).  Test results show tail misses no data when the logs rotate, even under higher logging rates (hundreds or thousands/sec).</div>
<div> </div>
<div>Thanks,</div>
<div>Bob Taylor</div>
<div> </div>
<div>Software Engineer</div>
<div><a href="mailto:t_Bob.Taylor@viasat.com"><font color="#0563C1"><u>t_Bob.Taylor@viasat.com</u></font></a></div>
<div> </div>
<div> </div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">>From 23fe6efca3867ca035c7ca066c2e0ae279c84612 Mon Sep 17 00:00:00 2001</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">From: Bob Taylor <t_Bob.Taylor@viasat.com></span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">Date: Thu, 27 May 2021 11:40:22 -0400</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">Subject: [PATCH] Fix missing data with tail -F</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> </span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">Signed-off-by: Bob Taylor <t_Bob.Taylor@viasat.com></span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">---</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> coreutils/tail.c | 37 ++++++++++++++++++++++++++++++-------</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> 1 file changed, 30 insertions(+), 7 deletions(-)</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> </span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">diff --git a/coreutils/tail.c b/coreutils/tail.c</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">index 08fde6cdd..dbbbf738c 100644</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">--- a/coreutils/tail.c</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+++ b/coreutils/tail.c</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">@@ -125,6 +125,7 @@ int tail_main(int argc, char **argv)</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">         int *fds;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">         const char *fmt;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">         int prev_fd;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+       int skip_sleep = 0;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> </span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">         INIT_G();</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> </span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">@@ -338,13 +339,19 @@ int tail_main(int argc, char **argv)</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">         fmt = NULL;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> </span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">         if (FOLLOW) while (1) {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">-               sleep(sleep_period);</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+               if (0 == skip_sleep) {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                       sleep(sleep_period);</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+               }</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+               else {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                       skip_sleep = 0;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+               }</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> </span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                 i = 0;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                 do {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                         int nread;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                         const char *filename = argv[i];</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                         int fd = fds[i];</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                       int new_fd = -1;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> </span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                         if (FOLLOW_RETRY) {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                 struct stat sbuf, fsbuf;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">@@ -355,19 +362,27 @@ int tail_main(int argc, char **argv)</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                  || fsbuf.st_dev != sbuf.st_dev</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                  || fsbuf.st_ino != sbuf.st_ino</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                 ) {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">-                                       int new_fd;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">-</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">-                                       if (fd >= 0)</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">-                                               close(fd);</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                       /* We know the file has been created or renamed and the</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                        * producer now has a newly created file if it can be</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                        * opened by name.  Since we were sleeping, go through</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                        * one more loop if the old file still has a handle to</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                        * make sure that we haven't missed any more data. */</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                         new_fd = open(filename, O_RDONLY);</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                         if (new_fd >= 0) {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                                 bb_error_msg("%s has %s; following end of new file",</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                                         filename, (fd < 0) ? "appeared" : "been replaced"</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                                 );</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                         } else if (fd >= 0) {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">-                                               bb_perror_msg("%s has become inaccessible", filename);</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                               bb_perror_msg("%s has been renamed or deleted", filename);</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                       }</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                       if (fd < 0)</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                       {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                               /* If the original file isn't open, there's no more data</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                                * to process (or the file is just appearing),</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                                * start using the new file immediately */</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                               fds[i] = fd = new_fd;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                               new_fd = -1;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                         }</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">-                                       fds[i] = fd = new_fd;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                 }</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                         }</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                         if (ENABLE_FEATURE_FANCY_TAIL && fd < 0)</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">@@ -395,6 +410,14 @@ int tail_main(int argc, char **argv)</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                 }</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                                 xwrite(STDOUT_FILENO, tailbuf, nread);</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                         }</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                       if (new_fd >= 0)</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                       {</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                               /* We are switching files to a new one, use new_fd and skip the</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                                * next sleep to start processing it. */</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                               close(fd);</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                               fds[i] = fd = new_fd;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                               skip_sleep = 1;</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">+                       }</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">                 } while (++i < nfiles);</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">         } /* while (1) */</span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;"> </span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">-- </span></font></div>
<div><font face="Courier New" size="2"><span style="font-size:10pt;">2.20.1</span></font></div>
<div> </div>
<div> </div>
<div> </div>
</span></font>
</body>
</html>