github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/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/demonoid81/moby/api/types/plugins/logdriver"
    11  	"github.com/demonoid81/moby/daemon/logger"
    12  	"github.com/demonoid81/moby/daemon/logger/loggerutils"
    13  	"github.com/demonoid81/moby/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  type decoder struct {
   100  	rdr   io.Reader
   101  	proto *logdriver.LogEntry
   102  	buf   []byte
   103  }
   104  
   105  func (d *decoder) Decode() (*logger.Message, error) {
   106  	if d.proto == nil {
   107  		d.proto = &logdriver.LogEntry{}
   108  	} else {
   109  		resetProto(d.proto)
   110  	}
   111  	if d.buf == nil {
   112  		d.buf = make([]byte, initialBufSize)
   113  	}
   114  	var (
   115  		read int
   116  		err  error
   117  	)
   118  
   119  	for i := 0; i < maxDecodeRetry; i++ {
   120  		var n int
   121  		n, err = io.ReadFull(d.rdr, d.buf[read:encodeBinaryLen])
   122  		if err != nil {
   123  			if err != io.ErrUnexpectedEOF {
   124  				return nil, errors.Wrap(err, "error reading log message length")
   125  			}
   126  			read += n
   127  			continue
   128  		}
   129  		read += n
   130  		break
   131  	}
   132  	if err != nil {
   133  		return nil, errors.Wrapf(err, "could not read log message length: read: %d, expected: %d", read, encodeBinaryLen)
   134  	}
   135  
   136  	msgLen := int(binary.BigEndian.Uint32(d.buf[:read]))
   137  
   138  	if len(d.buf) < msgLen+encodeBinaryLen {
   139  		d.buf = make([]byte, msgLen+encodeBinaryLen)
   140  	} else {
   141  		if msgLen <= initialBufSize {
   142  			d.buf = d.buf[:initialBufSize]
   143  		} else {
   144  			d.buf = d.buf[:msgLen+encodeBinaryLen]
   145  		}
   146  	}
   147  
   148  	return decodeLogEntry(d.rdr, d.proto, d.buf, msgLen)
   149  }
   150  
   151  func (d *decoder) Reset(rdr io.Reader) {
   152  	d.rdr = rdr
   153  	if d.proto != nil {
   154  		resetProto(d.proto)
   155  	}
   156  	if d.buf != nil {
   157  		d.buf = d.buf[:initialBufSize]
   158  	}
   159  }
   160  
   161  func (d *decoder) Close() {
   162  	d.buf = d.buf[:0]
   163  	d.buf = nil
   164  	if d.proto != nil {
   165  		resetProto(d.proto)
   166  	}
   167  	d.rdr = nil
   168  }
   169  
   170  func decodeFunc(rdr io.Reader) loggerutils.Decoder {
   171  	return &decoder{rdr: rdr}
   172  }
   173  
   174  func decodeLogEntry(rdr io.Reader, proto *logdriver.LogEntry, buf []byte, msgLen int) (*logger.Message, error) {
   175  	var (
   176  		read int
   177  		err  error
   178  	)
   179  	for i := 0; i < maxDecodeRetry; i++ {
   180  		var n int
   181  		n, err = io.ReadFull(rdr, buf[read:msgLen+encodeBinaryLen])
   182  		if err != nil {
   183  			if err != io.ErrUnexpectedEOF {
   184  				return nil, errors.Wrap(err, "could not decode log entry")
   185  			}
   186  			read += n
   187  			continue
   188  		}
   189  		break
   190  	}
   191  	if err != nil {
   192  		return nil, errors.Wrapf(err, "could not decode entry: read %d, expected: %d", read, msgLen)
   193  	}
   194  
   195  	if err := proto.Unmarshal(buf[:msgLen]); err != nil {
   196  		return nil, errors.Wrap(err, "error unmarshalling log entry")
   197  	}
   198  
   199  	msg := protoToMessage(proto)
   200  	if msg.PLogMetaData == nil {
   201  		msg.Line = append(msg.Line, '\n')
   202  	}
   203  	return msg, nil
   204  }