1
2
3
4
5
6
7 package qlog
8
9 import (
10 "bytes"
11 "encoding/json"
12 "fmt"
13 "io"
14 "log/slog"
15 "reflect"
16 "testing"
17 "time"
18 )
19
20
21
22
23 func TestQLogHandlerEvents(t *testing.T) {
24 for _, test := range []struct {
25 name string
26 f func(*slog.Logger)
27 want []map[string]any
28 }{{
29 name: "various types",
30 f: func(log *slog.Logger) {
31 log.Info("message",
32 "bool", true,
33 "duration", time.Duration(1*time.Second),
34 "float", 0.0,
35 "int", 0,
36 "string", "value",
37 "uint", uint64(0),
38 slog.Group("group",
39 "a", 0,
40 ),
41 )
42 },
43 want: []map[string]any{{
44 "name": "message",
45 "data": map[string]any{
46 "bool": true,
47 "duration": float64(1000),
48 "float": float64(0.0),
49 "int": float64(0),
50 "string": "value",
51 "uint": float64(0),
52 "group": map[string]any{
53 "a": float64(0),
54 },
55 },
56 }},
57 }, {
58 name: "WithAttrs",
59 f: func(log *slog.Logger) {
60 log = log.With(
61 "with_a", "a",
62 "with_b", "b",
63 )
64 log.Info("m1", "field", "1")
65 log.Info("m2", "field", "2")
66 },
67 want: []map[string]any{{
68 "name": "m1",
69 "data": map[string]any{
70 "with_a": "a",
71 "with_b": "b",
72 "field": "1",
73 },
74 }, {
75 "name": "m2",
76 "data": map[string]any{
77 "with_a": "a",
78 "with_b": "b",
79 "field": "2",
80 },
81 }},
82 }, {
83 name: "WithGroup",
84 f: func(log *slog.Logger) {
85 log = log.With(
86 "with_a", "a",
87 "with_b", "b",
88 )
89 log.Info("m1", "field", "1")
90 log.Info("m2", "field", "2")
91 },
92 want: []map[string]any{{
93 "name": "m1",
94 "data": map[string]any{
95 "with_a": "a",
96 "with_b": "b",
97 "field": "1",
98 },
99 }, {
100 "name": "m2",
101 "data": map[string]any{
102 "with_a": "a",
103 "with_b": "b",
104 "field": "2",
105 },
106 }},
107 }} {
108 var out bytes.Buffer
109 opts := HandlerOptions{
110 Level: slog.LevelDebug,
111 NewTrace: func(TraceInfo) (io.WriteCloser, error) {
112 return nopCloseWriter{&out}, nil
113 },
114 }
115 h, err := newJSONTraceHandler(opts, []slog.Attr{
116 slog.String("group_id", "group"),
117 slog.Group("vantage_point",
118 slog.String("type", "client"),
119 ),
120 })
121 if err != nil {
122 t.Fatal(err)
123 }
124 log := slog.New(h)
125 test.f(log)
126 got := []map[string]any{}
127 for i, e := range bytes.Split(out.Bytes(), []byte{0x1e}) {
128
129
130 if i < 2 {
131 continue
132 }
133 var val map[string]any
134 if err := json.Unmarshal(e, &val); err != nil {
135 panic(fmt.Errorf("log unmarshal failure: %v\n%q", err, string(e)))
136 }
137 delete(val, "time")
138 got = append(got, val)
139 }
140 if !reflect.DeepEqual(got, test.want) {
141 t.Errorf("event mismatch\ngot: %v\nwant: %v", got, test.want)
142 }
143 }
144
145 }
146
147 type nopCloseWriter struct {
148 io.Writer
149 }
150
151 func (nopCloseWriter) Close() error { return nil }
152
View as plain text