github.com/sharovik/devbot@v1.0.1-0.20240308094637-4a0387c40516/internal/log/logger.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "io" 6 7 "github.com/pkg/errors" 8 "github.com/rs/zerolog" 9 "github.com/rs/zerolog/log" 10 "github.com/rs/zerolog/pkgerrors" 11 ) 12 13 var loggerInstance LoggerInstance 14 15 // Config configuration required by Logger 16 type Config struct { 17 Env string 18 Output string 19 Level string 20 FieldContext string 21 FieldLevelName string 22 FieldErrorMessage string 23 } 24 25 // LoggerInstance shared state 26 type LoggerInstance struct { 27 config Config 28 env string 29 context map[string]interface{} 30 initialized bool 31 } 32 33 // default constants 34 const ( 35 FieldContext = "context" 36 FieldLevelName = "level_name" 37 FieldErrorMessage = "error_message" 38 39 appEnvTesting = "testing" 40 41 Dbg = "debug" 42 Inf = "info" 43 Err = "error" 44 Warn = "warn" 45 Fatal = "fatal" 46 Panic = "panic" 47 48 OutputConsole = "console" 49 OutputJSON = "json" 50 ) 51 52 func (l *LoggerInstance) setLogLevel() { 53 switch l.config.Level { 54 case Dbg: 55 zerolog.SetGlobalLevel(zerolog.DebugLevel) 56 case Inf: 57 zerolog.SetGlobalLevel(zerolog.InfoLevel) 58 case Err: 59 zerolog.SetGlobalLevel(zerolog.ErrorLevel) 60 case Warn: 61 zerolog.SetGlobalLevel(zerolog.WarnLevel) 62 case Fatal: 63 zerolog.SetGlobalLevel(zerolog.FatalLevel) 64 case Panic: 65 zerolog.SetGlobalLevel(zerolog.PanicLevel) 66 default: 67 zerolog.SetGlobalLevel(zerolog.InfoLevel) 68 } 69 } 70 71 func (l *LoggerInstance) getOutput() zerolog.Context { 72 switch l.config.Output { 73 case OutputConsole: 74 return log.Output(zerolog.NewConsoleWriter()).With() 75 case OutputJSON: 76 return log.With() 77 } 78 79 return log.With() 80 } 81 82 // Init initializes the logger (required before use) 83 func Init(config Config) error { 84 loggerInstance = LoggerInstance{ 85 config: config, 86 env: config.Env, 87 context: make(map[string]interface{}), 88 initialized: true, 89 } 90 91 return nil 92 } 93 94 // Refresh refreshes the logger instance 95 func Refresh() { 96 loggerInstance = LoggerInstance{} 97 } 98 99 // IsInitialized function retrieves current status of logger instance 100 func IsInitialized() bool { 101 return loggerInstance.initialized 102 } 103 104 // Logger returns a pointer to the singleton Logger loggerInstance 105 func Logger() *LoggerInstance { 106 if !loggerInstance.initialized { 107 panic("logger not initialized") 108 } 109 return &loggerInstance 110 } 111 112 // AppendGlobalContext for setting global context 113 func (l *LoggerInstance) AppendGlobalContext(context map[string]interface{}) { 114 if l.context == nil { 115 l.context = context 116 } 117 118 for field, value := range context { 119 l.context[field] = value 120 } 121 122 l.Debug().Interface("context_changes", context).Msg("Append new global context") 123 } 124 125 // GlobalContext method retrieve the GlobalContext variable 126 func (l *LoggerInstance) GlobalContext() map[string]interface{} { 127 return l.context 128 } 129 130 // DestroyGlobalContext method for global context destroy 131 func (l *LoggerInstance) DestroyGlobalContext() { 132 l.context = make(map[string]interface{}) 133 } 134 135 // AddError for correct error messages parse 136 func (l *LoggerInstance) AddError(err error) *zerolog.Event { 137 err = errors.Wrap(err, err.Error()) 138 return l.Error().Stack().Err(err) 139 } 140 141 // DefaultContext method which returns Logger with default context 142 func (l *LoggerInstance) DefaultContext() *zerolog.Logger { 143 l.setLogLevel() 144 var context = zerolog.Context{} 145 switch l.config.Env { 146 case appEnvTesting: 147 //For testing environment we need to disable the logs 148 context = log.Output(io.Discard).With() 149 default: 150 context = l.getOutput() 151 } 152 153 zerolog.TimestampFieldName = "@timestamp" 154 zerolog.LevelFieldName = l.config.FieldLevelName 155 zerolog.ErrorFieldName = l.config.FieldErrorMessage 156 zerolog.TimeFieldFormat = "2006-01-02T15:04:05.000000" 157 zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack 158 159 logger := context. 160 Interface(l.config.FieldContext, l.context). 161 Logger() 162 163 return &logger 164 } 165 166 // Debug method for messages with level DEBUG 167 func (l *LoggerInstance) Debug() *zerolog.Event { 168 return l.DefaultContext().Debug() 169 } 170 171 // Info method for messages with level INFO 172 func (l *LoggerInstance) Info() *zerolog.Event { 173 return l.DefaultContext().Info() 174 } 175 176 // Error method for messages with level ERROR 177 func (l *LoggerInstance) Error() *zerolog.Event { 178 return l.DefaultContext().Error() 179 } 180 181 // Warn method for messages with level WARNING 182 func (l *LoggerInstance) Warn() *zerolog.Event { 183 return l.DefaultContext().Warn() 184 } 185 186 // StartMessage adds message with START postfix 187 func (l *LoggerInstance) StartMessage(msg string) { 188 l.DefaultContext().Info().Msg(fmt.Sprintf("%s: %s", msg, "START")) 189 } 190 191 // FinishMessage adds message with FINISH postfix 192 func (l *LoggerInstance) FinishMessage(msg string) { 193 l.DefaultContext().Info().Msg(fmt.Sprintf("%s: %s", msg, "FINISH")) 194 }