mirror of
https://github.com/gofiber/fiber.git
synced 2025-04-05 00:22:06 +00:00
* feat(logger): Add predefined log formats This commit introduces predefined log formats for the logger middleware, enhancing its flexibility and ease of use. Users can now specify formats like "common", "combined", and "json" in addition to the default format. Changes: - Added a `format.go` file to store predefined log format constants. - Updated `config.go` to include documentation for the `Format` configuration option, explaining the available placeholders and predefined formats. - Modified `logger.go` to utilize the predefined formats based on the `Format` configuration. - Added a new test case `Test_Logger_CLF` in `logger_test.go` to verify the "common" log format. * feat(logger): Use predefined formats and fix default format This commit updates the logger middleware to utilize the predefined log formats introduced in a previous commit. It also fixes the default format to use the `FormatDefault` constant. Changes: - Updated `config.go` to use `FormatDefault` constant for the default format. - Updated `default_logger.go` to use `FormatDefault` constant for the default format. - Added new test cases in `logger_test.go` to verify the "common", "combined" and "json" log formats. - Updated `format.go` to add newline character to the end of the default format. * feat(logger): Document and exemplify predefined formats * fix(logger): Improve test assertions based on golangci-lint * docs(logger): Improve documentation and formatting logger.md based on markdownlint-cli2 * docs(logger): Improve documentation based on markdownlint-cli2 * fix(logger): Improve combined and JSON format tests * feat(logger): Add ECS log format * feat(logger): Add CustomFormat option This commit introduces a `CustomFormat` option to the `Config` struct, allowing users to specify a predefined format (like "common", "combined", "json", or "ecs") * feat(logger): Add ECS log format to examples and config * docs(logger): Update examples in whats_new.md * feat(logger): Remove CustomFormat option and renamed Format consts - Removed `CustomFormat` field from `Config`. - Removed `LoggerConfig` map. - Rename predefined formats constants. * docs(logger): Update documentation and examples after format refactor --------- Co-authored-by: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
128 lines
3.1 KiB
Go
128 lines
3.1 KiB
Go
package logger
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
)
|
|
|
|
// New creates a new middleware handler
|
|
func New(config ...Config) fiber.Handler {
|
|
// Set default config
|
|
cfg := configDefault(config...)
|
|
|
|
// Get timezone location
|
|
tz, err := time.LoadLocation(cfg.TimeZone)
|
|
if err != nil || tz == nil {
|
|
cfg.timeZoneLocation = time.Local
|
|
} else {
|
|
cfg.timeZoneLocation = tz
|
|
}
|
|
|
|
// Check if format contains latency
|
|
cfg.enableLatency = strings.Contains(cfg.Format, "${"+TagLatency+"}")
|
|
|
|
var timestamp atomic.Value
|
|
// Create correct timeformat
|
|
timestamp.Store(time.Now().In(cfg.timeZoneLocation).Format(cfg.TimeFormat))
|
|
|
|
// Update date/time every 500 milliseconds in a separate go routine
|
|
if strings.Contains(cfg.Format, "${"+TagTime+"}") {
|
|
go func() {
|
|
for {
|
|
time.Sleep(cfg.TimeInterval)
|
|
timestamp.Store(time.Now().In(cfg.timeZoneLocation).Format(cfg.TimeFormat))
|
|
}
|
|
}()
|
|
}
|
|
// Set PID once
|
|
pid := strconv.Itoa(os.Getpid())
|
|
|
|
// Set variables
|
|
var (
|
|
once sync.Once
|
|
errHandler fiber.ErrorHandler
|
|
|
|
dataPool = sync.Pool{New: func() any { return new(Data) }}
|
|
)
|
|
|
|
// Err padding
|
|
errPadding := 15
|
|
errPaddingStr := strconv.Itoa(errPadding)
|
|
|
|
// Before handling func
|
|
cfg.BeforeHandlerFunc(cfg)
|
|
|
|
// Logger data
|
|
// instead of analyzing the template inside(handler) each time, this is done once before
|
|
// and we create several slices of the same length with the functions to be executed and fixed parts.
|
|
templateChain, logFunChain, err := buildLogFuncChain(&cfg, createTagMap(&cfg))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Return new handler
|
|
return func(c fiber.Ctx) error {
|
|
// Don't execute middleware if Next returns true
|
|
if cfg.Next != nil && cfg.Next(c) {
|
|
return c.Next()
|
|
}
|
|
|
|
// Set error handler once
|
|
once.Do(func() {
|
|
// get longested possible path
|
|
stack := c.App().Stack()
|
|
for m := range stack {
|
|
for r := range stack[m] {
|
|
if len(stack[m][r].Path) > errPadding {
|
|
errPadding = len(stack[m][r].Path)
|
|
errPaddingStr = strconv.Itoa(errPadding)
|
|
}
|
|
}
|
|
}
|
|
// override error handler
|
|
errHandler = c.App().ErrorHandler
|
|
})
|
|
|
|
// Logger data
|
|
data := dataPool.Get().(*Data) //nolint:forcetypeassert,errcheck // We store nothing else in the pool
|
|
// no need for a reset, as long as we always override everything
|
|
data.Pid = pid
|
|
data.ErrPaddingStr = errPaddingStr
|
|
data.Timestamp = timestamp
|
|
data.TemplateChain = templateChain
|
|
data.LogFuncChain = logFunChain
|
|
// put data back in the pool
|
|
defer dataPool.Put(data)
|
|
|
|
// Set latency start time
|
|
if cfg.enableLatency {
|
|
data.Start = time.Now()
|
|
}
|
|
|
|
// Handle request, store err for logging
|
|
chainErr := c.Next()
|
|
|
|
data.ChainErr = chainErr
|
|
// Manually call error handler
|
|
if chainErr != nil {
|
|
if err := errHandler(c, chainErr); err != nil {
|
|
_ = c.SendStatus(fiber.StatusInternalServerError) //nolint:errcheck // TODO: Explain why we ignore the error here
|
|
}
|
|
}
|
|
|
|
// Set latency stop time
|
|
if cfg.enableLatency {
|
|
data.Stop = time.Now()
|
|
}
|
|
|
|
// Logger instance & update some logger data fields
|
|
return cfg.LoggerFunc(c, data, cfg)
|
|
}
|
|
}
|