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

     1  package jsonfilelog // import "github.com/docker/docker/daemon/logger/jsonfilelog"
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"encoding/json"
     7  	"io"
     8  	"os"
     9  	"path/filepath"
    10  	"reflect"
    11  	"strconv"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/docker/docker/daemon/logger"
    16  	"github.com/docker/docker/daemon/logger/jsonfilelog/jsonlog"
    17  	"gotest.tools/v3/assert"
    18  	is "gotest.tools/v3/assert/cmp"
    19  	"gotest.tools/v3/fs"
    20  )
    21  
    22  func TestJSONFileLogger(t *testing.T) {
    23  	cid := "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657"
    24  	tmp, err := os.MkdirTemp("", "docker-logger-")
    25  	if err != nil {
    26  		t.Fatal(err)
    27  	}
    28  	defer os.RemoveAll(tmp)
    29  	filename := filepath.Join(tmp, "container.log")
    30  	l, err := New(logger.Info{
    31  		ContainerID: cid,
    32  		LogPath:     filename,
    33  	})
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	defer l.Close()
    38  
    39  	if err := l.Log(&logger.Message{Line: []byte("line1"), Source: "src1"}); err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	if err := l.Log(&logger.Message{Line: []byte("line2"), Source: "src2"}); err != nil {
    43  		t.Fatal(err)
    44  	}
    45  	if err := l.Log(&logger.Message{Line: []byte("line3"), Source: "src3"}); err != nil {
    46  		t.Fatal(err)
    47  	}
    48  	res, err := os.ReadFile(filename)
    49  	if err != nil {
    50  		t.Fatal(err)
    51  	}
    52  	expected := `{"log":"line1\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
    53  {"log":"line2\n","stream":"src2","time":"0001-01-01T00:00:00Z"}
    54  {"log":"line3\n","stream":"src3","time":"0001-01-01T00:00:00Z"}
    55  `
    56  
    57  	if string(res) != expected {
    58  		t.Fatalf("Wrong log content: %q, expected %q", res, expected)
    59  	}
    60  }
    61  
    62  func TestJSONFileLoggerWithTags(t *testing.T) {
    63  	cid := "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657"
    64  	cname := "test-container"
    65  	tmp, err := os.MkdirTemp("", "docker-logger-")
    66  
    67  	assert.NilError(t, err)
    68  
    69  	defer os.RemoveAll(tmp)
    70  	filename := filepath.Join(tmp, "container.log")
    71  	l, err := New(logger.Info{
    72  		Config: map[string]string{
    73  			"tag": "{{.ID}}/{{.Name}}", // first 12 characters of ContainerID and full ContainerName
    74  		},
    75  		ContainerID:   cid,
    76  		ContainerName: cname,
    77  		LogPath:       filename,
    78  	})
    79  
    80  	assert.NilError(t, err)
    81  	defer l.Close()
    82  
    83  	err = l.Log(&logger.Message{Line: []byte("line1"), Source: "src1"})
    84  	assert.NilError(t, err)
    85  
    86  	err = l.Log(&logger.Message{Line: []byte("line2"), Source: "src2"})
    87  	assert.NilError(t, err)
    88  
    89  	err = l.Log(&logger.Message{Line: []byte("line3"), Source: "src3"})
    90  	assert.NilError(t, err)
    91  
    92  	res, err := os.ReadFile(filename)
    93  	assert.NilError(t, err)
    94  
    95  	expected := `{"log":"line1\n","stream":"src1","attrs":{"tag":"a7317399f3f8/test-container"},"time":"0001-01-01T00:00:00Z"}
    96  {"log":"line2\n","stream":"src2","attrs":{"tag":"a7317399f3f8/test-container"},"time":"0001-01-01T00:00:00Z"}
    97  {"log":"line3\n","stream":"src3","attrs":{"tag":"a7317399f3f8/test-container"},"time":"0001-01-01T00:00:00Z"}
    98  `
    99  	assert.Check(t, is.Equal(expected, string(res)))
   100  }
   101  
   102  func BenchmarkJSONFileLoggerLog(b *testing.B) {
   103  	tmp := fs.NewDir(b, "bench-jsonfilelog")
   104  	defer tmp.Remove()
   105  
   106  	jsonlogger, err := New(logger.Info{
   107  		ContainerID: "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657",
   108  		LogPath:     tmp.Join("container.log"),
   109  		Config: map[string]string{
   110  			"labels":   "first,second",
   111  			"max-file": "10",
   112  			"compress": "true",
   113  			"max-size": "20m",
   114  		},
   115  		ContainerLabels: map[string]string{
   116  			"first":  "label_value",
   117  			"second": "label_foo",
   118  		},
   119  	})
   120  	assert.NilError(b, err)
   121  	defer jsonlogger.Close()
   122  
   123  	t := time.Now().UTC()
   124  	for _, data := range [][]byte{
   125  		[]byte(""),
   126  		[]byte("a short string"),
   127  		bytes.Repeat([]byte("a long string"), 100),
   128  		bytes.Repeat([]byte("a really long string"), 10000),
   129  	} {
   130  		b.Run(strconv.Itoa(len(data)), func(b *testing.B) {
   131  			testMsg := &logger.Message{
   132  				Line:      data,
   133  				Source:    "stderr",
   134  				Timestamp: t,
   135  			}
   136  
   137  			buf := bytes.NewBuffer(nil)
   138  			assert.NilError(b, marshalMessage(testMsg, nil, buf))
   139  			b.SetBytes(int64(buf.Len()))
   140  			b.ResetTimer()
   141  			for i := 0; i < b.N; i++ {
   142  				msg := logger.NewMessage()
   143  				msg.Line = testMsg.Line
   144  				msg.Timestamp = testMsg.Timestamp
   145  				msg.Source = testMsg.Source
   146  				if err := jsonlogger.Log(msg); err != nil {
   147  					b.Fatal(err)
   148  				}
   149  			}
   150  		})
   151  	}
   152  }
   153  
   154  func TestJSONFileLoggerWithOpts(t *testing.T) {
   155  	cid := "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657"
   156  	tmp, err := os.MkdirTemp("", "docker-logger-")
   157  	if err != nil {
   158  		t.Fatal(err)
   159  	}
   160  	defer os.RemoveAll(tmp)
   161  	filename := filepath.Join(tmp, "container.log")
   162  	config := map[string]string{"max-file": "3", "max-size": "1k", "compress": "true"}
   163  	l, err := New(logger.Info{
   164  		ContainerID: cid,
   165  		LogPath:     filename,
   166  		Config:      config,
   167  	})
   168  	if err != nil {
   169  		t.Fatal(err)
   170  	}
   171  	defer l.Close()
   172  	for i := 0; i < 36; i++ {
   173  		if err := l.Log(&logger.Message{Line: []byte("line" + strconv.Itoa(i)), Source: "src1"}); err != nil {
   174  			t.Fatal(err)
   175  		}
   176  	}
   177  
   178  	res, err := os.ReadFile(filename)
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	penUlt, err := os.ReadFile(filename + ".1")
   184  	if err != nil {
   185  		if !os.IsNotExist(err) {
   186  			t.Fatal(err)
   187  		}
   188  
   189  		file, err := os.Open(filename + ".1.gz")
   190  		if err != nil {
   191  			t.Fatal(err)
   192  		}
   193  		defer file.Close()
   194  		zipReader, err := gzip.NewReader(file)
   195  		if err != nil {
   196  			t.Fatal(err)
   197  		}
   198  		defer zipReader.Close()
   199  		penUlt, err = io.ReadAll(zipReader)
   200  		if err != nil {
   201  			t.Fatal(err)
   202  		}
   203  	}
   204  
   205  	file, err := os.Open(filename + ".2.gz")
   206  	if err != nil {
   207  		t.Fatal(err)
   208  	}
   209  	defer file.Close()
   210  	zipReader, err := gzip.NewReader(file)
   211  	if err != nil {
   212  		t.Fatal(err)
   213  	}
   214  	defer zipReader.Close()
   215  	antepenult, err := io.ReadAll(zipReader)
   216  	if err != nil {
   217  		t.Fatal(err)
   218  	}
   219  
   220  	expectedAntepenultimate := `{"log":"line0\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   221  {"log":"line1\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   222  {"log":"line2\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   223  {"log":"line3\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   224  {"log":"line4\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   225  {"log":"line5\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   226  {"log":"line6\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   227  {"log":"line7\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   228  {"log":"line8\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   229  {"log":"line9\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   230  {"log":"line10\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   231  {"log":"line11\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   232  {"log":"line12\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   233  {"log":"line13\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   234  {"log":"line14\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   235  {"log":"line15\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   236  `
   237  	expectedPenultimate := `{"log":"line16\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   238  {"log":"line17\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   239  {"log":"line18\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   240  {"log":"line19\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   241  {"log":"line20\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   242  {"log":"line21\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   243  {"log":"line22\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   244  {"log":"line23\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   245  {"log":"line24\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   246  {"log":"line25\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   247  {"log":"line26\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   248  {"log":"line27\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   249  {"log":"line28\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   250  {"log":"line29\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   251  {"log":"line30\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   252  {"log":"line31\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   253  `
   254  	expected := `{"log":"line32\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   255  {"log":"line33\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   256  {"log":"line34\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   257  {"log":"line35\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
   258  `
   259  
   260  	if string(res) != expected {
   261  		t.Fatalf("Wrong log content: %q, expected %q", res, expected)
   262  	}
   263  	if string(penUlt) != expectedPenultimate {
   264  		t.Fatalf("Wrong log content: %q, expected %q", penUlt, expectedPenultimate)
   265  	}
   266  	if string(antepenult) != expectedAntepenultimate {
   267  		t.Fatalf("Wrong log content: %q, expected %q", antepenult, expectedAntepenultimate)
   268  	}
   269  }
   270  
   271  func TestJSONFileLoggerWithLabelsEnv(t *testing.T) {
   272  	cid := "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657"
   273  	tmp, err := os.MkdirTemp("", "docker-logger-")
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  	defer os.RemoveAll(tmp)
   278  	filename := filepath.Join(tmp, "container.log")
   279  	config := map[string]string{"labels": "rack,dc", "labels-regex": "^loc", "env": "environ,debug,ssl", "env-regex": "^dc"}
   280  	l, err := New(logger.Info{
   281  		ContainerID:     cid,
   282  		LogPath:         filename,
   283  		Config:          config,
   284  		ContainerLabels: map[string]string{"rack": "101", "dc": "lhr", "location": "here"},
   285  		ContainerEnv:    []string{"environ=production", "debug=false", "port=10001", "ssl=true", "dc_region=west"},
   286  	})
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	defer l.Close()
   291  	if err := l.Log(&logger.Message{Line: []byte("line"), Source: "src1"}); err != nil {
   292  		t.Fatal(err)
   293  	}
   294  	res, err := os.ReadFile(filename)
   295  	if err != nil {
   296  		t.Fatal(err)
   297  	}
   298  
   299  	var jsonLog jsonlog.JSONLogs
   300  	if err := json.Unmarshal(res, &jsonLog); err != nil {
   301  		t.Fatal(err)
   302  	}
   303  	extra := make(map[string]string)
   304  	if err := json.Unmarshal(jsonLog.RawAttrs, &extra); err != nil {
   305  		t.Fatal(err)
   306  	}
   307  	expected := map[string]string{
   308  		"rack":      "101",
   309  		"dc":        "lhr",
   310  		"location":  "here",
   311  		"environ":   "production",
   312  		"debug":     "false",
   313  		"ssl":       "true",
   314  		"dc_region": "west",
   315  	}
   316  	if !reflect.DeepEqual(extra, expected) {
   317  		t.Fatalf("Wrong log attrs: %q, expected %q", extra, expected)
   318  	}
   319  }