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  }