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