github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/logger/local/local_test.go (about)

     1  package local
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"io"
     7  	"os"
     8  	"path/filepath"
     9  	"strconv"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/docker/docker/api/types/backend"
    14  	"github.com/docker/docker/api/types/plugins/logdriver"
    15  	"github.com/docker/docker/daemon/logger"
    16  	"github.com/docker/docker/daemon/logger/loggertest"
    17  	protoio "github.com/gogo/protobuf/io"
    18  	"gotest.tools/v3/assert"
    19  	is "gotest.tools/v3/assert/cmp"
    20  )
    21  
    22  func TestWriteLog(t *testing.T) {
    23  	t.Parallel()
    24  
    25  	dir, err := os.MkdirTemp("", t.Name())
    26  	assert.NilError(t, err)
    27  	defer os.RemoveAll(dir)
    28  
    29  	logPath := filepath.Join(dir, "test.log")
    30  
    31  	l, err := New(logger.Info{LogPath: logPath})
    32  	assert.NilError(t, err)
    33  	defer l.Close()
    34  
    35  	m1 := logger.Message{Source: "stdout", Timestamp: time.Now().Add(-1 * 30 * time.Minute), Line: []byte("message 1")}
    36  	m2 := logger.Message{Source: "stdout", Timestamp: time.Now().Add(-1 * 20 * time.Minute), Line: []byte("message 2"), PLogMetaData: &backend.PartialLogMetaData{Last: true, ID: "0001", Ordinal: 1}}
    37  	m3 := logger.Message{Source: "stderr", Timestamp: time.Now().Add(-1 * 10 * time.Minute), Line: []byte("message 3")}
    38  
    39  	// copy the log message because the underying log writer resets the log message and returns it to a buffer pool
    40  	err = l.Log(copyLogMessage(&m1))
    41  	assert.NilError(t, err)
    42  	err = l.Log(copyLogMessage(&m2))
    43  	assert.NilError(t, err)
    44  	err = l.Log(copyLogMessage(&m3))
    45  	assert.NilError(t, err)
    46  
    47  	f, err := os.Open(logPath)
    48  	assert.NilError(t, err)
    49  	defer f.Close()
    50  	dec := protoio.NewUint32DelimitedReader(f, binary.BigEndian, 1e6)
    51  
    52  	var (
    53  		proto     logdriver.LogEntry
    54  		testProto logdriver.LogEntry
    55  		partial   logdriver.PartialLogEntryMetadata
    56  	)
    57  
    58  	lenBuf := make([]byte, encodeBinaryLen)
    59  	seekMsgLen := func() {
    60  		io.ReadFull(f, lenBuf)
    61  	}
    62  
    63  	err = dec.ReadMsg(&proto)
    64  	assert.NilError(t, err)
    65  	messageToProto(&m1, &testProto, &partial)
    66  	assert.Check(t, is.DeepEqual(testProto, proto), "expected:\n%+v\ngot:\n%+v", testProto, proto)
    67  	seekMsgLen()
    68  
    69  	err = dec.ReadMsg(&proto)
    70  	assert.NilError(t, err)
    71  	messageToProto(&m2, &testProto, &partial)
    72  	assert.Check(t, is.DeepEqual(testProto, proto))
    73  	seekMsgLen()
    74  
    75  	err = dec.ReadMsg(&proto)
    76  	assert.NilError(t, err)
    77  	messageToProto(&m3, &testProto, &partial)
    78  	assert.Check(t, is.DeepEqual(testProto, proto), "expected:\n%+v\ngot:\n%+v", testProto, proto)
    79  }
    80  
    81  func TestReadLog(t *testing.T) {
    82  	r := loggertest.Reader{
    83  		Factory: func(t *testing.T, info logger.Info) func(*testing.T) logger.Logger {
    84  			dir := t.TempDir()
    85  			info.LogPath = filepath.Join(dir, info.ContainerID+".log")
    86  			return func(t *testing.T) logger.Logger {
    87  				l, err := New(info)
    88  				assert.NilError(t, err)
    89  				return l
    90  			}
    91  		},
    92  	}
    93  	t.Run("Tail", r.TestTail)
    94  	t.Run("Follow", r.TestFollow)
    95  }
    96  
    97  func BenchmarkLogWrite(b *testing.B) {
    98  	f, err := os.CreateTemp("", b.Name())
    99  	assert.Assert(b, err)
   100  	defer os.Remove(f.Name())
   101  	f.Close()
   102  
   103  	local, err := New(logger.Info{LogPath: f.Name()})
   104  	assert.Assert(b, err)
   105  	defer local.Close()
   106  
   107  	t := time.Now().UTC()
   108  	for _, data := range [][]byte{
   109  		[]byte(""),
   110  		[]byte("a short string"),
   111  		bytes.Repeat([]byte("a long string"), 100),
   112  		bytes.Repeat([]byte("a really long string"), 10000),
   113  	} {
   114  		b.Run(strconv.Itoa(len(data)), func(b *testing.B) {
   115  			entry := &logdriver.LogEntry{Line: data, Source: "stdout", TimeNano: t.UnixNano()}
   116  			b.SetBytes(int64(entry.Size() + encodeBinaryLen + encodeBinaryLen))
   117  			b.ResetTimer()
   118  			for i := 0; i < b.N; i++ {
   119  				msg := logger.NewMessage()
   120  				msg.Line = data
   121  				msg.Timestamp = t
   122  				msg.Source = "stdout"
   123  				if err := local.Log(msg); err != nil {
   124  					b.Fatal(err)
   125  				}
   126  			}
   127  		})
   128  	}
   129  }
   130  
   131  func copyLogMessage(src *logger.Message) *logger.Message {
   132  	dst := logger.NewMessage()
   133  	dst.Source = src.Source
   134  	dst.Timestamp = src.Timestamp
   135  	dst.Attrs = src.Attrs
   136  	dst.Err = src.Err
   137  	dst.Line = append(dst.Line, src.Line...)
   138  	if src.PLogMetaData != nil {
   139  		lmd := *src.PLogMetaData
   140  		dst.PLogMetaData = &lmd
   141  	}
   142  	return dst
   143  }