Logger
Logger middleware logs the information about each HTTP request.
Echo has 2 different logger middlewares:
- Older string template based logger
Logger
- easy to start with but has limited capabilities - Newer customizable function based logger
RequestLogger
- allows developer fully to customize what is logged and how it is logged. Suitable for usage with 3rd party logger libraries.
Old Logger middleware
Usage
e.Use(middleware.Logger())
Sample output
{"time":"2017-01-12T08:58:07.372015644-08:00","remote_ip":"::1","host":"localhost:1323","method":"GET","uri":"/","status":200,"error":"","latency":14743,"latency_human":"14.743µs","bytes_in":0,"bytes_out":2}
Custom Configuration
Usage
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Format: "method=${method}, uri=${uri}, status=${status}\n",
}))
Example above uses a Format
which logs request method and request URI.
Sample output
method=GET, uri=/, status=200
Configuration
// LoggerConfig defines the config for Logger middleware.
LoggerConfig struct {
// Skipper defines a function to skip middleware.
Skipper Skipper
// Tags to construct the logger format.
//
// - time_unix
// - time_unix_milli
// - time_unix_micro
// - time_unix_nano
// - time_rfc3339
// - time_rfc3339_nano
// - time_custom
// - id (Request ID)
// - remote_ip
// - uri
// - host
// - method
// - path
// - protocol
// - referer
// - user_agent
// - status
// - error
// - latency (In nanoseconds)
// - latency_human (Human readable)
// - bytes_in (Bytes received)
// - bytes_out (Bytes sent)
// - header:<NAME>
// - query:<NAME>
// - form:<NAME>
//
// Example "${remote_ip} ${status}"
//
// Optional. Default value DefaultLoggerConfig.Format.
Format string `yaml:"format"`
// Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
CustomTimeFormat string `yaml:"custom_time_format"`
// Output is a writer where logs in JSON format are written.
// Optional. Default value os.Stdout.
Output io.Writer
}
Default Configuration
DefaultLoggerConfig = LoggerConfig{
Skipper: DefaultSkipper,
Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}",` +
`"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` +
`"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` +
`,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n",
CustomTimeFormat: "2006-01-02 15:04:05.00000",
}
New RequestLogger middleware
RequestLogger middleware allows developer fully to customize what is logged and how it is logged and is more suitable for usage with 3rd party (structured logging) libraries.
See RequestLoggerConfig
structure fields for values that logger knows to extract.
Examples
Example for naive fmt.Printf
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogStatus: true,
LogURI: true,
BeforeNextFunc: func(c echo.Context) {
c.Set("customValueFromContext", 42)
},
LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
value, _ := c.Get("customValueFromContext").(int)
fmt.Printf("REQUEST: uri: %v, status: %v, custom-value: %v\n", v.URI, v.Status, value)
return nil
},
}))
Example for slog (https://pkg.go.dev/log/slog)
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogStatus: true,
LogURI: true,
LogError: true,
HandleError: true, // forwards error to the global error handler, so it can decide appropriate status code
LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
if v.Error == nil {
logger.LogAttrs(context.Background(), slog.LevelInfo, "REQUEST",
slog.String("uri", v.URI),
slog.Int("status", v.Status),
)
} else {
logger.LogAttrs(context.Background(), slog.LevelError, "REQUEST_ERROR",
slog.String("uri", v.URI),
slog.Int("status", v.Status),
slog.String("err", v.Error.Error()),
)
}
return nil
},
}))
Example for Zerolog (https://github.com/rs/zerolog)
logger := zerolog.New(os.Stdout)
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogURI: true,
LogStatus: true,
LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
logger.Info().
Str("URI", v.URI).
Int("status", v.Status).
Msg("request")
return nil
},
}))
Example for Zap (https://github.com/uber-go/zap)
logger, _ := zap.NewProduction()
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogURI: true,
LogStatus: true,
LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
logger.Info("request",
zap.String("URI", v.URI),
zap.Int("status", v.Status),
)
return nil
},
}))
Example for Logrus (https://github.com/sirupsen/logrus)
log := logrus.New()
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogURI: true,
LogStatus: true,
LogValuesFunc: func(c echo.Context, values middleware.RequestLoggerValues) error {
log.WithFields(logrus.Fields{
"URI": values.URI,
"status": values.Status,
}).Info("request")
return nil
},
}))