github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/logger/loggerutils/follow.go (about) 1 package loggerutils // import "github.com/docker/docker/daemon/logger/loggerutils" 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 8 "github.com/docker/docker/daemon/logger" 9 "github.com/pkg/errors" 10 "github.com/sirupsen/logrus" 11 ) 12 13 type follow struct { 14 LogFile *LogFile 15 Watcher *logger.LogWatcher 16 Decoder Decoder 17 Forwarder *forwarder 18 19 log *logrus.Entry 20 c chan logPos 21 } 22 23 // Do follows the log file as it is written, starting from f at read. 24 func (fl *follow) Do(f *os.File, read logPos) { 25 fl.log = logrus.WithFields(logrus.Fields{ 26 "module": "logger", 27 "file": f.Name(), 28 }) 29 // Optimization: allocate the write-notifications channel only once and 30 // reuse it for multiple invocations of nextPos(). 31 fl.c = make(chan logPos, 1) 32 33 defer func() { 34 if err := f.Close(); err != nil && !errors.Is(err, os.ErrClosed) { 35 fl.log.WithError(err).Warn("error closing current log file") 36 } 37 }() 38 39 for { 40 wrote, ok := fl.nextPos(read) 41 if !ok { 42 return 43 } 44 45 if wrote.rotation != read.rotation { 46 // Flush the current file before moving on to the next. 47 if _, err := f.Seek(read.size, io.SeekStart); err != nil { 48 fl.Watcher.Err <- err 49 return 50 } 51 if !fl.forward(f) { 52 return 53 } 54 55 // Open the new file, which has the same name as the old 56 // file thanks to file rotation. Make no mistake: they 57 // are different files, with distinct identities. 58 // Atomically capture the wrote position to make 59 // absolutely sure that the position corresponds to the 60 // file we have opened; more rotations could have 61 // occurred since we previously received it. 62 if err := f.Close(); err != nil { 63 fl.log.WithError(err).Warn("error closing rotated log file") 64 } 65 var err error 66 func() { 67 fl.LogFile.fsopMu.RLock() 68 st := <-fl.LogFile.read 69 defer func() { 70 fl.LogFile.read <- st 71 fl.LogFile.fsopMu.RUnlock() 72 }() 73 f, err = open(f.Name()) 74 wrote = st.pos 75 }() 76 // We tried to open the file inside a critical section 77 // so we shouldn't have been racing the rotation of the 78 // file. Any error, even fs.ErrNotFound, is exceptional. 79 if err != nil { 80 fl.Watcher.Err <- fmt.Errorf("logger: error opening log file for follow after rotation: %w", err) 81 return 82 } 83 84 if nrot := wrote.rotation - read.rotation; nrot > 1 { 85 fl.log.WithField("missed-rotations", nrot). 86 Warn("file rotations were missed while following logs; some log messages have been skipped over") 87 } 88 89 // Set up our read position to start from the top of the file. 90 read.size = 0 91 } 92 93 if !fl.forward(io.NewSectionReader(f, read.size, wrote.size-read.size)) { 94 return 95 } 96 read = wrote 97 } 98 } 99 100 // nextPos waits until the write position of the LogFile being followed has 101 // advanced from current and returns the new position. 102 func (fl *follow) nextPos(current logPos) (next logPos, ok bool) { 103 var st logReadState 104 select { 105 case <-fl.Watcher.WatchConsumerGone(): 106 return current, false 107 case st = <-fl.LogFile.read: 108 } 109 110 // Have any any logs been written since we last checked? 111 if st.pos == current { // Nope. 112 // Add ourself to the notify list. 113 st.wait = append(st.wait, fl.c) 114 } else { // Yes. 115 // "Notify" ourself immediately. 116 fl.c <- st.pos 117 } 118 fl.LogFile.read <- st 119 120 select { 121 case <-fl.LogFile.closed: // No more logs will be written. 122 select { // Have we followed to the end? 123 case next = <-fl.c: // No: received a new position. 124 default: // Yes. 125 return current, false 126 } 127 case <-fl.Watcher.WatchConsumerGone(): 128 return current, false 129 case next = <-fl.c: 130 } 131 return next, true 132 } 133 134 // forward decodes log messages from r and forwards them to the log watcher. 135 // 136 // The return value, cont, signals whether following should continue. 137 func (fl *follow) forward(r io.Reader) (cont bool) { 138 fl.Decoder.Reset(r) 139 return fl.Forwarder.Do(fl.Watcher, fl.Decoder) 140 }