github.com/keakon/golog@v0.0.0-20230330091222-cac71197c18d/logger.go (about) 1 package golog 2 3 import ( 4 "io" 5 "sort" 6 "time" 7 ) 8 9 // Level specifies the log level. 10 type Level uint8 11 12 // All the log levels. 13 const ( 14 DebugLevel Level = iota 15 InfoLevel 16 WarnLevel 17 ErrorLevel 18 CritLevel 19 20 disabledLevel Level = 255 21 ) 22 23 var ( 24 levelNames = []byte("DIWEC") 25 26 internalLogger *Logger 27 ) 28 29 // A Record is an item which contains required context for the logger. 30 type Record struct { 31 date string 32 time string 33 file string 34 message string 35 args []interface{} 36 tm time.Time 37 line int 38 level Level 39 } 40 41 // A Logger is a leveled logger with several handlers. 42 type Logger struct { 43 handlers []*Handler 44 minLevel Level // the min level of the logger and its handlers 45 level Level // the lowest acceptable level of the logger 46 isInternal bool 47 } 48 49 // NewLogger creates a new Logger of the given level. 50 // Messages with lower level than the logger will be ignored. 51 func NewLogger(lv Level) *Logger { 52 return &Logger{level: lv, minLevel: disabledLevel} // disable all levels for empty logger 53 } 54 55 // AddHandler adds a Handler to the Logger. 56 func (l *Logger) AddHandler(h *Handler) { 57 h.isInternal = l.isInternal 58 l.handlers = append(l.handlers, h) 59 60 if len(l.handlers) > 1 { 61 sort.Slice(l.handlers, func(i, j int) bool { 62 return l.handlers[i].level < l.handlers[j].level 63 }) 64 } 65 66 minLevel := l.handlers[0].level 67 if l.level >= minLevel { 68 l.minLevel = l.level 69 } else { 70 l.minLevel = minLevel 71 } 72 } 73 74 // IsEnabledFor returns whether it's enabled for the level. 75 func (l *Logger) IsEnabledFor(level Level) bool { 76 return l.minLevel <= level 77 } 78 79 // GetMinLevel returns its minLevel. 80 // Records lower than its minLevel will be ignored. 81 func (l *Logger) GetMinLevel() Level { 82 return l.minLevel 83 } 84 85 // Log logs a message with context. 86 // A logger should check the message level before call its Log(). 87 // The line param should be uint32. 88 // It's not thread-safe, concurrent messages may be written in a random order 89 // through different handlers or writers. 90 // But two messages won't be mixed in a single line. 91 func (l *Logger) Log(lv Level, file string, line int, msg string, args ...interface{}) { 92 r := recordPool.Get().(*Record) 93 r.level = lv 94 if fastTimer.isRunning { 95 r.date = fastTimer.date 96 r.time = fastTimer.time 97 } else { 98 r.tm = now() 99 } 100 r.file = file 101 r.line = line 102 r.message = msg 103 r.args = args 104 105 for _, h := range l.handlers { 106 if !h.Handle(r) { 107 break 108 } 109 } 110 111 recordPool.Put(r) 112 } 113 114 // Close closes its handlers. 115 // It's safe to call this method more than once. 116 func (l *Logger) Close() { 117 for _, h := range l.handlers { 118 h.Close() 119 } 120 l.handlers = nil 121 } 122 123 // Debug logs a debug level message. It uses fmt.Fprint() to format args. 124 func (l *Logger) Debug(args ...interface{}) { 125 if l.IsEnabledFor(DebugLevel) { 126 file, line := Caller(1) // deeper caller will be more expensive 127 l.Log(DebugLevel, file, line, "", args...) 128 } 129 } 130 131 // Debugf logs a debug level message. It uses fmt.Fprintf() to format msg and args. 132 func (l *Logger) Debugf(msg string, args ...interface{}) { 133 if l.IsEnabledFor(DebugLevel) { 134 file, line := Caller(1) 135 l.Log(DebugLevel, file, line, msg, args...) 136 } 137 } 138 139 // Info logs a info level message. It uses fmt.Fprint() to format args. 140 func (l *Logger) Info(args ...interface{}) { 141 if l.IsEnabledFor(InfoLevel) { 142 file, line := Caller(1) 143 l.Log(InfoLevel, file, line, "", args...) 144 } 145 } 146 147 // Infof logs a info level message. It uses fmt.Fprintf() to format msg and args. 148 func (l *Logger) Infof(msg string, args ...interface{}) { 149 if l.IsEnabledFor(InfoLevel) { 150 file, line := Caller(1) 151 l.Log(InfoLevel, file, line, msg, args...) 152 } 153 } 154 155 // Warn logs a warning level message. It uses fmt.Fprint() to format args. 156 func (l *Logger) Warn(args ...interface{}) { 157 if l.IsEnabledFor(WarnLevel) { 158 file, line := Caller(1) 159 l.Log(WarnLevel, file, line, "", args...) 160 } 161 } 162 163 // Warnf logs a warning level message. It uses fmt.Fprintf() to format msg and args. 164 func (l *Logger) Warnf(msg string, args ...interface{}) { 165 if l.IsEnabledFor(WarnLevel) { 166 file, line := Caller(1) 167 l.Log(WarnLevel, file, line, msg, args...) 168 } 169 } 170 171 // Error logs an error level message. It uses fmt.Fprint() to format args. 172 func (l *Logger) Error(args ...interface{}) { 173 if l.IsEnabledFor(ErrorLevel) { 174 file, line := Caller(1) 175 l.Log(ErrorLevel, file, line, "", args...) 176 } 177 } 178 179 // Errorf logs a error level message. It uses fmt.Fprintf() to format msg and args. 180 func (l *Logger) Errorf(msg string, args ...interface{}) { 181 if l.IsEnabledFor(ErrorLevel) { 182 file, line := Caller(1) 183 l.Log(ErrorLevel, file, line, msg, args...) 184 } 185 } 186 187 // Crit logs a critical level message. It uses fmt.Fprint() to format args. 188 func (l *Logger) Crit(args ...interface{}) { 189 if l.IsEnabledFor(CritLevel) { 190 file, line := Caller(1) 191 l.Log(CritLevel, file, line, "", args...) 192 } 193 } 194 195 // Critf logs a critical level message. It uses fmt.Fprintf() to format msg and args. 196 func (l *Logger) Critf(msg string, args ...interface{}) { 197 if l.IsEnabledFor(CritLevel) { 198 file, line := Caller(1) 199 l.Log(CritLevel, file, line, msg, args...) 200 } 201 } 202 203 // NewLoggerWithWriter creates an info level logger with a writer. 204 func NewLoggerWithWriter(w io.WriteCloser) *Logger { 205 h := NewHandler(InfoLevel, DefaultFormatter) 206 h.AddWriter(w) 207 l := NewLogger(InfoLevel) 208 l.AddHandler(h) 209 return l 210 } 211 212 // NewStdoutLogger creates a logger with a stdout writer. 213 func NewStdoutLogger() *Logger { 214 return NewLoggerWithWriter(NewStdoutWriter()) 215 } 216 217 // NewStderrLogger creates a logger with a stderr writer. 218 func NewStderrLogger() *Logger { 219 return NewLoggerWithWriter(NewStderrWriter()) 220 } 221 222 // SetInternalLogger sets a logger as the internalLogger which is used to log internal errors. 223 // The logger and its handlers will be marked as internal, so do not reuse them. 224 // The internalLogger may discard its own errors to prevent recursive log. 225 func SetInternalLogger(l *Logger) { 226 if internalLogger != nil { 227 internalLogger.isInternal = false 228 for _, h := range internalLogger.handlers { 229 h.isInternal = false 230 } 231 } 232 233 if l != nil { 234 l.isInternal = true 235 for _, h := range l.handlers { 236 h.isInternal = true 237 } 238 } 239 240 internalLogger = l 241 }