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