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