github.com/devdivbcp/moby@v17.12.0-ce-rc1.0.20200726071732-2d4bfdc789ad+incompatible/daemon/logger/local/read.go (about) 1 package local 2 3 import ( 4 "context" 5 "encoding/binary" 6 "io" 7 8 "bytes" 9 10 "github.com/docker/docker/api/types/plugins/logdriver" 11 "github.com/docker/docker/daemon/logger" 12 "github.com/docker/docker/daemon/logger/loggerutils" 13 "github.com/docker/docker/errdefs" 14 "github.com/pkg/errors" 15 ) 16 17 func (d *driver) ReadLogs(config logger.ReadConfig) *logger.LogWatcher { 18 logWatcher := logger.NewLogWatcher() 19 20 go d.readLogs(logWatcher, config) 21 return logWatcher 22 } 23 24 func (d *driver) readLogs(watcher *logger.LogWatcher, config logger.ReadConfig) { 25 defer close(watcher.Msg) 26 27 d.mu.Lock() 28 d.readers[watcher] = struct{}{} 29 d.mu.Unlock() 30 31 d.logfile.ReadLogs(config, watcher) 32 33 d.mu.Lock() 34 delete(d.readers, watcher) 35 d.mu.Unlock() 36 } 37 38 func getTailReader(ctx context.Context, r loggerutils.SizeReaderAt, req int) (io.Reader, int, error) { 39 size := r.Size() 40 if req < 0 { 41 return nil, 0, errdefs.InvalidParameter(errors.Errorf("invalid number of lines to tail: %d", req)) 42 } 43 44 if size < (encodeBinaryLen*2)+1 { 45 return bytes.NewReader(nil), 0, nil 46 } 47 48 const encodeBinaryLen64 = int64(encodeBinaryLen) 49 var found int 50 51 buf := make([]byte, encodeBinaryLen) 52 53 offset := size 54 for { 55 select { 56 case <-ctx.Done(): 57 return nil, 0, ctx.Err() 58 default: 59 } 60 61 n, err := r.ReadAt(buf, offset-encodeBinaryLen64) 62 if err != nil && err != io.EOF { 63 return nil, 0, errors.Wrap(err, "error reading log message footer") 64 } 65 66 if n != encodeBinaryLen { 67 return nil, 0, errdefs.DataLoss(errors.New("unexpected number of bytes read from log message footer")) 68 } 69 70 msgLen := binary.BigEndian.Uint32(buf) 71 72 n, err = r.ReadAt(buf, offset-encodeBinaryLen64-encodeBinaryLen64-int64(msgLen)) 73 if err != nil && err != io.EOF { 74 return nil, 0, errors.Wrap(err, "error reading log message header") 75 } 76 77 if n != encodeBinaryLen { 78 return nil, 0, errdefs.DataLoss(errors.New("unexpected number of bytes read from log message header")) 79 } 80 81 if msgLen != binary.BigEndian.Uint32(buf) { 82 return nil, 0, errdefs.DataLoss(errors.Wrap(err, "log message header and footer indicate different message sizes")) 83 } 84 85 found++ 86 offset -= int64(msgLen) 87 offset -= encodeBinaryLen64 * 2 88 if found == req { 89 break 90 } 91 if offset <= 0 { 92 break 93 } 94 } 95 96 return io.NewSectionReader(r, offset, size), found, nil 97 } 98 99 func decodeFunc(rdr io.Reader) func() (*logger.Message, error) { 100 proto := &logdriver.LogEntry{} 101 buf := make([]byte, initialBufSize) 102 103 return func() (*logger.Message, error) { 104 var ( 105 read int 106 err error 107 ) 108 109 resetProto(proto) 110 111 for i := 0; i < maxDecodeRetry; i++ { 112 var n int 113 n, err = io.ReadFull(rdr, buf[read:encodeBinaryLen]) 114 if err != nil { 115 if err != io.ErrUnexpectedEOF { 116 return nil, errors.Wrap(err, "error reading log message length") 117 } 118 read += n 119 continue 120 } 121 read += n 122 break 123 } 124 if err != nil { 125 return nil, errors.Wrapf(err, "could not read log message length: read: %d, expected: %d", read, encodeBinaryLen) 126 } 127 128 msgLen := int(binary.BigEndian.Uint32(buf[:read])) 129 130 if len(buf) < msgLen+encodeBinaryLen { 131 buf = make([]byte, msgLen+encodeBinaryLen) 132 } else { 133 if msgLen <= initialBufSize { 134 buf = buf[:initialBufSize] 135 } else { 136 buf = buf[:msgLen+encodeBinaryLen] 137 } 138 } 139 140 return decodeLogEntry(rdr, proto, buf, msgLen) 141 } 142 } 143 144 func decodeLogEntry(rdr io.Reader, proto *logdriver.LogEntry, buf []byte, msgLen int) (*logger.Message, error) { 145 var ( 146 read int 147 err error 148 ) 149 for i := 0; i < maxDecodeRetry; i++ { 150 var n int 151 n, err = io.ReadFull(rdr, buf[read:msgLen+encodeBinaryLen]) 152 if err != nil { 153 if err != io.ErrUnexpectedEOF { 154 return nil, errors.Wrap(err, "could not decode log entry") 155 } 156 read += n 157 continue 158 } 159 break 160 } 161 if err != nil { 162 return nil, errors.Wrapf(err, "could not decode entry: read %d, expected: %d", read, msgLen) 163 } 164 165 if err := proto.Unmarshal(buf[:msgLen]); err != nil { 166 return nil, errors.Wrap(err, "error unmarshalling log entry") 167 } 168 169 msg := protoToMessage(proto) 170 if msg.PLogMetaData == nil { 171 msg.Line = append(msg.Line, '\n') 172 } 173 return msg, nil 174 }