github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/daemon/logger/jsonfilelog/read.go (about) 1 package jsonfilelog 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "os" 9 "time" 10 11 "github.com/Sirupsen/logrus" 12 "github.com/docker/docker/daemon/logger" 13 "github.com/docker/docker/pkg/filenotify" 14 "github.com/docker/docker/pkg/ioutils" 15 "github.com/docker/docker/pkg/jsonlog" 16 "github.com/docker/docker/pkg/tailfile" 17 ) 18 19 const maxJSONDecodeRetry = 20000 20 21 func decodeLogLine(dec *json.Decoder, l *jsonlog.JSONLog) (*logger.Message, error) { 22 l.Reset() 23 if err := dec.Decode(l); err != nil { 24 return nil, err 25 } 26 msg := &logger.Message{ 27 Source: l.Stream, 28 Timestamp: l.Created, 29 Line: []byte(l.Log), 30 } 31 return msg, nil 32 } 33 34 // ReadLogs implements the logger's LogReader interface for the logs 35 // created by this driver. 36 func (l *JSONFileLogger) ReadLogs(config logger.ReadConfig) *logger.LogWatcher { 37 logWatcher := logger.NewLogWatcher() 38 39 go l.readLogs(logWatcher, config) 40 return logWatcher 41 } 42 43 func (l *JSONFileLogger) readLogs(logWatcher *logger.LogWatcher, config logger.ReadConfig) { 44 defer close(logWatcher.Msg) 45 46 pth := l.writer.LogPath() 47 var files []io.ReadSeeker 48 for i := l.writer.MaxFiles(); i > 1; i-- { 49 f, err := os.Open(fmt.Sprintf("%s.%d", pth, i-1)) 50 if err != nil { 51 if !os.IsNotExist(err) { 52 logWatcher.Err <- err 53 break 54 } 55 continue 56 } 57 files = append(files, f) 58 } 59 60 latestFile, err := os.Open(pth) 61 if err != nil { 62 logWatcher.Err <- err 63 return 64 } 65 66 if config.Tail != 0 { 67 tailer := ioutils.MultiReadSeeker(append(files, latestFile)...) 68 tailFile(tailer, logWatcher, config.Tail, config.Since) 69 } 70 71 // close all the rotated files 72 for _, f := range files { 73 if err := f.(io.Closer).Close(); err != nil { 74 logrus.WithField("logger", "json-file").Warnf("error closing tailed log file: %v", err) 75 } 76 } 77 78 if !config.Follow { 79 return 80 } 81 82 if config.Tail >= 0 { 83 latestFile.Seek(0, os.SEEK_END) 84 } 85 86 l.mu.Lock() 87 l.readers[logWatcher] = struct{}{} 88 l.mu.Unlock() 89 90 notifyRotate := l.writer.NotifyRotate() 91 followLogs(latestFile, logWatcher, notifyRotate, config.Since) 92 93 l.mu.Lock() 94 delete(l.readers, logWatcher) 95 l.mu.Unlock() 96 97 l.writer.NotifyRotateEvict(notifyRotate) 98 } 99 100 func tailFile(f io.ReadSeeker, logWatcher *logger.LogWatcher, tail int, since time.Time) { 101 var rdr io.Reader = f 102 if tail > 0 { 103 ls, err := tailfile.TailFile(f, tail) 104 if err != nil { 105 logWatcher.Err <- err 106 return 107 } 108 rdr = bytes.NewBuffer(bytes.Join(ls, []byte("\n"))) 109 } 110 dec := json.NewDecoder(rdr) 111 l := &jsonlog.JSONLog{} 112 for { 113 msg, err := decodeLogLine(dec, l) 114 if err != nil { 115 if err != io.EOF { 116 logWatcher.Err <- err 117 } 118 return 119 } 120 if !since.IsZero() && msg.Timestamp.Before(since) { 121 continue 122 } 123 logWatcher.Msg <- msg 124 } 125 } 126 127 func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan interface{}, since time.Time) { 128 dec := json.NewDecoder(f) 129 l := &jsonlog.JSONLog{} 130 131 fileWatcher, err := filenotify.New() 132 if err != nil { 133 logWatcher.Err <- err 134 } 135 defer func() { 136 f.Close() 137 fileWatcher.Close() 138 }() 139 name := f.Name() 140 141 if err := fileWatcher.Add(name); err != nil { 142 logrus.WithField("logger", "json-file").Warnf("falling back to file poller due to error: %v", err) 143 fileWatcher.Close() 144 fileWatcher = filenotify.NewPollingWatcher() 145 146 if err := fileWatcher.Add(name); err != nil { 147 logrus.Debugf("error watching log file for modifications: %v", err) 148 logWatcher.Err <- err 149 return 150 } 151 } 152 153 var retries int 154 for { 155 msg, err := decodeLogLine(dec, l) 156 if err != nil { 157 if err != io.EOF { 158 // try again because this shouldn't happen 159 if _, ok := err.(*json.SyntaxError); ok && retries <= maxJSONDecodeRetry { 160 dec = json.NewDecoder(f) 161 retries++ 162 continue 163 } 164 165 // io.ErrUnexpectedEOF is returned from json.Decoder when there is 166 // remaining data in the parser's buffer while an io.EOF occurs. 167 // If the json logger writes a partial json log entry to the disk 168 // while at the same time the decoder tries to decode it, the race condition happens. 169 if err == io.ErrUnexpectedEOF && retries <= maxJSONDecodeRetry { 170 reader := io.MultiReader(dec.Buffered(), f) 171 dec = json.NewDecoder(reader) 172 retries++ 173 continue 174 } 175 176 return 177 } 178 179 select { 180 case <-fileWatcher.Events(): 181 dec = json.NewDecoder(f) 182 continue 183 case <-fileWatcher.Errors(): 184 logWatcher.Err <- err 185 return 186 case <-logWatcher.WatchClose(): 187 fileWatcher.Remove(name) 188 return 189 case <-notifyRotate: 190 f.Close() 191 fileWatcher.Remove(name) 192 193 // retry when the file doesn't exist 194 for retries := 0; retries <= 5; retries++ { 195 f, err = os.Open(name) 196 if err == nil || !os.IsNotExist(err) { 197 break 198 } 199 } 200 201 if err = fileWatcher.Add(name); err != nil { 202 logWatcher.Err <- err 203 return 204 } 205 if err != nil { 206 logWatcher.Err <- err 207 return 208 } 209 210 dec = json.NewDecoder(f) 211 continue 212 } 213 } 214 215 retries = 0 // reset retries since we've succeeded 216 if !since.IsZero() && msg.Timestamp.Before(since) { 217 continue 218 } 219 select { 220 case logWatcher.Msg <- msg: 221 case <-logWatcher.WatchClose(): 222 logWatcher.Msg <- msg 223 for { 224 msg, err := decodeLogLine(dec, l) 225 if err != nil { 226 return 227 } 228 if !since.IsZero() && msg.Timestamp.Before(since) { 229 continue 230 } 231 logWatcher.Msg <- msg 232 } 233 } 234 } 235 }