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.
pull/3359/head
edvardsanta 2025-03-18 14:38:51 -03:00
parent 395c8fafa9
commit c25ea013f2
4 changed files with 58 additions and 3 deletions

View File

@ -50,9 +50,20 @@ type Config struct {
timeZoneLocation *time.Location
// Format defines the logging tags
// Format defines the logging format for the middleware.
//
// Optional. Default: [${time}] ${ip} ${status} - ${latency} ${method} ${path} ${error}
// You can customize the log output by defining a format string with placeholders
// such as: ${time}, ${ip}, ${status}, ${method}, ${path}, ${latency}, ${error}, etc.
// The full list of available placeholders can be found in 'tags.go' or at
// 'https://docs.gofiber.io/api/middleware/logger/#constants'.
//
// Alternatively, you can use one of the predefined formats:
// - "default" → Uses the default log format: "[${time}] ${ip} ${status} - ${latency} ${method} ${path} ${error}"
// - "common" → Uses the Common Log Format (CLF): "${ip} - - [${time}] "${method} ${url} ${protocol}" ${status} ${bytesSent}"
// - "combined" → Uses the Combined Log Format: "${ip} - - [${time}] "${method} ${url} ${protocol}" ${status} ${bytesSent} "${referer}" "${ua}""
// - "json" → Uses the JSON structured log format: "{"time":"${time}","ip":"${ip}","method":"${method}","url":"${url}","status":${status},"bytesSent":${bytesSent}}"
//
// If no format is specified, the default format is used: "[${time}] ${ip} ${status} - ${latency} ${method} ${path} ${error}"
Format string
// TimeFormat https://programming.guide/go/format-parse-string-time-date-example.html

View File

@ -0,0 +1,16 @@
package logger
const (
FormatDefault = "${time}] ${ip} ${status} - ${latency} ${method} ${path} ${error}"
FormatCommonLog = "${ip} - - [${time}] \"${method} ${url} ${protocol}\" ${status} ${bytesSent}\n"
FormatCombined = "${ip} - - [${time}] \"${method} ${url} ${protocol}\" ${status} ${bytesSent} \"${referer}\" \"${ua}\"\n"
FormatJSON = "{\"time\":\"${time}\",\"ip\":\"${ip}\",\"method\":\"${method}\",\"url\":\"${url}\",\"status\":${status},\"bytesSent\":${bytesSent}}\n"
)
// LoggerConfig provides a mapping of predefined formats
var LoggerConfig = map[string]string{
"default": FormatDefault,
"common": FormatCommonLog,
"combined": FormatCombined,
"json": FormatJSON,
}

View File

@ -31,6 +31,10 @@ func New(config ...Config) fiber.Handler {
// Create correct timeformat
timestamp.Store(time.Now().In(cfg.timeZoneLocation).Format(cfg.TimeFormat))
if logFormat, exists := LoggerConfig[cfg.Format]; exists {
cfg.Format = logFormat
}
// Update date/time every 500 milliseconds in a separate go routine
if strings.Contains(cfg.Format, "${"+TagTime+"}") {
go func() {
@ -40,7 +44,6 @@ func New(config ...Config) fiber.Handler {
}
}()
}
// Set PID once
pid := strconv.Itoa(os.Getpid())

View File

@ -467,6 +467,31 @@ func Test_Logger_All(t *testing.T) {
require.Equal(t, expected, buf.String())
}
func Test_Logger_CLF(t *testing.T) {
t.Parallel()
buf := bytebufferpool.Get()
defer bytebufferpool.Put(buf)
app := fiber.New()
app.Use(New(Config{
Format: "common",
Stream: buf,
}))
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/?foo=bar", nil))
require.NoError(t, err)
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
expected := fmt.Sprintf("0.0.0.0 - - [%s] \"%s %s %s\" %d %d\n",
time.Now().Format("15:04:05"),
fiber.MethodGet, "/?foo=bar", "HTTP/1.1",
fiber.StatusNotFound,
0)
logAnswer := buf.String()
require.Equal(t, expected, logAnswer)
}
func getLatencyTimeUnits() []struct {
unit string
div time.Duration