github.com/devdivbcp/moby@v17.12.0-ce-rc1.0.20200726071732-2d4bfdc789ad+incompatible/daemon/logger/jsonfilelog/read.go (about) 1 package jsonfilelog // import "github.com/docker/docker/daemon/logger/jsonfilelog" 2 3 import ( 4 "context" 5 "encoding/json" 6 "io" 7 8 "github.com/docker/docker/api/types/backend" 9 "github.com/docker/docker/daemon/logger" 10 "github.com/docker/docker/daemon/logger/jsonfilelog/jsonlog" 11 "github.com/docker/docker/daemon/logger/loggerutils" 12 "github.com/docker/docker/pkg/tailfile" 13 "github.com/sirupsen/logrus" 14 ) 15 16 const maxJSONDecodeRetry = 20000 17 18 // ReadLogs implements the logger's LogReader interface for the logs 19 // created by this driver. 20 func (l *JSONFileLogger) ReadLogs(config logger.ReadConfig) *logger.LogWatcher { 21 logWatcher := logger.NewLogWatcher() 22 23 go l.readLogs(logWatcher, config) 24 return logWatcher 25 } 26 27 func (l *JSONFileLogger) readLogs(watcher *logger.LogWatcher, config logger.ReadConfig) { 28 defer close(watcher.Msg) 29 30 l.mu.Lock() 31 l.readers[watcher] = struct{}{} 32 l.mu.Unlock() 33 34 l.writer.ReadLogs(config, watcher) 35 36 l.mu.Lock() 37 delete(l.readers, watcher) 38 l.mu.Unlock() 39 } 40 41 func decodeLogLine(dec *json.Decoder, l *jsonlog.JSONLog) (*logger.Message, error) { 42 l.Reset() 43 if err := dec.Decode(l); err != nil { 44 return nil, err 45 } 46 47 var attrs []backend.LogAttr 48 if len(l.Attrs) != 0 { 49 attrs = make([]backend.LogAttr, 0, len(l.Attrs)) 50 for k, v := range l.Attrs { 51 attrs = append(attrs, backend.LogAttr{Key: k, Value: v}) 52 } 53 } 54 msg := &logger.Message{ 55 Source: l.Stream, 56 Timestamp: l.Created, 57 Line: []byte(l.Log), 58 Attrs: attrs, 59 } 60 return msg, nil 61 } 62 63 // decodeFunc is used to create a decoder for the log file reader 64 func decodeFunc(rdr io.Reader) func() (*logger.Message, error) { 65 l := &jsonlog.JSONLog{} 66 dec := json.NewDecoder(rdr) 67 return func() (msg *logger.Message, err error) { 68 for retries := 0; retries < maxJSONDecodeRetry; retries++ { 69 msg, err = decodeLogLine(dec, l) 70 if err == nil || err == io.EOF { 71 break 72 } 73 74 logrus.WithError(err).WithField("retries", retries).Warn("got error while decoding json") 75 // try again, could be due to a an incomplete json object as we read 76 if _, ok := err.(*json.SyntaxError); ok { 77 dec = json.NewDecoder(rdr) 78 continue 79 } 80 81 // io.ErrUnexpectedEOF is returned from json.Decoder when there is 82 // remaining data in the parser's buffer while an io.EOF occurs. 83 // If the json logger writes a partial json log entry to the disk 84 // while at the same time the decoder tries to decode it, the race condition happens. 85 if err == io.ErrUnexpectedEOF { 86 reader := io.MultiReader(dec.Buffered(), rdr) 87 dec = json.NewDecoder(reader) 88 continue 89 } 90 } 91 return msg, err 92 } 93 } 94 95 func getTailReader(ctx context.Context, r loggerutils.SizeReaderAt, req int) (io.Reader, int, error) { 96 return tailfile.NewTailReader(ctx, r, req) 97 }