github.com/nikandfor/tlog@v0.21.5-0.20231108111739-3ef89426a96d/convert/logfmt_test.go (about)

     1  package convert
     2  
     3  import (
     4  	"regexp"
     5  	"strings"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  
    11  	"github.com/nikandfor/tlog"
    12  	"github.com/nikandfor/tlog/low"
    13  	"github.com/nikandfor/tlog/tlwire"
    14  )
    15  
    16  func TestLogfmtSubObj(t *testing.T) {
    17  	testLogfmtObj(t, false)
    18  }
    19  
    20  func TestLogfmtFlatObj(t *testing.T) {
    21  	testLogfmtObj(t, true)
    22  }
    23  
    24  func testLogfmtObj(t *testing.T, flat bool) {
    25  	tm := time.Date(2020, time.December, 25, 22, 8, 13, 0, time.FixedZone("Europe/Moscow", int(3*time.Hour/time.Second)))
    26  
    27  	var b low.Buf
    28  
    29  	j := NewLogfmt(&b)
    30  	j.SubObjects = !flat
    31  	j.QuoteEmptyValue = true
    32  	j.TimeZone = time.FixedZone("MSK", int(3*time.Hour/time.Second))
    33  	j.TimeFormat = time.RFC3339Nano
    34  
    35  	l := tlog.New(j)
    36  
    37  	tlog.LoggerSetTimeNow(l, func() time.Time { return tm }, tm.UnixNano)
    38  
    39  	l.SetLabels(tlog.ParseLabels("a=b,c")...)
    40  
    41  	l.Printw("message", "str", "arg", "int", 5, "struct", struct {
    42  		A string `json:"a"`
    43  		B int    `tlog:"bb" yaml:"b"`
    44  		C *int   `tlog:"c,omitempty"`
    45  	}{
    46  		A: "A field",
    47  		B: 9,
    48  	})
    49  
    50  	exp := `_t="2020-12-25T22:08:13\+03:00"  _c="[\w./-]*logfmt_test.go:\d+"  _m=message  str=arg  int=5  struct={a="A field" bb=9}  a=b  c=""
    51  `
    52  	if flat {
    53  		exp = `_t="2020-12-25T22:08:13\+03:00"  _c="[\w./-]*logfmt_test.go:\d+"  _m=message  str=arg  int=5  struct.a="A field"  struct.bb=9  a=b  c=""
    54  `
    55  	}
    56  
    57  	exps := strings.Split(exp, "\n")
    58  	ls := strings.Split(string(b), "\n")
    59  	for i := 0; i < len(exps); i++ {
    60  		re := regexp.MustCompile("^" + exps[i] + "$")
    61  
    62  		var have string
    63  		if i < len(ls) {
    64  			have = ls[i]
    65  		}
    66  
    67  		assert.True(t, re.MatchString(have), "expected\n%s\ngot\n%s", exps[i], have)
    68  	}
    69  
    70  	for i := len(exps); i < len(ls); i++ {
    71  		assert.True(t, false, "expected\n%s\ngot\n%s", "", ls[i])
    72  	}
    73  }
    74  
    75  func TestLogfmtRename(t *testing.T) {
    76  	tm := time.Date(2020, time.December, 25, 22, 8, 13, 0, time.FixedZone("Europe/Moscow", int(3*time.Hour/time.Second)))
    77  
    78  	var b low.Buf
    79  
    80  	j := NewLogfmt(&b)
    81  	j.SubObjects = true
    82  	j.QuoteEmptyValue = true
    83  	j.TimeZone = time.FixedZone("MSK", int(3*time.Hour/time.Second))
    84  	j.TimeFormat = time.RFC3339Nano
    85  
    86  	renamer := simpleTestRenamer()
    87  
    88  	j.Rename = renamer.Rename
    89  
    90  	l := tlog.New(j)
    91  
    92  	tlog.LoggerSetTimeNow(l, func() time.Time { return tm }, tm.UnixNano)
    93  
    94  	l.SetLabels(tlog.ParseLabels("a=b,c")...)
    95  
    96  	l.Printw("message", "str", "arg", "int", 5, "struct", struct {
    97  		A string `json:"a"`
    98  		B int    `tlog:"bb" yaml:"b"`
    99  		C *int   `tlog:"c,omitempty"`
   100  	}{
   101  		A: "A field",
   102  		B: 9,
   103  	})
   104  
   105  	exp := `time="2020-12-25T22:08:13\+03:00"  caller="[\w./-]*logfmt_test.go:\d+"  message=message  str_key=arg  int=5  struct={a="A field" bb=9}  L_a=b  L_c=""
   106  `
   107  
   108  	exps := strings.Split(exp, "\n")
   109  	ls := strings.Split(string(b), "\n")
   110  	for i := 0; i < len(exps); i++ {
   111  		re := regexp.MustCompile("^" + exps[i] + "$")
   112  
   113  		var have string
   114  		if i < len(ls) {
   115  			have = ls[i]
   116  		}
   117  
   118  		assert.True(t, re.MatchString(have), "expected\n%s\ngot\n%s", exps[i], have)
   119  	}
   120  
   121  	for i := len(exps); i < len(ls); i++ {
   122  		assert.True(t, false, "expected\n%s\ngot\n%s", "", ls[i])
   123  	}
   124  }
   125  
   126  func TestLogfmtKeyWithSpace(t *testing.T) {
   127  	var b low.Buf
   128  
   129  	j := NewLogfmt(&b)
   130  	j.QuoteEmptyValue = true
   131  
   132  	_, err := j.Write(tlog.AppendKVs(nil, []interface{}{tlog.RawTag(tlwire.Map, 1), "key with spaces", "value"}))
   133  	assert.NoError(t, err)
   134  	assert.Equal(t, `"key with spaces"=value`+"\n", string(b))
   135  }
   136  
   137  func simpleTestRenamer() SimpleRenamer {
   138  	return SimpleRenamer{
   139  		Rules: map[string]SimpleRenameRule{
   140  			tlog.KeyEventKind: {Tags: []TagSub{{tlwire.Semantic, tlog.WireEventKind}}, Key: "kind"},
   141  			tlog.KeyTimestamp: {Tags: []TagSub{{tlwire.Semantic, tlwire.Time}}, Key: "time"},
   142  			tlog.KeyCaller:    {Tags: []TagSub{{tlwire.Semantic, tlwire.Caller}}, Key: "caller"},
   143  			tlog.KeyMessage:   {Tags: []TagSub{{tlwire.Semantic, tlog.WireMessage}}, Key: "message"},
   144  
   145  			"str": {Tags: []TagSub{{Tag: tlwire.String}}, Key: "str_key"},
   146  		},
   147  		Fallback: func(b, p, k []byte, i int) ([]byte, bool) {
   148  			var d tlwire.Decoder
   149  
   150  			tag, sub, _ := d.Tag(p, i)
   151  
   152  			if tag != tlwire.Semantic || sub != tlog.WireLabel {
   153  				return b, false
   154  			}
   155  
   156  			b = append(b, "L_"...)
   157  			b = append(b, k...)
   158  
   159  			return b, true
   160  		},
   161  	}
   162  }