package golang_logger import ( "fmt" "strings" "time" ) type Handler interface { Log(msg logFormat) } type Logger struct { handlers []Handler level Level channel string extraFunc func() interface{} } type logFormat struct { Message string `json:"message"` Context interface{} `json:"context"` Level int `json:"level"` LevelName string `json:"level_name"` Channel string `json:"channel"` DateTime string `json:"date_time"` Extra interface{} `json:"extra"` } type Level int const ( Debug Level = 100 Info Level = 200 Notice Level = 250 Warn Level = 300 Error Level = 400 Fatal Level = 500 Emerg Level = 600 ) func NewLogger(channel string, level Level, handlers ...Handler) *Logger { return &Logger{ level: level, handlers: handlers, channel: channel, } } func (l *Logger) PushHandler(handler Handler) *Logger { l.handlers = append(l.handlers, handler) return l } func (l *Logger) ExtraFunc(f func() interface{}) *Logger { l.extraFunc = f return l } func LevelFromString(l string) Level { switch strings.ToLower(l) { case "debug": return Debug case "info": return Info case "notice": return Notice case "warn": return Warn case "error": return Error case "fatal": return Fatal case "emerg": return Emerg default: return Debug } } func (l *Level) String() string { switch *l { case Debug: return "DEBUG" case Info: return "INFO" case Notice: return "NOTICE" case Warn: return "WARN" case Error: return "ERROR" case Fatal: return "FATAL" case Emerg: return "EMERG" default: return "UNKNOWN" } } // Fatal logs a fatal message and exits func (l *Logger) Fatal(msg string, context ...interface{}) { l.log(Fatal, msg, context...) } // Error logs an error message func (l *Logger) Error(msg string, context ...interface{}) { l.log(Error, msg, context...) } // Warn logs a warning message func (l *Logger) Warn(msg string, context ...interface{}) { l.log(Warn, msg, context...) } // Info logs an info message func (l *Logger) Info(msg string, context ...interface{}) { l.log(Info, msg, context...) } // Infof logs an info message with formatting func (l *Logger) Infof(msg string, context ...interface{}) { l.log(Info, fmt.Sprintf(msg, context...)) } // Debug logs a debug message func (l *Logger) Debug(msg string, context ...interface{}) { l.log(Debug, msg, context...) } func (l *Logger) log(level Level, msg string, context ...interface{}) { // check if the level is allowed if int32(l.level) > int32(level) { return } var extra interface{} if l.extraFunc != nil { extra = l.extraFunc() } logFormated := logFormat{ Message: msg, Context: context, Level: int(level), LevelName: level.String(), Channel: l.channel, DateTime: time.Now().Format(time.RFC3339Nano), Extra: extra, } for _, handler := range l.handlers { (handler).Log(logFormated) } }