github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/logger/local/read.go (about) 1 package local 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/binary" 7 "fmt" 8 "io" 9 10 "github.com/Prakhar-Agarwal-byte/moby/api/types/plugins/logdriver" 11 "github.com/Prakhar-Agarwal-byte/moby/daemon/logger" 12 "github.com/Prakhar-Agarwal-byte/moby/daemon/logger/loggerutils" 13 "github.com/Prakhar-Agarwal-byte/moby/errdefs" 14 "github.com/pkg/errors" 15 ) 16 17 // maxMsgLen is the maximum size of the logger.Message after serialization. 18 // logger.defaultBufSize caps the size of Line field. 19 const maxMsgLen int = 1e6 // 1MB. 20 21 func (d *driver) ReadLogs(config logger.ReadConfig) *logger.LogWatcher { 22 return d.logfile.ReadLogs(config) 23 } 24 25 func getTailReader(ctx context.Context, r loggerutils.SizeReaderAt, req int) (io.Reader, int, error) { 26 size := r.Size() 27 if req < 0 { 28 return nil, 0, errdefs.InvalidParameter(errors.Errorf("invalid number of lines to tail: %d", req)) 29 } 30 31 if size < (encodeBinaryLen*2)+1 { 32 return bytes.NewReader(nil), 0, nil 33 } 34 35 const encodeBinaryLen64 = int64(encodeBinaryLen) 36 var found int 37 38 buf := make([]byte, encodeBinaryLen) 39 40 offset := size 41 for { 42 select { 43 case <-ctx.Done(): 44 return nil, 0, ctx.Err() 45 default: 46 } 47 48 n, err := r.ReadAt(buf, offset-encodeBinaryLen64) 49 if err != nil && err != io.EOF { 50 return nil, 0, errors.Wrap(err, "error reading log message footer") 51 } 52 53 if n != encodeBinaryLen { 54 return nil, 0, errdefs.DataLoss(errors.New("unexpected number of bytes read from log message footer")) 55 } 56 57 msgLen := binary.BigEndian.Uint32(buf) 58 59 n, err = r.ReadAt(buf, offset-encodeBinaryLen64-encodeBinaryLen64-int64(msgLen)) 60 if err != nil && err != io.EOF { 61 return nil, 0, errors.Wrap(err, "error reading log message header") 62 } 63 64 if n != encodeBinaryLen { 65 return nil, 0, errdefs.DataLoss(errors.New("unexpected number of bytes read from log message header")) 66 } 67 68 if msgLen != binary.BigEndian.Uint32(buf) { 69 return nil, 0, errdefs.DataLoss(errors.Wrap(err, "log message header and footer indicate different message sizes")) 70 } 71 72 found++ 73 offset -= int64(msgLen) 74 offset -= encodeBinaryLen64 * 2 75 if found == req { 76 break 77 } 78 if offset <= 0 { 79 break 80 } 81 } 82 83 return io.NewSectionReader(r, offset, size), found, nil 84 } 85 86 type decoder struct { 87 rdr io.Reader 88 proto *logdriver.LogEntry 89 // buf keeps bytes from rdr. 90 buf []byte 91 // offset is the position in buf. 92 // If offset > 0, buf[offset:] has bytes which are read but haven't used. 93 offset int 94 // nextMsgLen is the length of the next log message. 95 // If nextMsgLen = 0, a new value must be read from rdr. 96 nextMsgLen int 97 } 98 99 func (d *decoder) readRecord(size int) error { 100 var err error 101 for i := 0; i < maxDecodeRetry; i++ { 102 var n int 103 n, err = io.ReadFull(d.rdr, d.buf[d.offset:size]) 104 d.offset += n 105 if err != nil { 106 if err != io.ErrUnexpectedEOF { 107 return err 108 } 109 continue 110 } 111 break 112 } 113 if err != nil { 114 return err 115 } 116 d.offset = 0 117 return nil 118 } 119 120 func (d *decoder) Decode() (*logger.Message, error) { 121 if d.proto == nil { 122 d.proto = &logdriver.LogEntry{} 123 } else { 124 resetProto(d.proto) 125 } 126 if d.buf == nil { 127 d.buf = make([]byte, initialBufSize) 128 } 129 130 if d.nextMsgLen == 0 { 131 msgLen, err := d.decodeSizeHeader() 132 if err != nil { 133 return nil, err 134 } 135 136 if msgLen > maxMsgLen { 137 return nil, fmt.Errorf("log message is too large (%d > %d)", msgLen, maxMsgLen) 138 } 139 140 if len(d.buf) < msgLen+encodeBinaryLen { 141 d.buf = make([]byte, msgLen+encodeBinaryLen) 142 } else if msgLen <= initialBufSize { 143 d.buf = d.buf[:initialBufSize] 144 } else { 145 d.buf = d.buf[:msgLen+encodeBinaryLen] 146 } 147 148 d.nextMsgLen = msgLen 149 } 150 return d.decodeLogEntry() 151 } 152 153 func (d *decoder) Reset(rdr io.Reader) { 154 if d.rdr == rdr { 155 return 156 } 157 158 d.rdr = rdr 159 if d.proto != nil { 160 resetProto(d.proto) 161 } 162 if d.buf != nil { 163 d.buf = d.buf[:initialBufSize] 164 } 165 d.offset = 0 166 d.nextMsgLen = 0 167 } 168 169 func (d *decoder) Close() { 170 d.buf = d.buf[:0] 171 d.buf = nil 172 if d.proto != nil { 173 resetProto(d.proto) 174 } 175 d.rdr = nil 176 } 177 178 func decodeFunc(rdr io.Reader) loggerutils.Decoder { 179 return &decoder{rdr: rdr} 180 } 181 182 func (d *decoder) decodeSizeHeader() (int, error) { 183 err := d.readRecord(encodeBinaryLen) 184 if err != nil { 185 return 0, errors.Wrap(err, "could not read a size header") 186 } 187 188 msgLen := int(binary.BigEndian.Uint32(d.buf[:encodeBinaryLen])) 189 return msgLen, nil 190 } 191 192 func (d *decoder) decodeLogEntry() (*logger.Message, error) { 193 msgLen := d.nextMsgLen 194 err := d.readRecord(msgLen + encodeBinaryLen) 195 if err != nil { 196 return nil, errors.Wrapf(err, "could not read a log entry (size=%d+%d)", msgLen, encodeBinaryLen) 197 } 198 d.nextMsgLen = 0 199 200 if err := d.proto.Unmarshal(d.buf[:msgLen]); err != nil { 201 return nil, errors.Wrapf(err, "error unmarshalling log entry (size=%d)", msgLen) 202 } 203 204 msg := protoToMessage(d.proto) 205 if msg.PLogMetaData == nil || msg.PLogMetaData.Last { 206 msg.Line = append(msg.Line, '\n') 207 } 208 209 return msg, nil 210 }