1// Copyright (c) 2012 - Cloud Instruments Co., Ltd. 2// 3// All rights reserved. 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are met: 7// 8// 1. Redistributions of source code must retain the above copyright notice, this 9// list of conditions and the following disclaimer. 10// 2. Redistributions in binary form must reproduce the above copyright notice, 11// this list of conditions and the following disclaimer in the documentation 12// and/or other materials provided with the distribution. 13// 14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 25package seelog 26 27import ( 28 "errors" 29 "fmt" 30 "sync" 31 "time" 32) 33 34const ( 35 staticFuncCallDepth = 3 // See 'commonLogger.log' method comments 36 loggerFuncCallDepth = 3 37) 38 39// Current is the logger used in all package level convenience funcs like 'Trace', 'Debug', 'Flush', etc. 40var Current LoggerInterface 41 42// Default logger that is created from an empty config: "<seelog/>". It is not closed by a ReplaceLogger call. 43var Default LoggerInterface 44 45// Disabled logger that doesn't produce any output in any circumstances. It is neither closed nor flushed by a ReplaceLogger call. 46var Disabled LoggerInterface 47 48var pkgOperationsMutex *sync.Mutex 49 50func init() { 51 pkgOperationsMutex = new(sync.Mutex) 52 var err error 53 54 if Default == nil { 55 Default, err = LoggerFromConfigAsBytes([]byte("<seelog />")) 56 } 57 58 if Disabled == nil { 59 Disabled, err = LoggerFromConfigAsBytes([]byte("<seelog levels=\"off\"/>")) 60 } 61 62 if err != nil { 63 panic(fmt.Sprintf("Seelog couldn't start. Error: %s", err.Error())) 64 } 65 66 Current = Default 67} 68 69func createLoggerFromFullConfig(config *configForParsing) (LoggerInterface, error) { 70 if config.LogType == syncloggerTypeFromString { 71 return NewSyncLogger(&config.logConfig), nil 72 } else if config.LogType == asyncLooploggerTypeFromString { 73 return NewAsyncLoopLogger(&config.logConfig), nil 74 } else if config.LogType == asyncTimerloggerTypeFromString { 75 logData := config.LoggerData 76 if logData == nil { 77 return nil, errors.New("async timer data not set") 78 } 79 80 asyncInt, ok := logData.(asyncTimerLoggerData) 81 if !ok { 82 return nil, errors.New("invalid async timer data") 83 } 84 85 logger, err := NewAsyncTimerLogger(&config.logConfig, time.Duration(asyncInt.AsyncInterval)) 86 if !ok { 87 return nil, err 88 } 89 90 return logger, nil 91 } else if config.LogType == adaptiveLoggerTypeFromString { 92 logData := config.LoggerData 93 if logData == nil { 94 return nil, errors.New("adaptive logger parameters not set") 95 } 96 97 adaptData, ok := logData.(adaptiveLoggerData) 98 if !ok { 99 return nil, errors.New("invalid adaptive logger parameters") 100 } 101 102 logger, err := NewAsyncAdaptiveLogger( 103 &config.logConfig, 104 time.Duration(adaptData.MinInterval), 105 time.Duration(adaptData.MaxInterval), 106 adaptData.CriticalMsgCount, 107 ) 108 if err != nil { 109 return nil, err 110 } 111 112 return logger, nil 113 } 114 return nil, errors.New("invalid config log type/data") 115} 116 117// UseLogger sets the 'Current' package level logger variable to the specified value. 118// This variable is used in all Trace/Debug/... package level convenience funcs. 119// 120// Example: 121// 122// after calling 123// seelog.UseLogger(somelogger) 124// the following: 125// seelog.Debug("abc") 126// will be equal to 127// somelogger.Debug("abc") 128// 129// IMPORTANT: UseLogger do NOT close the previous logger (only flushes it). So if 130// you constantly use it to replace loggers and don't close them in other code, you'll 131// end up having memory leaks. 132// 133// To safely replace loggers, use ReplaceLogger. 134func UseLogger(logger LoggerInterface) error { 135 if logger == nil { 136 return errors.New("logger can not be nil") 137 } 138 139 pkgOperationsMutex.Lock() 140 defer pkgOperationsMutex.Unlock() 141 142 oldLogger := Current 143 Current = logger 144 145 if oldLogger != nil { 146 oldLogger.Flush() 147 } 148 149 return nil 150} 151 152// ReplaceLogger acts as UseLogger but the logger that was previously 153// used is disposed (except Default and Disabled loggers). 154// 155// Example: 156// import log "github.com/cihub/seelog" 157// 158// func main() { 159// logger, err := log.LoggerFromConfigAsFile("seelog.xml") 160// 161// if err != nil { 162// panic(err) 163// } 164// 165// log.ReplaceLogger(logger) 166// defer log.Flush() 167// 168// log.Trace("test") 169// log.Debugf("var = %s", "abc") 170// } 171func ReplaceLogger(logger LoggerInterface) error { 172 if logger == nil { 173 return errors.New("logger can not be nil") 174 } 175 176 pkgOperationsMutex.Lock() 177 defer pkgOperationsMutex.Unlock() 178 179 defer func() { 180 if err := recover(); err != nil { 181 reportInternalError(fmt.Errorf("recovered from panic during ReplaceLogger: %s", err)) 182 } 183 }() 184 185 if Current == Default { 186 Current.Flush() 187 } else if Current != nil && !Current.Closed() && Current != Disabled { 188 Current.Flush() 189 Current.Close() 190 } 191 192 Current = logger 193 194 return nil 195} 196 197// Tracef formats message according to format specifier 198// and writes to default logger with log level = Trace. 199func Tracef(format string, params ...interface{}) { 200 pkgOperationsMutex.Lock() 201 defer pkgOperationsMutex.Unlock() 202 Current.traceWithCallDepth(staticFuncCallDepth, newLogFormattedMessage(format, params)) 203} 204 205// Debugf formats message according to format specifier 206// and writes to default logger with log level = Debug. 207func Debugf(format string, params ...interface{}) { 208 pkgOperationsMutex.Lock() 209 defer pkgOperationsMutex.Unlock() 210 Current.debugWithCallDepth(staticFuncCallDepth, newLogFormattedMessage(format, params)) 211} 212 213// Infof formats message according to format specifier 214// and writes to default logger with log level = Info. 215func Infof(format string, params ...interface{}) { 216 pkgOperationsMutex.Lock() 217 defer pkgOperationsMutex.Unlock() 218 Current.infoWithCallDepth(staticFuncCallDepth, newLogFormattedMessage(format, params)) 219} 220 221// Warnf formats message according to format specifier and writes to default logger with log level = Warn 222func Warnf(format string, params ...interface{}) error { 223 pkgOperationsMutex.Lock() 224 defer pkgOperationsMutex.Unlock() 225 message := newLogFormattedMessage(format, params) 226 Current.warnWithCallDepth(staticFuncCallDepth, message) 227 return errors.New(message.String()) 228} 229 230// Errorf formats message according to format specifier and writes to default logger with log level = Error 231func Errorf(format string, params ...interface{}) error { 232 pkgOperationsMutex.Lock() 233 defer pkgOperationsMutex.Unlock() 234 message := newLogFormattedMessage(format, params) 235 Current.errorWithCallDepth(staticFuncCallDepth, message) 236 return errors.New(message.String()) 237} 238 239// Criticalf formats message according to format specifier and writes to default logger with log level = Critical 240func Criticalf(format string, params ...interface{}) error { 241 pkgOperationsMutex.Lock() 242 defer pkgOperationsMutex.Unlock() 243 message := newLogFormattedMessage(format, params) 244 Current.criticalWithCallDepth(staticFuncCallDepth, message) 245 return errors.New(message.String()) 246} 247 248// Trace formats message using the default formats for its operands and writes to default logger with log level = Trace 249func Trace(v ...interface{}) { 250 pkgOperationsMutex.Lock() 251 defer pkgOperationsMutex.Unlock() 252 Current.traceWithCallDepth(staticFuncCallDepth, newLogMessage(v)) 253} 254 255// Debug formats message using the default formats for its operands and writes to default logger with log level = Debug 256func Debug(v ...interface{}) { 257 pkgOperationsMutex.Lock() 258 defer pkgOperationsMutex.Unlock() 259 Current.debugWithCallDepth(staticFuncCallDepth, newLogMessage(v)) 260} 261 262// Info formats message using the default formats for its operands and writes to default logger with log level = Info 263func Info(v ...interface{}) { 264 pkgOperationsMutex.Lock() 265 defer pkgOperationsMutex.Unlock() 266 Current.infoWithCallDepth(staticFuncCallDepth, newLogMessage(v)) 267} 268 269// Warn formats message using the default formats for its operands and writes to default logger with log level = Warn 270func Warn(v ...interface{}) error { 271 pkgOperationsMutex.Lock() 272 defer pkgOperationsMutex.Unlock() 273 message := newLogMessage(v) 274 Current.warnWithCallDepth(staticFuncCallDepth, message) 275 return errors.New(message.String()) 276} 277 278// Error formats message using the default formats for its operands and writes to default logger with log level = Error 279func Error(v ...interface{}) error { 280 pkgOperationsMutex.Lock() 281 defer pkgOperationsMutex.Unlock() 282 message := newLogMessage(v) 283 Current.errorWithCallDepth(staticFuncCallDepth, message) 284 return errors.New(message.String()) 285} 286 287// Critical formats message using the default formats for its operands and writes to default logger with log level = Critical 288func Critical(v ...interface{}) error { 289 pkgOperationsMutex.Lock() 290 defer pkgOperationsMutex.Unlock() 291 message := newLogMessage(v) 292 Current.criticalWithCallDepth(staticFuncCallDepth, message) 293 return errors.New(message.String()) 294} 295 296// Flush immediately processes all currently queued messages and all currently buffered messages. 297// It is a blocking call which returns only after the queue is empty and all the buffers are empty. 298// 299// If Flush is called for a synchronous logger (type='sync'), it only flushes buffers (e.g. '<buffered>' receivers) 300// , because there is no queue. 301// 302// Call this method when your app is going to shut down not to lose any log messages. 303func Flush() { 304 pkgOperationsMutex.Lock() 305 defer pkgOperationsMutex.Unlock() 306 Current.Flush() 307} 308