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

     1  //go:build race
     2  // +build race
     3  
     4  package loggerutils // import "github.com/docker/docker/daemon/logger/loggerutils"
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"io"
    10  	"path/filepath"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/docker/docker/api/types/backend"
    15  	"github.com/docker/docker/daemon/logger"
    16  	"github.com/docker/docker/pkg/tailfile"
    17  	"golang.org/x/sync/errgroup"
    18  	"gotest.tools/v3/assert"
    19  )
    20  
    21  func TestConcurrentLogging(t *testing.T) {
    22  	const (
    23  		containers = 5
    24  		loggers    = 3  // loggers per container
    25  		messages   = 50 // messages per logger
    26  
    27  		capacity = 256
    28  		maxFiles = 3
    29  		compress = true
    30  	)
    31  	getTailReader := func(ctx context.Context, r SizeReaderAt, lines int) (io.Reader, int, error) {
    32  		return tailfile.NewTailReader(ctx, r, lines)
    33  	}
    34  	createDecoder := func(io.Reader) Decoder {
    35  		return dummyDecoder{}
    36  	}
    37  	marshal := func(msg *logger.Message) []byte {
    38  		return []byte(fmt.Sprintf(
    39  			"Line=%q Source=%q Timestamp=%v Attrs=%v PLogMetaData=%#v Err=%v",
    40  			msg.Line, msg.Source, msg.Timestamp, msg.Attrs, msg.PLogMetaData, msg.Err,
    41  		))
    42  	}
    43  	g, ctx := errgroup.WithContext(context.Background())
    44  	for ct := 0; ct < containers; ct++ {
    45  		ct := ct
    46  		dir := t.TempDir()
    47  		g.Go(func() (err error) {
    48  			logfile, err := NewLogFile(filepath.Join(dir, "log.log"), capacity, maxFiles, compress, createDecoder, 0644, getTailReader)
    49  			if err != nil {
    50  				return err
    51  			}
    52  			defer func() {
    53  				if cErr := logfile.Close(); cErr != nil && err == nil {
    54  					err = cErr
    55  				}
    56  			}()
    57  			lg, ctx := errgroup.WithContext(ctx)
    58  			for ln := 0; ln < loggers; ln++ {
    59  				ln := ln
    60  				lg.Go(func() error {
    61  					for m := 0; m < messages; m++ {
    62  						select {
    63  						case <-ctx.Done():
    64  							return ctx.Err()
    65  						default:
    66  						}
    67  						timestamp := time.Now()
    68  						msg := logger.NewMessage()
    69  						msg.Line = append(msg.Line, fmt.Sprintf("container=%v logger=%v msg=%v", ct, ln, m)...)
    70  						msg.Source = "stdout"
    71  						msg.Timestamp = timestamp
    72  						msg.Attrs = append(msg.Attrs, backend.LogAttr{Key: "foo", Value: "bar"})
    73  						msg.PLogMetaData = &backend.PartialLogMetaData{ID: fmt.Sprintf("%v %v %v", ct, ln, m), Ordinal: 1, Last: true}
    74  						marshalled := marshal(msg)
    75  						logger.PutMessage(msg)
    76  						if err := logfile.WriteLogEntry(timestamp, marshalled); err != nil {
    77  							return err
    78  						}
    79  					}
    80  					return nil
    81  				})
    82  			}
    83  			return lg.Wait()
    84  		})
    85  	}
    86  	assert.NilError(t, g.Wait())
    87  }