goa.design custom zerolog logger with HTTP Info, Warn and Error codes
Sun, Apr 21, 2024
2-minute read
goa.design custom zerolog logger with HTTP Info, Warn and Error codes
By default the goa logger isn’t great IMO. I like zerolog and have created a custom logger.
You could also use slog or zap, basically anything as long as it has these methods to implement the Logger interface.
package logger
import (
"fmt"
"os"
"github.com/rs/zerolog"
)
// Logger is an adapted zerologger
type Logger struct {
*zerolog.Logger
}
func New(serviceName string, isDebug, isConsole bool) *Logger {
logLevel := zerolog.InfoLevel
if isDebug {
logLevel = zerolog.DebugLevel
}
zerolog.SetGlobalLevel(logLevel)
svclogger := zerolog.New(os.Stderr).With().Timestamp().Str("service", serviceName).Logger()
if isConsole {
svclogger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout}).
With().
Timestamp().
Str("service", serviceName).
Logger()
}
return &Logger{&svclogger}
}
// Log is called by the log middleware to log HTTP requests key values
func (logger *Logger) Log(keyvals ...interface{}) error {
fields := FormatFields(keyvals)
// If this isn't here, all HTTP requests get a zerolog.Info() block
// which is super confusing when a request is a 5xx so I've overridden it
if status, ok := fields["status"].(int); ok {
s := status / 100
switch s {
case 4:
logger.Warn().Fields(fields).Msgf("HTTP Request")
return nil
case 5:
logger.Error().Fields(fields).Msgf("HTTP Request")
return nil
}
}
logger.Info().Fields(fields).Msgf("HTTP Request")
return nil
}
// FormatFields formats input keyvals
// ref: https://github.com/goadesign/goa/blob/v1/logging/logrus/adapter.go#L64
func FormatFields(keyvals []interface{}) map[string]interface{} {
n := (len(keyvals) + 1) / 2
res := make(map[string]interface{}, n)
for i := 0; i < len(keyvals); i += 2 {
k := keyvals[i]
var v interface{}
if i+1 < len(keyvals) {
v = keyvals[i+1]
}
res[fmt.Sprintf("%v", k)] = v
}
return res
}
Tags:
#zerolog #go #goa