code.gitea.io/gitea@v1.19.3/modules/log/log.go (about) 1 // Copyright 2014 The Gogs Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package log 5 6 import ( 7 "fmt" 8 "os" 9 "runtime" 10 "strings" 11 "sync" 12 13 "code.gitea.io/gitea/modules/process" 14 ) 15 16 type loggerMap struct { 17 sync.Map 18 } 19 20 func (m *loggerMap) Load(k string) (*MultiChannelledLogger, bool) { 21 v, ok := m.Map.Load(k) 22 if !ok { 23 return nil, false 24 } 25 l, ok := v.(*MultiChannelledLogger) 26 return l, ok 27 } 28 29 func (m *loggerMap) Store(k string, v *MultiChannelledLogger) { 30 m.Map.Store(k, v) 31 } 32 33 func (m *loggerMap) Delete(k string) { 34 m.Map.Delete(k) 35 } 36 37 var ( 38 // DEFAULT is the name of the default logger 39 DEFAULT = "default" 40 // NamedLoggers map of named loggers 41 NamedLoggers loggerMap 42 prefix string 43 ) 44 45 // NewLogger create a logger for the default logger 46 func NewLogger(bufLen int64, name, provider, config string) *MultiChannelledLogger { 47 err := NewNamedLogger(DEFAULT, bufLen, name, provider, config) 48 if err != nil { 49 CriticalWithSkip(1, "Unable to create default logger: %v", err) 50 panic(err) 51 } 52 l, _ := NamedLoggers.Load(DEFAULT) 53 return l 54 } 55 56 // NewNamedLogger creates a new named logger for a given configuration 57 func NewNamedLogger(name string, bufLen int64, subname, provider, config string) error { 58 logger, ok := NamedLoggers.Load(name) 59 if !ok { 60 logger = newLogger(name, bufLen) 61 NamedLoggers.Store(name, logger) 62 } 63 64 return logger.SetLogger(subname, provider, config) 65 } 66 67 // DelNamedLogger closes and deletes the named logger 68 func DelNamedLogger(name string) { 69 l, ok := NamedLoggers.Load(name) 70 if ok { 71 NamedLoggers.Delete(name) 72 l.Close() 73 } 74 } 75 76 // DelLogger removes the named sublogger from the default logger 77 func DelLogger(name string) error { 78 logger, _ := NamedLoggers.Load(DEFAULT) 79 found, err := logger.DelLogger(name) 80 if !found { 81 Trace("Log %s not found, no need to delete", name) 82 } 83 return err 84 } 85 86 // GetLogger returns either a named logger or the default logger 87 func GetLogger(name string) *MultiChannelledLogger { 88 logger, ok := NamedLoggers.Load(name) 89 if ok { 90 return logger 91 } 92 logger, _ = NamedLoggers.Load(DEFAULT) 93 return logger 94 } 95 96 // GetLevel returns the minimum logger level 97 func GetLevel() Level { 98 l, _ := NamedLoggers.Load(DEFAULT) 99 return l.GetLevel() 100 } 101 102 // GetStacktraceLevel returns the minimum logger level 103 func GetStacktraceLevel() Level { 104 l, _ := NamedLoggers.Load(DEFAULT) 105 return l.GetStacktraceLevel() 106 } 107 108 // Trace records trace log 109 func Trace(format string, v ...interface{}) { 110 Log(1, TRACE, format, v...) 111 } 112 113 // IsTrace returns true if at least one logger is TRACE 114 func IsTrace() bool { 115 return GetLevel() <= TRACE 116 } 117 118 // Debug records debug log 119 func Debug(format string, v ...interface{}) { 120 Log(1, DEBUG, format, v...) 121 } 122 123 // IsDebug returns true if at least one logger is DEBUG 124 func IsDebug() bool { 125 return GetLevel() <= DEBUG 126 } 127 128 // Info records info log 129 func Info(format string, v ...interface{}) { 130 Log(1, INFO, format, v...) 131 } 132 133 // IsInfo returns true if at least one logger is INFO 134 func IsInfo() bool { 135 return GetLevel() <= INFO 136 } 137 138 // Warn records warning log 139 func Warn(format string, v ...interface{}) { 140 Log(1, WARN, format, v...) 141 } 142 143 // IsWarn returns true if at least one logger is WARN 144 func IsWarn() bool { 145 return GetLevel() <= WARN 146 } 147 148 // Error records error log 149 func Error(format string, v ...interface{}) { 150 Log(1, ERROR, format, v...) 151 } 152 153 // ErrorWithSkip records error log from "skip" calls back from this function 154 func ErrorWithSkip(skip int, format string, v ...interface{}) { 155 Log(skip+1, ERROR, format, v...) 156 } 157 158 // IsError returns true if at least one logger is ERROR 159 func IsError() bool { 160 return GetLevel() <= ERROR 161 } 162 163 // Critical records critical log 164 func Critical(format string, v ...interface{}) { 165 Log(1, CRITICAL, format, v...) 166 } 167 168 // CriticalWithSkip records critical log from "skip" calls back from this function 169 func CriticalWithSkip(skip int, format string, v ...interface{}) { 170 Log(skip+1, CRITICAL, format, v...) 171 } 172 173 // IsCritical returns true if at least one logger is CRITICAL 174 func IsCritical() bool { 175 return GetLevel() <= CRITICAL 176 } 177 178 // Fatal records fatal log and exit process 179 func Fatal(format string, v ...interface{}) { 180 Log(1, FATAL, format, v...) 181 Close() 182 os.Exit(1) 183 } 184 185 // FatalWithSkip records fatal log from "skip" calls back from this function 186 func FatalWithSkip(skip int, format string, v ...interface{}) { 187 Log(skip+1, FATAL, format, v...) 188 Close() 189 os.Exit(1) 190 } 191 192 // IsFatal returns true if at least one logger is FATAL 193 func IsFatal() bool { 194 return GetLevel() <= FATAL 195 } 196 197 // Pause pauses all the loggers 198 func Pause() { 199 NamedLoggers.Range(func(key, value interface{}) bool { 200 logger := value.(*MultiChannelledLogger) 201 logger.Pause() 202 logger.Flush() 203 return true 204 }) 205 } 206 207 // Resume resumes all the loggers 208 func Resume() { 209 NamedLoggers.Range(func(key, value interface{}) bool { 210 logger := value.(*MultiChannelledLogger) 211 logger.Resume() 212 return true 213 }) 214 } 215 216 // ReleaseReopen releases and reopens logging files 217 func ReleaseReopen() error { 218 var accumulatedErr error 219 NamedLoggers.Range(func(key, value interface{}) bool { 220 logger := value.(*MultiChannelledLogger) 221 if err := logger.ReleaseReopen(); err != nil { 222 if accumulatedErr == nil { 223 accumulatedErr = fmt.Errorf("Error reopening %s: %w", key.(string), err) 224 } else { 225 accumulatedErr = fmt.Errorf("Error reopening %s: %v & %w", key.(string), err, accumulatedErr) 226 } 227 } 228 return true 229 }) 230 return accumulatedErr 231 } 232 233 // Close closes all the loggers 234 func Close() { 235 l, ok := NamedLoggers.Load(DEFAULT) 236 if !ok { 237 return 238 } 239 NamedLoggers.Delete(DEFAULT) 240 l.Close() 241 } 242 243 // Log a message with defined skip and at logging level 244 // A skip of 0 refers to the caller of this command 245 func Log(skip int, level Level, format string, v ...interface{}) { 246 l, ok := NamedLoggers.Load(DEFAULT) 247 if ok { 248 l.Log(skip+1, level, format, v...) 249 } 250 } 251 252 // LoggerAsWriter is a io.Writer shim around the gitea log 253 type LoggerAsWriter struct { 254 ourLoggers []*MultiChannelledLogger 255 level Level 256 } 257 258 // NewLoggerAsWriter creates a Writer representation of the logger with setable log level 259 func NewLoggerAsWriter(level string, ourLoggers ...*MultiChannelledLogger) *LoggerAsWriter { 260 if len(ourLoggers) == 0 { 261 l, _ := NamedLoggers.Load(DEFAULT) 262 ourLoggers = []*MultiChannelledLogger{l} 263 } 264 l := &LoggerAsWriter{ 265 ourLoggers: ourLoggers, 266 level: FromString(level), 267 } 268 return l 269 } 270 271 // Write implements the io.Writer interface to allow spoofing of chi 272 func (l *LoggerAsWriter) Write(p []byte) (int, error) { 273 for _, logger := range l.ourLoggers { 274 // Skip = 3 because this presumes that we have been called by log.Println() 275 // If the caller has used log.Output or the like this will be wrong 276 logger.Log(3, l.level, string(p)) 277 } 278 return len(p), nil 279 } 280 281 // Log takes a given string and logs it at the set log-level 282 func (l *LoggerAsWriter) Log(msg string) { 283 for _, logger := range l.ourLoggers { 284 // Set the skip to reference the call just above this 285 _ = logger.Log(1, l.level, msg) 286 } 287 } 288 289 func init() { 290 process.Trace = func(start bool, pid process.IDType, description string, parentPID process.IDType, typ string) { 291 if start && parentPID != "" { 292 Log(1, TRACE, "Start %s: %s (from %s) (%s)", NewColoredValue(pid, FgHiYellow), description, NewColoredValue(parentPID, FgYellow), NewColoredValue(typ, Reset)) 293 } else if start { 294 Log(1, TRACE, "Start %s: %s (%s)", NewColoredValue(pid, FgHiYellow), description, NewColoredValue(typ, Reset)) 295 } else { 296 Log(1, TRACE, "Done %s: %s", NewColoredValue(pid, FgHiYellow), NewColoredValue(description, Reset)) 297 } 298 } 299 _, filename, _, _ := runtime.Caller(0) 300 prefix = strings.TrimSuffix(filename, "modules/log/log.go") 301 if prefix == filename { 302 // in case the source code file is moved, we can not trim the suffix, the code above should also be updated. 303 panic("unable to detect correct package prefix, please update file: " + filename) 304 } 305 }