github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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/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  // 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  }