github.com/boomhut/fiber/v2@v2.0.0-20230603160335-b65c856e57d3/middleware/logger/logger_test.go (about) 1 //nolint:bodyclose // Much easier to just ignore memory leaks in tests 2 package logger 3 4 import ( 5 "bufio" 6 "bytes" 7 "errors" 8 "fmt" 9 "io" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "sync" 14 "testing" 15 "time" 16 17 "github.com/boomhut/fiber/v2" 18 "github.com/boomhut/fiber/v2/middleware/requestid" 19 "github.com/boomhut/fiber/v2/utils" 20 21 "github.com/valyala/bytebufferpool" 22 "github.com/valyala/fasthttp" 23 ) 24 25 // go test -run Test_Logger 26 func Test_Logger(t *testing.T) { 27 t.Parallel() 28 app := fiber.New() 29 30 buf := bytebufferpool.Get() 31 defer bytebufferpool.Put(buf) 32 33 app.Use(New(Config{ 34 Format: "${error}", 35 Output: buf, 36 })) 37 38 app.Get("/", func(c *fiber.Ctx) error { 39 return errors.New("some random error") 40 }) 41 42 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 43 utils.AssertEqual(t, nil, err) 44 utils.AssertEqual(t, fiber.StatusInternalServerError, resp.StatusCode) 45 utils.AssertEqual(t, "some random error", buf.String()) 46 } 47 48 // go test -run Test_Logger_locals 49 func Test_Logger_locals(t *testing.T) { 50 t.Parallel() 51 app := fiber.New() 52 53 buf := bytebufferpool.Get() 54 defer bytebufferpool.Put(buf) 55 56 app.Use(New(Config{ 57 Format: "${locals:demo}", 58 Output: buf, 59 })) 60 61 app.Get("/", func(c *fiber.Ctx) error { 62 c.Locals("demo", "johndoe") 63 return c.SendStatus(fiber.StatusOK) 64 }) 65 66 app.Get("/int", func(c *fiber.Ctx) error { 67 c.Locals("demo", 55) 68 return c.SendStatus(fiber.StatusOK) 69 }) 70 71 app.Get("/empty", func(c *fiber.Ctx) error { 72 return c.SendStatus(fiber.StatusOK) 73 }) 74 75 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 76 utils.AssertEqual(t, nil, err) 77 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 78 utils.AssertEqual(t, "johndoe", buf.String()) 79 80 buf.Reset() 81 82 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/int", nil)) 83 utils.AssertEqual(t, nil, err) 84 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 85 utils.AssertEqual(t, "55", buf.String()) 86 87 buf.Reset() 88 89 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/empty", nil)) 90 utils.AssertEqual(t, nil, err) 91 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 92 utils.AssertEqual(t, "", buf.String()) 93 } 94 95 // go test -run Test_Logger_Next 96 func Test_Logger_Next(t *testing.T) { 97 t.Parallel() 98 app := fiber.New() 99 app.Use(New(Config{ 100 Next: func(_ *fiber.Ctx) bool { 101 return true 102 }, 103 })) 104 105 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 106 utils.AssertEqual(t, nil, err) 107 utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode) 108 } 109 110 // go test -run Test_Logger_Done 111 func Test_Logger_Done(t *testing.T) { 112 t.Parallel() 113 buf := bytes.NewBuffer(nil) 114 app := fiber.New() 115 app.Use(New(Config{ 116 Done: func(c *fiber.Ctx, logString []byte) { 117 if c.Response().StatusCode() == fiber.StatusOK { 118 _, err := buf.Write(logString) 119 utils.AssertEqual(t, nil, err) 120 } 121 }, 122 })).Get("/logging", func(ctx *fiber.Ctx) error { 123 return ctx.SendStatus(fiber.StatusOK) 124 }) 125 126 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/logging", nil)) 127 utils.AssertEqual(t, nil, err) 128 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 129 utils.AssertEqual(t, true, buf.Len() > 0) 130 } 131 132 // go test -run Test_Logger_ErrorTimeZone 133 func Test_Logger_ErrorTimeZone(t *testing.T) { 134 t.Parallel() 135 app := fiber.New() 136 app.Use(New(Config{ 137 TimeZone: "invalid", 138 })) 139 140 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 141 utils.AssertEqual(t, nil, err) 142 utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode) 143 } 144 145 type fakeOutput int 146 147 func (o *fakeOutput) Write([]byte) (int, error) { 148 *o++ 149 return 0, errors.New("fake output") 150 } 151 152 // go test -run Test_Logger_ErrorOutput 153 func Test_Logger_ErrorOutput(t *testing.T) { 154 t.Parallel() 155 o := new(fakeOutput) 156 app := fiber.New() 157 app.Use(New(Config{ 158 Output: o, 159 })) 160 161 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 162 utils.AssertEqual(t, nil, err) 163 utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode) 164 165 utils.AssertEqual(t, 2, int(*o)) 166 } 167 168 // go test -run Test_Logger_All 169 func Test_Logger_All(t *testing.T) { 170 t.Parallel() 171 buf := bytebufferpool.Get() 172 defer bytebufferpool.Put(buf) 173 174 app := fiber.New() 175 app.Use(New(Config{ 176 Format: "${pid}${reqHeaders}${referer}${protocol}${ip}${ips}${host}${url}${ua}${body}${route}${black}${red}${green}${yellow}${blue}${magenta}${cyan}${white}${reset}${error}${header:test}${query:test}${form:test}${cookie:test}${non}", 177 Output: buf, 178 })) 179 180 // Alias colors 181 colors := app.Config().ColorScheme 182 183 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/?foo=bar", nil)) 184 utils.AssertEqual(t, nil, err) 185 utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode) 186 187 expected := fmt.Sprintf("%dHost=example.comhttp0.0.0.0example.com/?foo=bar/%s%s%s%s%s%s%s%s%sCannot GET /", os.Getpid(), colors.Black, colors.Red, colors.Green, colors.Yellow, colors.Blue, colors.Magenta, colors.Cyan, colors.White, colors.Reset) 188 utils.AssertEqual(t, expected, buf.String()) 189 } 190 191 // go test -run Test_Query_Params 192 func Test_Query_Params(t *testing.T) { 193 t.Parallel() 194 buf := bytebufferpool.Get() 195 defer bytebufferpool.Put(buf) 196 197 app := fiber.New() 198 app.Use(New(Config{ 199 Format: "${queryParams}", 200 Output: buf, 201 })) 202 203 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/?foo=bar&baz=moz", nil)) 204 utils.AssertEqual(t, nil, err) 205 utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode) 206 207 expected := "foo=bar&baz=moz" 208 utils.AssertEqual(t, expected, buf.String()) 209 } 210 211 // go test -run Test_Response_Body 212 func Test_Response_Body(t *testing.T) { 213 t.Parallel() 214 buf := bytebufferpool.Get() 215 defer bytebufferpool.Put(buf) 216 217 app := fiber.New() 218 app.Use(New(Config{ 219 Format: "${resBody}", 220 Output: buf, 221 })) 222 223 app.Get("/", func(c *fiber.Ctx) error { 224 return c.SendString("Sample response body") 225 }) 226 227 app.Post("/test", func(c *fiber.Ctx) error { 228 return c.Send([]byte("Post in test")) 229 }) 230 231 _, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 232 utils.AssertEqual(t, nil, err) 233 234 expectedGetResponse := "Sample response body" 235 utils.AssertEqual(t, expectedGetResponse, buf.String()) 236 237 buf.Reset() // Reset buffer to test POST 238 239 _, err = app.Test(httptest.NewRequest(fiber.MethodPost, "/test", nil)) 240 utils.AssertEqual(t, nil, err) 241 242 expectedPostResponse := "Post in test" 243 utils.AssertEqual(t, expectedPostResponse, buf.String()) 244 } 245 246 // go test -run Test_Logger_AppendUint 247 func Test_Logger_AppendUint(t *testing.T) { 248 t.Parallel() 249 app := fiber.New() 250 251 buf := bytebufferpool.Get() 252 defer bytebufferpool.Put(buf) 253 254 app.Use(New(Config{ 255 Format: "${bytesReceived} ${bytesSent} ${status}", 256 Output: buf, 257 })) 258 259 app.Get("/", func(c *fiber.Ctx) error { 260 return c.SendString("hello") 261 }) 262 263 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 264 utils.AssertEqual(t, nil, err) 265 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 266 utils.AssertEqual(t, "0 5 200", buf.String()) 267 } 268 269 // go test -run Test_Logger_Data_Race -race 270 func Test_Logger_Data_Race(t *testing.T) { 271 t.Parallel() 272 app := fiber.New() 273 274 buf := bytebufferpool.Get() 275 defer bytebufferpool.Put(buf) 276 277 app.Use(New(ConfigDefault)) 278 app.Use(New(Config{ 279 Format: "${time} | ${pid} | ${locals:requestid} | ${status} | ${latency} | ${method} | ${path}\n", 280 })) 281 282 app.Get("/", func(c *fiber.Ctx) error { 283 return c.SendString("hello") 284 }) 285 286 var ( 287 resp1, resp2 *http.Response 288 err1, err2 error 289 ) 290 wg := &sync.WaitGroup{} 291 wg.Add(1) 292 go func() { 293 resp1, err1 = app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 294 wg.Done() 295 }() 296 resp2, err2 = app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 297 wg.Wait() 298 utils.AssertEqual(t, nil, err1) 299 utils.AssertEqual(t, fiber.StatusOK, resp1.StatusCode) 300 utils.AssertEqual(t, nil, err2) 301 utils.AssertEqual(t, fiber.StatusOK, resp2.StatusCode) 302 } 303 304 // go test -v -run=^$ -bench=Benchmark_Logger -benchmem -count=4 305 func Benchmark_Logger(b *testing.B) { 306 benchSetup := func(b *testing.B, app *fiber.App) { 307 b.Helper() 308 309 h := app.Handler() 310 311 fctx := &fasthttp.RequestCtx{} 312 fctx.Request.Header.SetMethod(fiber.MethodGet) 313 fctx.Request.SetRequestURI("/") 314 315 b.ReportAllocs() 316 b.ResetTimer() 317 318 for n := 0; n < b.N; n++ { 319 h(fctx) 320 } 321 322 utils.AssertEqual(b, 200, fctx.Response.Header.StatusCode()) 323 } 324 325 b.Run("Base", func(bb *testing.B) { 326 app := fiber.New() 327 app.Use(New(Config{ 328 Format: "${bytesReceived} ${bytesSent} ${status}", 329 Output: io.Discard, 330 })) 331 app.Get("/", func(c *fiber.Ctx) error { 332 c.Set("test", "test") 333 return c.SendString("Hello, World!") 334 }) 335 benchSetup(bb, app) 336 }) 337 338 b.Run("DefaultFormat", func(bb *testing.B) { 339 app := fiber.New() 340 app.Use(New(Config{ 341 Output: io.Discard, 342 })) 343 app.Get("/", func(c *fiber.Ctx) error { 344 return c.SendString("Hello, World!") 345 }) 346 benchSetup(bb, app) 347 }) 348 349 b.Run("WithTagParameter", func(bb *testing.B) { 350 app := fiber.New() 351 app.Use(New(Config{ 352 Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}", 353 Output: io.Discard, 354 })) 355 app.Get("/", func(c *fiber.Ctx) error { 356 c.Set("test", "test") 357 return c.SendString("Hello, World!") 358 }) 359 benchSetup(bb, app) 360 }) 361 } 362 363 // go test -run Test_Response_Header 364 func Test_Response_Header(t *testing.T) { 365 t.Parallel() 366 buf := bytebufferpool.Get() 367 defer bytebufferpool.Put(buf) 368 369 app := fiber.New() 370 app.Use(requestid.New(requestid.Config{ 371 Next: nil, 372 Header: fiber.HeaderXRequestID, 373 Generator: func() string { return "Hello fiber!" }, 374 ContextKey: "requestid", 375 })) 376 app.Use(New(Config{ 377 Format: "${respHeader:X-Request-ID}", 378 Output: buf, 379 })) 380 app.Get("/", func(c *fiber.Ctx) error { 381 return c.SendString("Hello fiber!") 382 }) 383 384 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 385 utils.AssertEqual(t, nil, err) 386 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 387 utils.AssertEqual(t, "Hello fiber!", buf.String()) 388 } 389 390 // go test -run Test_Req_Header 391 func Test_Req_Header(t *testing.T) { 392 t.Parallel() 393 buf := bytebufferpool.Get() 394 defer bytebufferpool.Put(buf) 395 396 app := fiber.New() 397 app.Use(New(Config{ 398 Format: "${header:test}", 399 Output: buf, 400 })) 401 app.Get("/", func(c *fiber.Ctx) error { 402 return c.SendString("Hello fiber!") 403 }) 404 headerReq := httptest.NewRequest(fiber.MethodGet, "/", nil) 405 headerReq.Header.Add("test", "Hello fiber!") 406 407 resp, err := app.Test(headerReq) 408 utils.AssertEqual(t, nil, err) 409 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 410 utils.AssertEqual(t, "Hello fiber!", buf.String()) 411 } 412 413 // go test -run Test_ReqHeader_Header 414 func Test_ReqHeader_Header(t *testing.T) { 415 t.Parallel() 416 buf := bytebufferpool.Get() 417 defer bytebufferpool.Put(buf) 418 419 app := fiber.New() 420 app.Use(New(Config{ 421 Format: "${reqHeader:test}", 422 Output: buf, 423 })) 424 app.Get("/", func(c *fiber.Ctx) error { 425 return c.SendString("Hello fiber!") 426 }) 427 reqHeaderReq := httptest.NewRequest(fiber.MethodGet, "/", nil) 428 reqHeaderReq.Header.Add("test", "Hello fiber!") 429 430 resp, err := app.Test(reqHeaderReq) 431 utils.AssertEqual(t, nil, err) 432 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 433 utils.AssertEqual(t, "Hello fiber!", buf.String()) 434 } 435 436 // go test -run Test_CustomTags 437 func Test_CustomTags(t *testing.T) { 438 t.Parallel() 439 customTag := "it is a custom tag" 440 441 buf := bytebufferpool.Get() 442 defer bytebufferpool.Put(buf) 443 444 app := fiber.New() 445 app.Use(New(Config{ 446 Format: "${custom_tag}", 447 CustomTags: map[string]LogFunc{ 448 "custom_tag": func(output Buffer, c *fiber.Ctx, data *Data, extraParam string) (int, error) { 449 return output.WriteString(customTag) 450 }, 451 }, 452 Output: buf, 453 })) 454 app.Get("/", func(c *fiber.Ctx) error { 455 return c.SendString("Hello fiber!") 456 }) 457 reqHeaderReq := httptest.NewRequest(fiber.MethodGet, "/", nil) 458 reqHeaderReq.Header.Add("test", "Hello fiber!") 459 460 resp, err := app.Test(reqHeaderReq) 461 utils.AssertEqual(t, nil, err) 462 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 463 utils.AssertEqual(t, customTag, buf.String()) 464 } 465 466 // go test -run Test_Logger_ByteSent_Streaming 467 func Test_Logger_ByteSent_Streaming(t *testing.T) { 468 t.Parallel() 469 app := fiber.New() 470 471 buf := bytebufferpool.Get() 472 defer bytebufferpool.Put(buf) 473 474 app.Use(New(Config{ 475 Format: "${bytesReceived} ${bytesSent} ${status}", 476 Output: buf, 477 })) 478 479 app.Get("/", func(c *fiber.Ctx) error { 480 c.Set("Connection", "keep-alive") 481 c.Set("Transfer-Encoding", "chunked") 482 c.Context().SetBodyStreamWriter(func(w *bufio.Writer) { 483 var i int 484 for { 485 i++ 486 msg := fmt.Sprintf("%d - the time is %v", i, time.Now()) 487 fmt.Fprintf(w, "data: Message: %s\n\n", msg) 488 err := w.Flush() 489 if err != nil { 490 break 491 } 492 if i == 10 { 493 break 494 } 495 } 496 }) 497 return nil 498 }) 499 500 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 501 utils.AssertEqual(t, nil, err) 502 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 503 utils.AssertEqual(t, "0 0 200", buf.String()) 504 }