mirror of https://github.com/gofiber/fiber.git
1356 lines
34 KiB
Go
1356 lines
34 KiB
Go
//nolint:depguard // Because we test logging :D
|
|
package logger
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"regexp"
|
|
"runtime"
|
|
"strconv"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
fiberlog "github.com/gofiber/fiber/v3/log"
|
|
"github.com/gofiber/fiber/v3/middleware/requestid"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/valyala/bytebufferpool"
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
const (
|
|
pathFooBar = "/?foo=bar"
|
|
httpProto = "HTTP/1.1"
|
|
)
|
|
|
|
func benchmarkSetup(b *testing.B, app *fiber.App, uri string) {
|
|
b.Helper()
|
|
|
|
h := app.Handler()
|
|
|
|
fctx := &fasthttp.RequestCtx{}
|
|
fctx.Request.Header.SetMethod(fiber.MethodGet)
|
|
fctx.Request.SetRequestURI(uri)
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
h(fctx)
|
|
}
|
|
}
|
|
|
|
func benchmarkSetupParallel(b *testing.B, app *fiber.App, path string) {
|
|
b.Helper()
|
|
|
|
handler := app.Handler()
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
fctx := &fasthttp.RequestCtx{}
|
|
fctx.Request.Header.SetMethod(fiber.MethodGet)
|
|
fctx.Request.SetRequestURI(path)
|
|
|
|
for pb.Next() {
|
|
handler(fctx)
|
|
}
|
|
})
|
|
}
|
|
|
|
// go test -run Test_Logger
|
|
func Test_Logger(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app.Use(New(Config{
|
|
Format: "${error}",
|
|
Stream: buf,
|
|
}))
|
|
|
|
app.Get("/", func(_ fiber.Ctx) error {
|
|
return errors.New("some random error")
|
|
})
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusInternalServerError, resp.StatusCode)
|
|
require.Equal(t, "some random error", buf.String())
|
|
}
|
|
|
|
// go test -run Test_Logger_locals
|
|
func Test_Logger_locals(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app.Use(New(Config{
|
|
Format: "${locals:demo}",
|
|
Stream: buf,
|
|
}))
|
|
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Locals("demo", "johndoe")
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
|
|
app.Get("/int", func(c fiber.Ctx) error {
|
|
c.Locals("demo", 55)
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
|
|
app.Get("/empty", func(c fiber.Ctx) error {
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Equal(t, "johndoe", buf.String())
|
|
|
|
buf.Reset()
|
|
|
|
resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/int", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Equal(t, "55", buf.String())
|
|
|
|
buf.Reset()
|
|
|
|
resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/empty", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Equal(t, "", buf.String())
|
|
}
|
|
|
|
// go test -run Test_Logger_Next
|
|
func Test_Logger_Next(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Next: func(_ fiber.Ctx) bool {
|
|
return true
|
|
},
|
|
}))
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
|
}
|
|
|
|
// go test -run Test_Logger_Done
|
|
func Test_Logger_Done(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytes.NewBuffer(nil)
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Done: func(c fiber.Ctx, logString []byte) {
|
|
if c.Response().StatusCode() == fiber.StatusOK {
|
|
_, err := buf.Write(logString)
|
|
require.NoError(t, err)
|
|
}
|
|
},
|
|
})).Get("/logging", func(ctx fiber.Ctx) error {
|
|
return ctx.SendStatus(fiber.StatusOK)
|
|
})
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/logging", nil))
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Positive(t, buf.Len(), 0)
|
|
}
|
|
|
|
// Test_Logger_Filter tests the Filter functionality of the logger middleware.
|
|
// It verifies that logs are written or skipped based on the filter condition.
|
|
func Test_Logger_Filter(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("Test Not Found", func(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
logOutput := bytes.Buffer{}
|
|
|
|
// Return true to skip logging for all requests != 404
|
|
app.Use(New(Config{
|
|
Skip: func(c fiber.Ctx) bool {
|
|
return c.Response().StatusCode() != fiber.StatusNotFound
|
|
},
|
|
Stream: &logOutput,
|
|
}))
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/nonexistent", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
|
|
|
// Expect logs for the 404 request
|
|
require.Contains(t, logOutput.String(), "404")
|
|
})
|
|
|
|
t.Run("Test OK", func(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
logOutput := bytes.Buffer{}
|
|
|
|
// Return true to skip logging for all requests == 200
|
|
app.Use(New(Config{
|
|
Skip: func(c fiber.Ctx) bool {
|
|
return c.Response().StatusCode() == fiber.StatusOK
|
|
},
|
|
Stream: &logOutput,
|
|
}))
|
|
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
|
|
// We skip logging for status == 200, so "200" should not appear
|
|
require.NotContains(t, logOutput.String(), "200")
|
|
})
|
|
|
|
t.Run("Always Skip", func(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
logOutput := bytes.Buffer{}
|
|
|
|
// Filter always returns true => skip all logs
|
|
app.Use(New(Config{
|
|
Skip: func(_ fiber.Ctx) bool {
|
|
return true // always skip
|
|
},
|
|
Stream: &logOutput,
|
|
}))
|
|
|
|
app.Get("/something", func(c fiber.Ctx) error {
|
|
return c.Status(fiber.StatusTeapot).SendString("I'm a teapot")
|
|
})
|
|
|
|
_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/something", nil))
|
|
require.NoError(t, err)
|
|
|
|
// Expect NO logs
|
|
require.Empty(t, logOutput.String())
|
|
})
|
|
|
|
t.Run("Never Skip", func(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
logOutput := bytes.Buffer{}
|
|
|
|
// Filter always returns false => never skip logs
|
|
app.Use(New(Config{
|
|
Skip: func(_ fiber.Ctx) bool {
|
|
return false // never skip
|
|
},
|
|
Stream: &logOutput,
|
|
}))
|
|
|
|
app.Get("/always", func(c fiber.Ctx) error {
|
|
return c.Status(fiber.StatusTeapot).SendString("Teapot again")
|
|
})
|
|
|
|
_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/always", nil))
|
|
require.NoError(t, err)
|
|
|
|
// Expect some logging - check any substring
|
|
require.Contains(t, logOutput.String(), strconv.Itoa(fiber.StatusTeapot))
|
|
})
|
|
|
|
t.Run("Skip /healthz", func(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
logOutput := bytes.Buffer{}
|
|
|
|
// Filter returns true (skip logs) if the request path is /healthz
|
|
app.Use(New(Config{
|
|
Skip: func(c fiber.Ctx) bool {
|
|
return c.Path() == "/healthz"
|
|
},
|
|
Stream: &logOutput,
|
|
}))
|
|
|
|
// Normal route
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello World!")
|
|
})
|
|
// Health route
|
|
app.Get("/healthz", func(c fiber.Ctx) error {
|
|
return c.SendString("OK")
|
|
})
|
|
|
|
// Request to "/" -> should be logged
|
|
_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Contains(t, logOutput.String(), "200")
|
|
|
|
// Reset output buffer
|
|
logOutput.Reset()
|
|
|
|
// Request to "/healthz" -> should be skipped
|
|
_, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/healthz", nil))
|
|
require.NoError(t, err)
|
|
require.Empty(t, logOutput.String())
|
|
})
|
|
}
|
|
|
|
// go test -run Test_Logger_ErrorTimeZone
|
|
func Test_Logger_ErrorTimeZone(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
TimeZone: "invalid",
|
|
}))
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
|
}
|
|
|
|
// go test -run Test_Logger_Fiber_Logger
|
|
func Test_Logger_LoggerToWriter(t *testing.T) {
|
|
app := fiber.New()
|
|
|
|
buf := bytebufferpool.Get()
|
|
t.Cleanup(func() {
|
|
bytebufferpool.Put(buf)
|
|
})
|
|
|
|
logger := fiberlog.DefaultLogger()
|
|
stdlogger, ok := logger.Logger().(*log.Logger)
|
|
require.True(t, ok)
|
|
|
|
stdlogger.SetFlags(0)
|
|
logger.SetOutput(buf)
|
|
|
|
testCases := []struct {
|
|
levelStr string
|
|
level fiberlog.Level
|
|
}{
|
|
{
|
|
level: fiberlog.LevelTrace,
|
|
levelStr: "Trace",
|
|
},
|
|
{
|
|
level: fiberlog.LevelDebug,
|
|
levelStr: "Debug",
|
|
},
|
|
{
|
|
level: fiberlog.LevelInfo,
|
|
levelStr: "Info",
|
|
},
|
|
{
|
|
level: fiberlog.LevelWarn,
|
|
levelStr: "Warn",
|
|
},
|
|
{
|
|
level: fiberlog.LevelError,
|
|
levelStr: "Error",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
level := strconv.Itoa(int(tc.level))
|
|
t.Run(level, func(t *testing.T) {
|
|
buf.Reset()
|
|
|
|
app.Use("/"+level, New(Config{
|
|
Format: "${error}",
|
|
Stream: LoggerToWriter(logger, tc.
|
|
level),
|
|
}))
|
|
|
|
app.Get("/"+level, func(_ fiber.Ctx) error {
|
|
return errors.New("some random error")
|
|
})
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/"+level, nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusInternalServerError, resp.StatusCode)
|
|
require.Equal(t, "["+tc.levelStr+"] some random error\n", buf.String())
|
|
})
|
|
|
|
require.Panics(t, func() {
|
|
LoggerToWriter(logger, fiberlog.LevelPanic)
|
|
})
|
|
|
|
require.Panics(t, func() {
|
|
LoggerToWriter(logger, fiberlog.LevelFatal)
|
|
})
|
|
|
|
require.Panics(t, func() {
|
|
LoggerToWriter(nil, fiberlog.LevelFatal)
|
|
})
|
|
}
|
|
}
|
|
|
|
type fakeErrorOutput int
|
|
|
|
func (o *fakeErrorOutput) Write([]byte) (int, error) {
|
|
*o++
|
|
return 0, errors.New("fake output")
|
|
}
|
|
|
|
// go test -run Test_Logger_ErrorOutput_WithoutColor
|
|
func Test_Logger_ErrorOutput_WithoutColor(t *testing.T) {
|
|
t.Parallel()
|
|
o := new(fakeErrorOutput)
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Stream: o,
|
|
DisableColors: true,
|
|
}))
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
|
require.EqualValues(t, 2, *o)
|
|
}
|
|
|
|
// go test -run Test_Logger_ErrorOutput
|
|
func Test_Logger_ErrorOutput(t *testing.T) {
|
|
t.Parallel()
|
|
o := new(fakeErrorOutput)
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Stream: o,
|
|
}))
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
|
require.EqualValues(t, 2, *o)
|
|
}
|
|
|
|
// go test -run Test_Logger_All
|
|
func Test_Logger_All(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Format: "${pid}${reqHeaders}${referer}${scheme}${protocol}${ip}${ips}${host}${url}${ua}${body}${route}${black}${red}${green}${yellow}${blue}${magenta}${cyan}${white}${reset}${error}${reqHeader:test}${query:test}${form:test}${cookie:test}${non}",
|
|
Stream: buf,
|
|
}))
|
|
|
|
// Alias colors
|
|
colors := app.Config().ColorScheme
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, pathFooBar, nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
|
|
|
expected := fmt.Sprintf("%dHost=example.comhttpHTTP/1.10.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)
|
|
require.Equal(t, expected, buf.String())
|
|
}
|
|
|
|
func Test_Logger_CLF_Format(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: CommonFormat,
|
|
Stream: buf,
|
|
}))
|
|
|
|
method := fiber.MethodGet
|
|
status := fiber.StatusNotFound
|
|
bytesSent := 0
|
|
|
|
resp, err := app.Test(httptest.NewRequest(method, pathFooBar, nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, status, resp.StatusCode)
|
|
|
|
pattern := fmt.Sprintf(`0\.0\.0\.0 - - \[\d{2}:\d{2}:\d{2}\] "%s %s %s" %d %d`, method, regexp.QuoteMeta(pathFooBar), httpProto, status, bytesSent)
|
|
require.Regexp(t, pattern, buf.String())
|
|
}
|
|
|
|
func Test_Logger_Combined_CLF_Format(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: CombinedFormat,
|
|
Stream: buf,
|
|
}))
|
|
|
|
method := fiber.MethodGet
|
|
status := fiber.StatusNotFound
|
|
bytesSent := 0
|
|
referer := "http://example.com"
|
|
ua := "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"
|
|
|
|
req := httptest.NewRequest(method, pathFooBar, nil)
|
|
req.Header.Set("Referer", referer)
|
|
req.Header.Set("User-Agent", ua)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
require.Equal(t, status, resp.StatusCode)
|
|
|
|
pattern := fmt.Sprintf(`0\.0\.0\.0 - - \[\d{2}:\d{2}:\d{2}\] "%s %s %s" %d %d "%s" "%s"`, method, regexp.QuoteMeta(pathFooBar), httpProto, status, bytesSent, regexp.QuoteMeta(referer), regexp.QuoteMeta(ua)) //nolint:gocritic // double quoting for regex and string is not needed
|
|
require.Regexp(t, pattern, buf.String())
|
|
}
|
|
|
|
func Test_Logger_Json_Format(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: JSONFormat,
|
|
Stream: buf,
|
|
}))
|
|
|
|
method := fiber.MethodGet
|
|
status := fiber.StatusNotFound
|
|
ip := "0.0.0.0"
|
|
bytesSent := 0
|
|
|
|
req := httptest.NewRequest(method, pathFooBar, nil)
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
require.Equal(t, status, resp.StatusCode)
|
|
|
|
pattern := fmt.Sprintf(`\{"time":"\d{2}:\d{2}:\d{2}","ip":"%s","method":%q,"url":"%s","status":%d,"bytesSent":%d\}`, regexp.QuoteMeta(ip), method, regexp.QuoteMeta(pathFooBar), status, bytesSent) //nolint:gocritic // double quoting for regex and string is not needed
|
|
require.Regexp(t, pattern, buf.String())
|
|
}
|
|
|
|
func Test_Logger_ECS_Format(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: ECSFormat,
|
|
Stream: buf,
|
|
}))
|
|
|
|
method := fiber.MethodGet
|
|
status := fiber.StatusNotFound
|
|
ip := "0.0.0.0"
|
|
bytesSent := 0
|
|
msg := fmt.Sprintf("%s %s responded with %d", method, pathFooBar, status)
|
|
|
|
req := httptest.NewRequest(method, pathFooBar, nil)
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
require.Equal(t, status, resp.StatusCode)
|
|
|
|
pattern := fmt.Sprintf(`\{"@timestamp":"\d{2}:\d{2}:\d{2}","ecs":\{"version":"1.6.0"\},"client":\{"ip":"%s"\},"http":\{"request":\{"method":%q,"url":"%s","protocol":%q\},"response":\{"status_code":%d,"body":\{"bytes":%d\}\}\},"log":\{"level":"INFO","logger":"fiber"\},"message":"%s"\}`, regexp.QuoteMeta(ip), method, regexp.QuoteMeta(pathFooBar), httpProto, status, bytesSent, regexp.QuoteMeta(msg)) //nolint:gocritic // double quoting for regex and string is not needed
|
|
require.Regexp(t, pattern, buf.String())
|
|
}
|
|
|
|
func getLatencyTimeUnits() []struct {
|
|
unit string
|
|
div time.Duration
|
|
} {
|
|
// windows does not support µs sleep precision
|
|
// https://github.com/golang/go/issues/29485
|
|
if runtime.GOOS == "windows" {
|
|
return []struct {
|
|
unit string
|
|
div time.Duration
|
|
}{
|
|
{unit: "ms", div: time.Millisecond},
|
|
{unit: "s", div: time.Second},
|
|
}
|
|
}
|
|
return []struct {
|
|
unit string
|
|
div time.Duration
|
|
}{
|
|
{unit: "µs", div: time.Microsecond},
|
|
{unit: "ms", div: time.Millisecond},
|
|
{unit: "s", div: time.Second},
|
|
}
|
|
}
|
|
|
|
// go test -run Test_Logger_WithLatency
|
|
func Test_Logger_WithLatency(t *testing.T) {
|
|
buff := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buff)
|
|
app := fiber.New()
|
|
|
|
logger := New(Config{
|
|
Stream: buff,
|
|
Format: "${latency}",
|
|
})
|
|
app.Use(logger)
|
|
|
|
// Define a list of time units to test
|
|
timeUnits := getLatencyTimeUnits()
|
|
|
|
// Initialize a new time unit
|
|
sleepDuration := 1 * time.Nanosecond
|
|
|
|
// Define a test route that sleeps
|
|
app.Get("/test", func(c fiber.Ctx) error {
|
|
time.Sleep(sleepDuration)
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
|
|
// Loop through each time unit and assert that the log output contains the expected latency value
|
|
for _, tu := range timeUnits {
|
|
// Update the sleep duration for the next iteration
|
|
sleepDuration = 1 * tu.div
|
|
|
|
// Create a new HTTP request to the test route
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{
|
|
Timeout: 3 * time.Second,
|
|
FailOnTimeout: true,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
|
|
// Assert that the log output contains the expected latency value in the current time unit
|
|
require.True(t, bytes.HasSuffix(buff.Bytes(), []byte(tu.unit)), "Expected latency to be in %s, got %s", tu.unit, buff.String())
|
|
|
|
// Reset the buffer
|
|
buff.Reset()
|
|
}
|
|
}
|
|
|
|
// go test -run Test_Logger_WithLatency_DefaultFormat
|
|
func Test_Logger_WithLatency_DefaultFormat(t *testing.T) {
|
|
buff := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buff)
|
|
app := fiber.New()
|
|
|
|
logger := New(Config{
|
|
Stream: buff,
|
|
})
|
|
app.Use(logger)
|
|
|
|
// Define a list of time units to test
|
|
timeUnits := getLatencyTimeUnits()
|
|
|
|
// Initialize a new time unit
|
|
sleepDuration := 1 * time.Nanosecond
|
|
|
|
// Define a test route that sleeps
|
|
app.Get("/test", func(c fiber.Ctx) error {
|
|
time.Sleep(sleepDuration)
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
|
|
// Loop through each time unit and assert that the log output contains the expected latency value
|
|
for _, tu := range timeUnits {
|
|
// Update the sleep duration for the next iteration
|
|
sleepDuration = 1 * tu.div
|
|
|
|
// Create a new HTTP request to the test route
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), fiber.TestConfig{
|
|
Timeout: 2 * time.Second,
|
|
FailOnTimeout: true,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
|
|
// Assert that the log output contains the expected latency value in the current time unit
|
|
// parse out the latency value from the log output
|
|
latency := bytes.Split(buff.Bytes(), []byte(" | "))[2]
|
|
// Assert that the latency value is in the current time unit
|
|
require.True(t, bytes.HasSuffix(latency, []byte(tu.unit)), "Expected latency to be in %s, got %s", tu.unit, latency)
|
|
|
|
// Reset the buffer
|
|
buff.Reset()
|
|
}
|
|
}
|
|
|
|
// go test -run Test_Query_Params
|
|
func Test_Query_Params(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Format: "${queryParams}",
|
|
Stream: buf,
|
|
}))
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/?foo=bar&baz=moz", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
|
|
|
expected := "foo=bar&baz=moz"
|
|
require.Equal(t, expected, buf.String())
|
|
}
|
|
|
|
// go test -run Test_Response_Body
|
|
func Test_Response_Body(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Format: "${resBody}",
|
|
Stream: buf,
|
|
}))
|
|
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Sample response body")
|
|
})
|
|
|
|
app.Post("/test", func(c fiber.Ctx) error {
|
|
return c.Send([]byte("Post in test"))
|
|
})
|
|
|
|
_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
|
|
expectedGetResponse := "Sample response body"
|
|
require.Equal(t, expectedGetResponse, buf.String())
|
|
|
|
buf.Reset() // Reset buffer to test POST
|
|
_, err = app.Test(httptest.NewRequest(fiber.MethodPost, "/test", nil))
|
|
|
|
expectedPostResponse := "Post in test"
|
|
require.NoError(t, err)
|
|
require.Equal(t, expectedPostResponse, buf.String())
|
|
}
|
|
|
|
// go test -run Test_Request_Body
|
|
func Test_Request_Body(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Format: "${bytesReceived} ${bytesSent} ${status}",
|
|
Stream: buf,
|
|
}))
|
|
|
|
app.Post("/", func(c fiber.Ctx) error {
|
|
c.Response().Header.SetContentLength(5)
|
|
return c.SendString("World")
|
|
})
|
|
|
|
// Create a POST request with a body
|
|
body := []byte("Hello")
|
|
req := httptest.NewRequest(fiber.MethodPost, "/", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/octet-stream")
|
|
|
|
_, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "5 5 200", buf.String())
|
|
}
|
|
|
|
// go test -run Test_Logger_AppendUint
|
|
func Test_Logger_AppendUint(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app.Use(New(Config{
|
|
Format: "${bytesReceived} ${bytesSent} ${status}",
|
|
Stream: buf,
|
|
}))
|
|
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("hello")
|
|
})
|
|
|
|
app.Get("/content", func(c fiber.Ctx) error {
|
|
c.Response().Header.SetContentLength(5)
|
|
return c.SendString("hello")
|
|
})
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Equal(t, "-2 0 200", buf.String())
|
|
|
|
buf.Reset()
|
|
resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/content", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Equal(t, "-2 5 200", buf.String())
|
|
}
|
|
|
|
// go test -run Test_Logger_Data_Race -race
|
|
func Test_Logger_Data_Race(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app.Use(New(ConfigDefault))
|
|
app.Use(New(Config{
|
|
Format: "${time} | ${pid} | ${locals:requestid} | ${status} | ${latency} | ${method} | ${path}\n",
|
|
}))
|
|
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("hello")
|
|
})
|
|
|
|
var (
|
|
resp1, resp2 *http.Response
|
|
err1, err2 error
|
|
)
|
|
wg := &sync.WaitGroup{}
|
|
wg.Add(1)
|
|
go func() {
|
|
resp1, err1 = app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
wg.Done()
|
|
}()
|
|
resp2, err2 = app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
wg.Wait()
|
|
|
|
require.NoError(t, err1)
|
|
require.Equal(t, fiber.StatusOK, resp1.StatusCode)
|
|
require.NoError(t, err2)
|
|
require.Equal(t, fiber.StatusOK, resp2.StatusCode)
|
|
}
|
|
|
|
// go test -run Test_Response_Header
|
|
func Test_Response_Header(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
|
|
app.Use(requestid.New(requestid.Config{
|
|
Next: nil,
|
|
Header: fiber.HeaderXRequestID,
|
|
Generator: func() string { return "Hello fiber!" },
|
|
}))
|
|
app.Use(New(Config{
|
|
Format: "${respHeader:X-Request-ID}",
|
|
Stream: buf,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello fiber!")
|
|
})
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Equal(t, "Hello fiber!", buf.String())
|
|
}
|
|
|
|
// go test -run Test_Req_Header
|
|
func Test_Req_Header(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Format: "${reqHeader:test}",
|
|
Stream: buf,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello fiber!")
|
|
})
|
|
headerReq := httptest.NewRequest(fiber.MethodGet, "/", nil)
|
|
headerReq.Header.Add("test", "Hello fiber!")
|
|
|
|
resp, err := app.Test(headerReq)
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Equal(t, "Hello fiber!", buf.String())
|
|
}
|
|
|
|
// go test -run Test_ReqHeader_Header
|
|
func Test_ReqHeader_Header(t *testing.T) {
|
|
t.Parallel()
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Format: "${reqHeader:test}",
|
|
Stream: buf,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello fiber!")
|
|
})
|
|
reqHeaderReq := httptest.NewRequest(fiber.MethodGet, "/", nil)
|
|
reqHeaderReq.Header.Add("test", "Hello fiber!")
|
|
|
|
resp, err := app.Test(reqHeaderReq)
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Equal(t, "Hello fiber!", buf.String())
|
|
}
|
|
|
|
// go test -run Test_CustomTags
|
|
func Test_CustomTags(t *testing.T) {
|
|
t.Parallel()
|
|
customTag := "it is a custom tag"
|
|
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Format: "${custom_tag}",
|
|
CustomTags: map[string]LogFunc{
|
|
"custom_tag": func(output Buffer, _ fiber.Ctx, _ *Data, _ string) (int, error) {
|
|
return output.WriteString(customTag)
|
|
},
|
|
},
|
|
Stream: buf,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello fiber!")
|
|
})
|
|
reqHeaderReq := httptest.NewRequest(fiber.MethodGet, "/", nil)
|
|
reqHeaderReq.Header.Add("test", "Hello fiber!")
|
|
|
|
resp, err := app.Test(reqHeaderReq)
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
require.Equal(t, customTag, buf.String())
|
|
}
|
|
|
|
// go test -run Test_Logger_ByteSent_Streaming
|
|
func Test_Logger_ByteSent_Streaming(t *testing.T) {
|
|
t.Parallel()
|
|
app := fiber.New()
|
|
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
app.Use(New(Config{
|
|
Format: "${bytesReceived} ${bytesSent} ${status}",
|
|
Stream: buf,
|
|
}))
|
|
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Set("Connection", "keep-alive")
|
|
c.Set("Transfer-Encoding", "chunked")
|
|
c.RequestCtx().SetBodyStreamWriter(func(w *bufio.Writer) {
|
|
var i int
|
|
for {
|
|
i++
|
|
msg := fmt.Sprintf("%d - the time is %v", i, time.Now())
|
|
fmt.Fprintf(w, "data: Message: %s\n\n", msg)
|
|
err := w.Flush()
|
|
if err != nil {
|
|
break
|
|
}
|
|
if i == 10 {
|
|
break
|
|
}
|
|
}
|
|
})
|
|
return nil
|
|
})
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusOK, resp.StatusCode)
|
|
|
|
// -2 means identity, -1 means chunked, 200 status
|
|
require.Equal(t, "-2 -1 200", buf.String())
|
|
}
|
|
|
|
type fakeOutput int
|
|
|
|
func (o *fakeOutput) Write(b []byte) (int, error) {
|
|
*o++
|
|
return len(b), nil
|
|
}
|
|
|
|
// go test -run Test_Logger_EnableColors
|
|
func Test_Logger_EnableColors(t *testing.T) {
|
|
t.Parallel()
|
|
o := new(fakeOutput)
|
|
app := fiber.New()
|
|
|
|
app.Use(New(Config{
|
|
Stream: o,
|
|
}))
|
|
|
|
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
|
|
require.NoError(t, err)
|
|
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
|
require.EqualValues(t, 1, *o)
|
|
}
|
|
|
|
// go test -v -run=^$ -bench=Benchmark_Logger$ -benchmem -count=4
|
|
func Benchmark_Logger(b *testing.B) {
|
|
b.Run("NoMiddleware", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithBytesAndStatus", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${bytesReceived} ${bytesSent} ${status}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Set("test", "test")
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
|
|
b.Run("DefaultFormat", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
|
|
b.Run("DefaultFormatDisableColors", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Stream: io.Discard,
|
|
DisableColors: true,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
|
|
b.Run("DefaultFormatWithFiberLog", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
logger := fiberlog.DefaultLogger()
|
|
logger.SetOutput(io.Discard)
|
|
app.Use(New(Config{
|
|
Stream: LoggerToWriter(logger, fiberlog.LevelDebug),
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithTagParameter", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Set("test", "test")
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithLocals", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${locals:demo}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Locals("demo", "johndoe")
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithLocalsInt", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${locals:demo}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/int", func(c fiber.Ctx) error {
|
|
c.Locals("demo", 55)
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
benchmarkSetup(bb, app, "/int")
|
|
})
|
|
|
|
b.Run("WithCustomDone", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Done: func(c fiber.Ctx, logString []byte) {
|
|
if c.Response().StatusCode() == fiber.StatusOK {
|
|
io.Discard.Write(logString) //nolint:errcheck // ignore error
|
|
}
|
|
},
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/logging", func(ctx fiber.Ctx) error {
|
|
return ctx.SendStatus(fiber.StatusOK)
|
|
})
|
|
benchmarkSetup(bb, app, "/logging")
|
|
})
|
|
|
|
b.Run("WithAllTags", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${pid}${reqHeaders}${referer}${scheme}${protocol}${ip}${ips}${host}${url}${ua}${body}${route}${black}${red}${green}${yellow}${blue}${magenta}${cyan}${white}${reset}${error}${reqHeader:test}${query:test}${form:test}${cookie:test}${non}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
|
|
b.Run("Streaming", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${bytesReceived} ${bytesSent} ${status}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Set("Connection", "keep-alive")
|
|
c.Set("Transfer-Encoding", "chunked")
|
|
c.RequestCtx().SetBodyStreamWriter(func(w *bufio.Writer) {
|
|
var i int
|
|
for {
|
|
i++
|
|
msg := fmt.Sprintf("%d - the time is %v", i, time.Now())
|
|
fmt.Fprintf(w, "data: Message: %s\n\n", msg)
|
|
err := w.Flush()
|
|
if err != nil {
|
|
break
|
|
}
|
|
if i == 10 {
|
|
break
|
|
}
|
|
}
|
|
})
|
|
return nil
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithBody", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${resBody}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Sample response body")
|
|
})
|
|
benchmarkSetup(bb, app, "/")
|
|
})
|
|
}
|
|
|
|
// go test -v -run=^$ -bench=Benchmark_Logger_Parallel$ -benchmem -count=4
|
|
func Benchmark_Logger_Parallel(b *testing.B) {
|
|
b.Run("NoMiddleware", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithBytesAndStatus", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${bytesReceived} ${bytesSent} ${status}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Set("test", "test")
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
|
|
b.Run("DefaultFormat", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
|
|
b.Run("DefaultFormatWithFiberLog", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
logger := fiberlog.DefaultLogger()
|
|
logger.SetOutput(io.Discard)
|
|
app.Use(New(Config{
|
|
Stream: LoggerToWriter(logger, fiberlog.LevelDebug),
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
|
|
b.Run("DefaultFormatDisableColors", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Stream: io.Discard,
|
|
DisableColors: true,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithTagParameter", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${bytesReceived} ${bytesSent} ${status} ${reqHeader:test}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Set("test", "test")
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithLocals", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${locals:demo}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Locals("demo", "johndoe")
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithLocalsInt", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${locals:demo}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/int", func(c fiber.Ctx) error {
|
|
c.Locals("demo", 55)
|
|
return c.SendStatus(fiber.StatusOK)
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/int")
|
|
})
|
|
|
|
b.Run("WithCustomDone", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Done: func(c fiber.Ctx, logString []byte) {
|
|
if c.Response().StatusCode() == fiber.StatusOK {
|
|
io.Discard.Write(logString) //nolint:errcheck // ignore error
|
|
}
|
|
},
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/logging", func(ctx fiber.Ctx) error {
|
|
return ctx.SendStatus(fiber.StatusOK)
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/logging")
|
|
})
|
|
|
|
b.Run("WithAllTags", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${pid}${reqHeaders}${referer}${scheme}${protocol}${ip}${ips}${host}${url}${ua}${body}${route}${black}${red}${green}${yellow}${blue}${magenta}${cyan}${white}${reset}${error}${reqHeader:test}${query:test}${form:test}${cookie:test}${non}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Hello, World!")
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
|
|
b.Run("Streaming", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${bytesReceived} ${bytesSent} ${status}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
c.Set("Connection", "keep-alive")
|
|
c.Set("Transfer-Encoding", "chunked")
|
|
c.RequestCtx().SetBodyStreamWriter(func(w *bufio.Writer) {
|
|
var i int
|
|
for {
|
|
i++
|
|
msg := fmt.Sprintf("%d - the time is %v", i, time.Now())
|
|
fmt.Fprintf(w, "data: Message: %s\n\n", msg)
|
|
err := w.Flush()
|
|
if err != nil {
|
|
break
|
|
}
|
|
if i == 10 {
|
|
break
|
|
}
|
|
}
|
|
})
|
|
return nil
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
|
|
b.Run("WithBody", func(bb *testing.B) {
|
|
app := fiber.New()
|
|
app.Use(New(Config{
|
|
Format: "${resBody}",
|
|
Stream: io.Discard,
|
|
}))
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
return c.SendString("Sample response body")
|
|
})
|
|
benchmarkSetupParallel(bb, app, "/")
|
|
})
|
|
}
|