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  }