1
2
3
4 package hlog
5
6 import (
7 "bytes"
8 "context"
9 "fmt"
10 "io/ioutil"
11 "net/http"
12 "net/http/httptest"
13 "net/url"
14 "reflect"
15 "testing"
16
17 "github.com/rs/xid"
18 "github.com/rs/zerolog"
19 "github.com/rs/zerolog/internal/cbor"
20 )
21
22 func decodeIfBinary(out *bytes.Buffer) string {
23 p := out.Bytes()
24 if len(p) == 0 || p[0] < 0x7F {
25 return out.String()
26 }
27 return cbor.DecodeObjectToStr(p) + "\n"
28 }
29
30 func TestNewHandler(t *testing.T) {
31 log := zerolog.New(nil).With().
32 Str("foo", "bar").
33 Logger()
34 lh := NewHandler(log)
35 h := lh(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
36 l := FromRequest(r)
37 if !reflect.DeepEqual(*l, log) {
38 t.Fail()
39 }
40 }))
41 h.ServeHTTP(nil, &http.Request{})
42 }
43
44 func TestURLHandler(t *testing.T) {
45 out := &bytes.Buffer{}
46 r := &http.Request{
47 URL: &url.URL{Path: "/path", RawQuery: "foo=bar"},
48 }
49 h := URLHandler("url")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
50 l := FromRequest(r)
51 l.Log().Msg("")
52 }))
53 h = NewHandler(zerolog.New(out))(h)
54 h.ServeHTTP(nil, r)
55 if want, got := `{"url":"/path?foo=bar"}`+"\n", decodeIfBinary(out); want != got {
56 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
57 }
58 }
59
60 func TestMethodHandler(t *testing.T) {
61 out := &bytes.Buffer{}
62 r := &http.Request{
63 Method: "POST",
64 }
65 h := MethodHandler("method")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
66 l := FromRequest(r)
67 l.Log().Msg("")
68 }))
69 h = NewHandler(zerolog.New(out))(h)
70 h.ServeHTTP(nil, r)
71 if want, got := `{"method":"POST"}`+"\n", decodeIfBinary(out); want != got {
72 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
73 }
74 }
75
76 func TestRequestHandler(t *testing.T) {
77 out := &bytes.Buffer{}
78 r := &http.Request{
79 Method: "POST",
80 URL: &url.URL{Path: "/path", RawQuery: "foo=bar"},
81 }
82 h := RequestHandler("request")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
83 l := FromRequest(r)
84 l.Log().Msg("")
85 }))
86 h = NewHandler(zerolog.New(out))(h)
87 h.ServeHTTP(nil, r)
88 if want, got := `{"request":"POST /path?foo=bar"}`+"\n", decodeIfBinary(out); want != got {
89 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
90 }
91 }
92
93 func TestRemoteAddrHandler(t *testing.T) {
94 out := &bytes.Buffer{}
95 r := &http.Request{
96 RemoteAddr: "1.2.3.4:1234",
97 }
98 h := RemoteAddrHandler("ip")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
99 l := FromRequest(r)
100 l.Log().Msg("")
101 }))
102 h = NewHandler(zerolog.New(out))(h)
103 h.ServeHTTP(nil, r)
104 if want, got := `{"ip":"1.2.3.4:1234"}`+"\n", decodeIfBinary(out); want != got {
105 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
106 }
107 }
108
109 func TestRemoteAddrHandlerIPv6(t *testing.T) {
110 out := &bytes.Buffer{}
111 r := &http.Request{
112 RemoteAddr: "[2001:db8:a0b:12f0::1]:1234",
113 }
114 h := RemoteAddrHandler("ip")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
115 l := FromRequest(r)
116 l.Log().Msg("")
117 }))
118 h = NewHandler(zerolog.New(out))(h)
119 h.ServeHTTP(nil, r)
120 if want, got := `{"ip":"[2001:db8:a0b:12f0::1]:1234"}`+"\n", decodeIfBinary(out); want != got {
121 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
122 }
123 }
124
125 func TestUserAgentHandler(t *testing.T) {
126 out := &bytes.Buffer{}
127 r := &http.Request{
128 Header: http.Header{
129 "User-Agent": []string{"some user agent string"},
130 },
131 }
132 h := UserAgentHandler("ua")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
133 l := FromRequest(r)
134 l.Log().Msg("")
135 }))
136 h = NewHandler(zerolog.New(out))(h)
137 h.ServeHTTP(nil, r)
138 if want, got := `{"ua":"some user agent string"}`+"\n", decodeIfBinary(out); want != got {
139 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
140 }
141 }
142
143 func TestRefererHandler(t *testing.T) {
144 out := &bytes.Buffer{}
145 r := &http.Request{
146 Header: http.Header{
147 "Referer": []string{"http://foo.com/bar"},
148 },
149 }
150 h := RefererHandler("referer")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
151 l := FromRequest(r)
152 l.Log().Msg("")
153 }))
154 h = NewHandler(zerolog.New(out))(h)
155 h.ServeHTTP(nil, r)
156 if want, got := `{"referer":"http://foo.com/bar"}`+"\n", decodeIfBinary(out); want != got {
157 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
158 }
159 }
160
161 func TestRequestIDHandler(t *testing.T) {
162 out := &bytes.Buffer{}
163 r := &http.Request{
164 Header: http.Header{
165 "Referer": []string{"http://foo.com/bar"},
166 },
167 }
168 h := RequestIDHandler("id", "Request-Id")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
169 id, ok := IDFromRequest(r)
170 if !ok {
171 t.Fatal("Missing id in request")
172 }
173 if want, got := id.String(), w.Header().Get("Request-Id"); got != want {
174 t.Errorf("Invalid Request-Id header, got: %s, want: %s", got, want)
175 }
176 l := FromRequest(r)
177 l.Log().Msg("")
178 if want, got := fmt.Sprintf(`{"id":"%s"}`+"\n", id), decodeIfBinary(out); want != got {
179 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
180 }
181 }))
182 h = NewHandler(zerolog.New(out))(h)
183 h.ServeHTTP(httptest.NewRecorder(), r)
184 }
185
186 func TestCustomHeaderHandler(t *testing.T) {
187 out := &bytes.Buffer{}
188 r := &http.Request{
189 Header: http.Header{
190 "X-Request-Id": []string{"514bbe5bb5251c92bd07a9846f4a1ab6"},
191 },
192 }
193 h := CustomHeaderHandler("reqID", "X-Request-Id")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
194 l := FromRequest(r)
195 l.Log().Msg("")
196 }))
197 h = NewHandler(zerolog.New(out))(h)
198 h.ServeHTTP(nil, r)
199 if want, got := `{"reqID":"514bbe5bb5251c92bd07a9846f4a1ab6"}`+"\n", decodeIfBinary(out); want != got {
200 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
201 }
202 }
203
204 func TestProtoHandler(t *testing.T) {
205 out := &bytes.Buffer{}
206 r := &http.Request{
207 Proto: "test",
208 }
209 h := ProtoHandler("proto")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
210 l := FromRequest(r)
211 l.Log().Msg("")
212 }))
213 h = NewHandler(zerolog.New(out))(h)
214 h.ServeHTTP(nil, r)
215 if want, got := `{"proto":"test"}`+"\n", decodeIfBinary(out); want != got {
216 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
217 }
218 }
219
220 func TestCombinedHandlers(t *testing.T) {
221 out := &bytes.Buffer{}
222 r := &http.Request{
223 Method: "POST",
224 URL: &url.URL{Path: "/path", RawQuery: "foo=bar"},
225 }
226 h := MethodHandler("method")(RequestHandler("request")(URLHandler("url")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
227 l := FromRequest(r)
228 l.Log().Msg("")
229 }))))
230 h = NewHandler(zerolog.New(out))(h)
231 h.ServeHTTP(nil, r)
232 if want, got := `{"method":"POST","request":"POST /path?foo=bar","url":"/path?foo=bar"}`+"\n", decodeIfBinary(out); want != got {
233 t.Errorf("Invalid log output, got: %s, want: %s", got, want)
234 }
235 }
236
237 func BenchmarkHandlers(b *testing.B) {
238 r := &http.Request{
239 Method: "POST",
240 URL: &url.URL{Path: "/path", RawQuery: "foo=bar"},
241 }
242 h1 := URLHandler("url")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
243 l := FromRequest(r)
244 l.Log().Msg("")
245 }))
246 h2 := MethodHandler("method")(RequestHandler("request")(h1))
247 handlers := map[string]http.Handler{
248 "Single": NewHandler(zerolog.New(ioutil.Discard))(h1),
249 "Combined": NewHandler(zerolog.New(ioutil.Discard))(h2),
250 "SingleDisabled": NewHandler(zerolog.New(ioutil.Discard).Level(zerolog.Disabled))(h1),
251 "CombinedDisabled": NewHandler(zerolog.New(ioutil.Discard).Level(zerolog.Disabled))(h2),
252 }
253 for name := range handlers {
254 h := handlers[name]
255 b.Run(name, func(b *testing.B) {
256 for i := 0; i < b.N; i++ {
257 h.ServeHTTP(nil, r)
258 }
259 })
260 }
261 }
262
263 func BenchmarkDataRace(b *testing.B) {
264 log := zerolog.New(nil).With().
265 Str("foo", "bar").
266 Logger()
267 lh := NewHandler(log)
268 h := lh(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
269 l := FromRequest(r)
270 l.UpdateContext(func(c zerolog.Context) zerolog.Context {
271 return c.Str("bar", "baz")
272 })
273 l.Log().Msg("")
274 }))
275
276 b.RunParallel(func(pb *testing.PB) {
277 for pb.Next() {
278 h.ServeHTTP(nil, &http.Request{})
279 }
280 })
281 }
282
283 func TestCtxWithID(t *testing.T) {
284 ctx := context.Background()
285
286 id, _ := xid.FromString(`c0umremcie6smuu506pg`)
287
288 want := context.Background()
289 want = context.WithValue(want, idKey{}, id)
290
291 if got := CtxWithID(ctx, id); !reflect.DeepEqual(got, want) {
292 t.Errorf("CtxWithID() = %v, want %v", got, want)
293 }
294 }
295
View as plain text