github.com/gofiber/fiber/v2@v2.47.0/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/gofiber/fiber/v2"
    18  	"github.com/gofiber/fiber/v2/middleware/requestid"
    19  	"github.com/gofiber/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_WithoutColor
   153  func Test_Logger_ErrorOutput_WithoutColor(t *testing.T) {
   154  	t.Parallel()
   155  	o := new(fakeOutput)
   156  	app := fiber.New()
   157  	app.Use(New(Config{
   158  		Output:        o,
   159  		DisableColors: true,
   160  	}))
   161  
   162  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   163  	utils.AssertEqual(t, nil, err)
   164  	utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
   165  
   166  	utils.AssertEqual(t, 1, int(*o))
   167  }
   168  
   169  // go test -run Test_Logger_ErrorOutput
   170  func Test_Logger_ErrorOutput(t *testing.T) {
   171  	t.Parallel()
   172  	o := new(fakeOutput)
   173  	app := fiber.New()
   174  	app.Use(New(Config{
   175  		Output: o,
   176  	}))
   177  
   178  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   179  	utils.AssertEqual(t, nil, err)
   180  	utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
   181  
   182  	utils.AssertEqual(t, 1, int(*o))
   183  }
   184  
   185  // go test -run Test_Logger_All
   186  func Test_Logger_All(t *testing.T) {
   187  	t.Parallel()
   188  	buf := bytebufferpool.Get()
   189  	defer bytebufferpool.Put(buf)
   190  
   191  	app := fiber.New()
   192  	app.Use(New(Config{
   193  		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}",
   194  		Output: buf,
   195  	}))
   196  
   197  	// Alias colors
   198  	colors := app.Config().ColorScheme
   199  
   200  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/?foo=bar", nil))
   201  	utils.AssertEqual(t, nil, err)
   202  	utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
   203  
   204  	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)
   205  	utils.AssertEqual(t, expected, buf.String())
   206  }
   207  
   208  // go test -run Test_Query_Params
   209  func Test_Query_Params(t *testing.T) {
   210  	t.Parallel()
   211  	buf := bytebufferpool.Get()
   212  	defer bytebufferpool.Put(buf)
   213  
   214  	app := fiber.New()
   215  	app.Use(New(Config{
   216  		Format: "${queryParams}",
   217  		Output: buf,
   218  	}))
   219  
   220  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/?foo=bar&baz=moz", nil))
   221  	utils.AssertEqual(t, nil, err)
   222  	utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
   223  
   224  	expected := "foo=bar&baz=moz"
   225  	utils.AssertEqual(t, expected, buf.String())
   226  }
   227  
   228  // go test -run Test_Response_Body
   229  func Test_Response_Body(t *testing.T) {
   230  	t.Parallel()
   231  	buf := bytebufferpool.Get()
   232  	defer bytebufferpool.Put(buf)
   233  
   234  	app := fiber.New()
   235  	app.Use(New(Config{
   236  		Format: "${resBody}",
   237  		Output: buf,
   238  	}))
   239  
   240  	app.Get("/", func(c *fiber.Ctx) error {
   241  		return c.SendString("Sample response body")
   242  	})
   243  
   244  	app.Post("/test", func(c *fiber.Ctx) error {
   245  		return c.Send([]byte("Post in test"))
   246  	})
   247  
   248  	_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   249  	utils.AssertEqual(t, nil, err)
   250  
   251  	expectedGetResponse := "Sample response body"
   252  	utils.AssertEqual(t, expectedGetResponse, buf.String())
   253  
   254  	buf.Reset() // Reset buffer to test POST
   255  
   256  	_, err = app.Test(httptest.NewRequest(fiber.MethodPost, "/test", nil))
   257  	utils.AssertEqual(t, nil, err)
   258  
   259  	expectedPostResponse := "Post in test"
   260  	utils.AssertEqual(t, expectedPostResponse, buf.String())
   261  }
   262  
   263  // go test -run Test_Logger_AppendUint
   264  func Test_Logger_AppendUint(t *testing.T) {
   265  	t.Parallel()
   266  	app := fiber.New()
   267  
   268  	buf := bytebufferpool.Get()
   269  	defer bytebufferpool.Put(buf)
   270  
   271  	app.Use(New(Config{
   272  		Format: "${bytesReceived} ${bytesSent} ${status}",
   273  		Output: buf,
   274  	}))
   275  
   276  	app.Get("/", func(c *fiber.Ctx) error {
   277  		return c.SendString("hello")
   278  	})
   279  
   280  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   281  	utils.AssertEqual(t, nil, err)
   282  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   283  	utils.AssertEqual(t, "0 5 200", buf.String())
   284  }
   285  
   286  // go test -run Test_Logger_Data_Race -race
   287  func Test_Logger_Data_Race(t *testing.T) {
   288  	t.Parallel()
   289  	app := fiber.New()
   290  
   291  	buf := bytebufferpool.Get()
   292  	defer bytebufferpool.Put(buf)
   293  
   294  	app.Use(New(ConfigDefault))
   295  	app.Use(New(Config{
   296  		Format: "${time} | ${pid} | ${locals:requestid} | ${status} | ${latency} | ${method} | ${path}\n",
   297  	}))
   298  
   299  	app.Get("/", func(c *fiber.Ctx) error {
   300  		return c.SendString("hello")
   301  	})
   302  
   303  	var (
   304  		resp1, resp2 *http.Response
   305  		err1, err2   error
   306  	)
   307  	wg := &sync.WaitGroup{}
   308  	wg.Add(1)
   309  	go func() {
   310  		resp1, err1 = app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   311  		wg.Done()
   312  	}()
   313  	resp2, err2 = app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   314  	wg.Wait()
   315  	utils.AssertEqual(t, nil, err1)
   316  	utils.AssertEqual(t, fiber.StatusOK, resp1.StatusCode)
   317  	utils.AssertEqual(t, nil, err2)
   318  	utils.AssertEqual(t, fiber.StatusOK, resp2.StatusCode)
   319  }
   320  
   321  // go test -v -run=^$ -bench=Benchmark_Logger -benchmem -count=4
   322  func Benchmark_Logger(b *testing.B) {
   323  	benchSetup := func(b *testing.B, app *fiber.App) {
   324  		b.Helper()
   325  
   326  		h := app.Handler()
   327  
   328  		fctx := &fasthttp.RequestCtx{}
   329  		fctx.Request.Header.SetMethod(fiber.MethodGet)
   330  		fctx.Request.SetRequestURI("/")
   331  
   332  		b.ReportAllocs()
   333  		b.ResetTimer()
   334  
   335  		for n := 0; n < b.N; n++ {
   336  			h(fctx)
   337  		}
   338  
   339  		utils.AssertEqual(b, 200, fctx.Response.Header.StatusCode())
   340  	}
   341  
   342  	b.Run("Base", func(bb *testing.B) {
   343  		app := fiber.New()
   344  		app.Use(New(Config{
   345  			Format: "${bytesReceived} ${bytesSent} ${status}",
   346  			Output: io.Discard,
   347  		}))
   348  		app.Get("/", func(c *fiber.Ctx) error {
   349  			c.Set("test", "test")
   350  			return c.SendString("Hello, World!")
   351  		})
   352  		benchSetup(bb, app)
   353  	})
   354  
   355  	b.Run("DefaultFormat", func(bb *testing.B) {
   356  		app := fiber.New()
   357  		app.Use(New(Config{
   358  			Output: io.Discard,
   359  		}))
   360  		app.Get("/", func(c *fiber.Ctx) error {
   361  			return c.SendString("Hello, World!")
   362  		})
   363  		benchSetup(bb, app)
   364  	})
   365  
   366  	b.Run("WithTagParameter", func(bb *testing.B) {
   367  		app := fiber.New()
   368  		app.Use(New(Config{
   369  			Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}",
   370  			Output: io.Discard,
   371  		}))
   372  		app.Get("/", func(c *fiber.Ctx) error {
   373  			c.Set("test", "test")
   374  			return c.SendString("Hello, World!")
   375  		})
   376  		benchSetup(bb, app)
   377  	})
   378  }
   379  
   380  // go test -run Test_Response_Header
   381  func Test_Response_Header(t *testing.T) {
   382  	t.Parallel()
   383  	buf := bytebufferpool.Get()
   384  	defer bytebufferpool.Put(buf)
   385  
   386  	app := fiber.New()
   387  	app.Use(requestid.New(requestid.Config{
   388  		Next:       nil,
   389  		Header:     fiber.HeaderXRequestID,
   390  		Generator:  func() string { return "Hello fiber!" },
   391  		ContextKey: "requestid",
   392  	}))
   393  	app.Use(New(Config{
   394  		Format: "${respHeader:X-Request-ID}",
   395  		Output: buf,
   396  	}))
   397  	app.Get("/", func(c *fiber.Ctx) error {
   398  		return c.SendString("Hello fiber!")
   399  	})
   400  
   401  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   402  	utils.AssertEqual(t, nil, err)
   403  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   404  	utils.AssertEqual(t, "Hello fiber!", buf.String())
   405  }
   406  
   407  // go test -run Test_Req_Header
   408  func Test_Req_Header(t *testing.T) {
   409  	t.Parallel()
   410  	buf := bytebufferpool.Get()
   411  	defer bytebufferpool.Put(buf)
   412  
   413  	app := fiber.New()
   414  	app.Use(New(Config{
   415  		Format: "${header:test}",
   416  		Output: buf,
   417  	}))
   418  	app.Get("/", func(c *fiber.Ctx) error {
   419  		return c.SendString("Hello fiber!")
   420  	})
   421  	headerReq := httptest.NewRequest(fiber.MethodGet, "/", nil)
   422  	headerReq.Header.Add("test", "Hello fiber!")
   423  
   424  	resp, err := app.Test(headerReq)
   425  	utils.AssertEqual(t, nil, err)
   426  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   427  	utils.AssertEqual(t, "Hello fiber!", buf.String())
   428  }
   429  
   430  // go test -run Test_ReqHeader_Header
   431  func Test_ReqHeader_Header(t *testing.T) {
   432  	t.Parallel()
   433  	buf := bytebufferpool.Get()
   434  	defer bytebufferpool.Put(buf)
   435  
   436  	app := fiber.New()
   437  	app.Use(New(Config{
   438  		Format: "${reqHeader:test}",
   439  		Output: buf,
   440  	}))
   441  	app.Get("/", func(c *fiber.Ctx) error {
   442  		return c.SendString("Hello fiber!")
   443  	})
   444  	reqHeaderReq := httptest.NewRequest(fiber.MethodGet, "/", nil)
   445  	reqHeaderReq.Header.Add("test", "Hello fiber!")
   446  
   447  	resp, err := app.Test(reqHeaderReq)
   448  	utils.AssertEqual(t, nil, err)
   449  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   450  	utils.AssertEqual(t, "Hello fiber!", buf.String())
   451  }
   452  
   453  // go test -run Test_CustomTags
   454  func Test_CustomTags(t *testing.T) {
   455  	t.Parallel()
   456  	customTag := "it is a custom tag"
   457  
   458  	buf := bytebufferpool.Get()
   459  	defer bytebufferpool.Put(buf)
   460  
   461  	app := fiber.New()
   462  	app.Use(New(Config{
   463  		Format: "${custom_tag}",
   464  		CustomTags: map[string]LogFunc{
   465  			"custom_tag": func(output Buffer, c *fiber.Ctx, data *Data, extraParam string) (int, error) {
   466  				return output.WriteString(customTag)
   467  			},
   468  		},
   469  		Output: buf,
   470  	}))
   471  	app.Get("/", func(c *fiber.Ctx) error {
   472  		return c.SendString("Hello fiber!")
   473  	})
   474  	reqHeaderReq := httptest.NewRequest(fiber.MethodGet, "/", nil)
   475  	reqHeaderReq.Header.Add("test", "Hello fiber!")
   476  
   477  	resp, err := app.Test(reqHeaderReq)
   478  	utils.AssertEqual(t, nil, err)
   479  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   480  	utils.AssertEqual(t, customTag, buf.String())
   481  }
   482  
   483  // go test -run Test_Logger_ByteSent_Streaming
   484  func Test_Logger_ByteSent_Streaming(t *testing.T) {
   485  	t.Parallel()
   486  	app := fiber.New()
   487  
   488  	buf := bytebufferpool.Get()
   489  	defer bytebufferpool.Put(buf)
   490  
   491  	app.Use(New(Config{
   492  		Format: "${bytesReceived} ${bytesSent} ${status}",
   493  		Output: buf,
   494  	}))
   495  
   496  	app.Get("/", func(c *fiber.Ctx) error {
   497  		c.Set("Connection", "keep-alive")
   498  		c.Set("Transfer-Encoding", "chunked")
   499  		c.Context().SetBodyStreamWriter(func(w *bufio.Writer) {
   500  			var i int
   501  			for {
   502  				i++
   503  				msg := fmt.Sprintf("%d - the time is %v", i, time.Now())
   504  				fmt.Fprintf(w, "data: Message: %s\n\n", msg)
   505  				err := w.Flush()
   506  				if err != nil {
   507  					break
   508  				}
   509  				if i == 10 {
   510  					break
   511  				}
   512  			}
   513  		})
   514  		return nil
   515  	})
   516  
   517  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   518  	utils.AssertEqual(t, nil, err)
   519  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   520  	utils.AssertEqual(t, "0 0 200", buf.String())
   521  }
   522  
   523  // go test -run Test_Logger_EnableColors
   524  func Test_Logger_EnableColors(t *testing.T) {
   525  	t.Parallel()
   526  	o := new(fakeOutput)
   527  	app := fiber.New()
   528  	app.Use(New(Config{
   529  		Output: o,
   530  	}))
   531  
   532  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   533  	utils.AssertEqual(t, nil, err)
   534  	utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
   535  
   536  	utils.AssertEqual(t, 1, int(*o))
   537  }