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 }