github.com/astaxie/beego@v1.12.3/logs/log.go (about)

     1  // Copyright 2014 beego Author. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package logs provide a general log interface
    16  // Usage:
    17  //
    18  // import "github.com/astaxie/beego/logs"
    19  //
    20  //	log := NewLogger(10000)
    21  //	log.SetLogger("console", "")
    22  //
    23  //	> the first params stand for how many channel
    24  //
    25  // Use it like this:
    26  //
    27  //	log.Trace("trace")
    28  //	log.Info("info")
    29  //	log.Warn("warning")
    30  //	log.Debug("debug")
    31  //	log.Critical("critical")
    32  //
    33  //  more docs http://beego.me/docs/module/logs.md
    34  package logs
    35  
    36  import (
    37  	"fmt"
    38  	"log"
    39  	"os"
    40  	"path"
    41  	"runtime"
    42  	"strconv"
    43  	"strings"
    44  	"sync"
    45  	"time"
    46  )
    47  
    48  // RFC5424 log message levels.
    49  const (
    50  	LevelEmergency = iota
    51  	LevelAlert
    52  	LevelCritical
    53  	LevelError
    54  	LevelWarning
    55  	LevelNotice
    56  	LevelInformational
    57  	LevelDebug
    58  )
    59  
    60  // levelLogLogger is defined to implement log.Logger
    61  // the real log level will be LevelEmergency
    62  const levelLoggerImpl = -1
    63  
    64  // Name for adapter with beego official support
    65  const (
    66  	AdapterConsole   = "console"
    67  	AdapterFile      = "file"
    68  	AdapterMultiFile = "multifile"
    69  	AdapterMail      = "smtp"
    70  	AdapterConn      = "conn"
    71  	AdapterEs        = "es"
    72  	AdapterJianLiao  = "jianliao"
    73  	AdapterSlack     = "slack"
    74  	AdapterAliLS     = "alils"
    75  )
    76  
    77  // Legacy log level constants to ensure backwards compatibility.
    78  const (
    79  	LevelInfo  = LevelInformational
    80  	LevelTrace = LevelDebug
    81  	LevelWarn  = LevelWarning
    82  )
    83  
    84  type newLoggerFunc func() Logger
    85  
    86  // Logger defines the behavior of a log provider.
    87  type Logger interface {
    88  	Init(config string) error
    89  	WriteMsg(when time.Time, msg string, level int) error
    90  	Destroy()
    91  	Flush()
    92  }
    93  
    94  var adapters = make(map[string]newLoggerFunc)
    95  var levelPrefix = [LevelDebug + 1]string{"[M]", "[A]", "[C]", "[E]", "[W]", "[N]", "[I]", "[D]"}
    96  
    97  // Register makes a log provide available by the provided name.
    98  // If Register is called twice with the same name or if driver is nil,
    99  // it panics.
   100  func Register(name string, log newLoggerFunc) {
   101  	if log == nil {
   102  		panic("logs: Register provide is nil")
   103  	}
   104  	if _, dup := adapters[name]; dup {
   105  		panic("logs: Register called twice for provider " + name)
   106  	}
   107  	adapters[name] = log
   108  }
   109  
   110  // BeeLogger is default logger in beego application.
   111  // it can contain several providers and log message into all providers.
   112  type BeeLogger struct {
   113  	lock                sync.Mutex
   114  	level               int
   115  	init                bool
   116  	enableFuncCallDepth bool
   117  	loggerFuncCallDepth int
   118  	asynchronous        bool
   119  	prefix              string
   120  	msgChanLen          int64
   121  	msgChan             chan *logMsg
   122  	signalChan          chan string
   123  	wg                  sync.WaitGroup
   124  	outputs             []*nameLogger
   125  }
   126  
   127  const defaultAsyncMsgLen = 1e3
   128  
   129  type nameLogger struct {
   130  	Logger
   131  	name string
   132  }
   133  
   134  type logMsg struct {
   135  	level int
   136  	msg   string
   137  	when  time.Time
   138  }
   139  
   140  var logMsgPool *sync.Pool
   141  
   142  // NewLogger returns a new BeeLogger.
   143  // channelLen means the number of messages in chan(used where asynchronous is true).
   144  // if the buffering chan is full, logger adapters write to file or other way.
   145  func NewLogger(channelLens ...int64) *BeeLogger {
   146  	bl := new(BeeLogger)
   147  	bl.level = LevelDebug
   148  	bl.loggerFuncCallDepth = 2
   149  	bl.msgChanLen = append(channelLens, 0)[0]
   150  	if bl.msgChanLen <= 0 {
   151  		bl.msgChanLen = defaultAsyncMsgLen
   152  	}
   153  	bl.signalChan = make(chan string, 1)
   154  	bl.setLogger(AdapterConsole)
   155  	return bl
   156  }
   157  
   158  // Async set the log to asynchronous and start the goroutine
   159  func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger {
   160  	bl.lock.Lock()
   161  	defer bl.lock.Unlock()
   162  	if bl.asynchronous {
   163  		return bl
   164  	}
   165  	bl.asynchronous = true
   166  	if len(msgLen) > 0 && msgLen[0] > 0 {
   167  		bl.msgChanLen = msgLen[0]
   168  	}
   169  	bl.msgChan = make(chan *logMsg, bl.msgChanLen)
   170  	logMsgPool = &sync.Pool{
   171  		New: func() interface{} {
   172  			return &logMsg{}
   173  		},
   174  	}
   175  	bl.wg.Add(1)
   176  	go bl.startLogger()
   177  	return bl
   178  }
   179  
   180  // SetLogger provides a given logger adapter into BeeLogger with config string.
   181  // config need to be correct JSON as string: {"interval":360}.
   182  func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error {
   183  	config := append(configs, "{}")[0]
   184  	for _, l := range bl.outputs {
   185  		if l.name == adapterName {
   186  			return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName)
   187  		}
   188  	}
   189  
   190  	logAdapter, ok := adapters[adapterName]
   191  	if !ok {
   192  		return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
   193  	}
   194  
   195  	lg := logAdapter()
   196  	err := lg.Init(config)
   197  	if err != nil {
   198  		fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error())
   199  		return err
   200  	}
   201  	bl.outputs = append(bl.outputs, &nameLogger{name: adapterName, Logger: lg})
   202  	return nil
   203  }
   204  
   205  // SetLogger provides a given logger adapter into BeeLogger with config string.
   206  // config need to be correct JSON as string: {"interval":360}.
   207  func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error {
   208  	bl.lock.Lock()
   209  	defer bl.lock.Unlock()
   210  	if !bl.init {
   211  		bl.outputs = []*nameLogger{}
   212  		bl.init = true
   213  	}
   214  	return bl.setLogger(adapterName, configs...)
   215  }
   216  
   217  // DelLogger remove a logger adapter in BeeLogger.
   218  func (bl *BeeLogger) DelLogger(adapterName string) error {
   219  	bl.lock.Lock()
   220  	defer bl.lock.Unlock()
   221  	outputs := []*nameLogger{}
   222  	for _, lg := range bl.outputs {
   223  		if lg.name == adapterName {
   224  			lg.Destroy()
   225  		} else {
   226  			outputs = append(outputs, lg)
   227  		}
   228  	}
   229  	if len(outputs) == len(bl.outputs) {
   230  		return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
   231  	}
   232  	bl.outputs = outputs
   233  	return nil
   234  }
   235  
   236  func (bl *BeeLogger) writeToLoggers(when time.Time, msg string, level int) {
   237  	for _, l := range bl.outputs {
   238  		err := l.WriteMsg(when, msg, level)
   239  		if err != nil {
   240  			fmt.Fprintf(os.Stderr, "unable to WriteMsg to adapter:%v,error:%v\n", l.name, err)
   241  		}
   242  	}
   243  }
   244  
   245  func (bl *BeeLogger) Write(p []byte) (n int, err error) {
   246  	if len(p) == 0 {
   247  		return 0, nil
   248  	}
   249  	// writeMsg will always add a '\n' character
   250  	if p[len(p)-1] == '\n' {
   251  		p = p[0 : len(p)-1]
   252  	}
   253  	// set levelLoggerImpl to ensure all log message will be write out
   254  	err = bl.writeMsg(levelLoggerImpl, string(p))
   255  	if err == nil {
   256  		return len(p), err
   257  	}
   258  	return 0, err
   259  }
   260  
   261  func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error {
   262  	if !bl.init {
   263  		bl.lock.Lock()
   264  		bl.setLogger(AdapterConsole)
   265  		bl.lock.Unlock()
   266  	}
   267  
   268  	if len(v) > 0 {
   269  		msg = fmt.Sprintf(msg, v...)
   270  	}
   271  
   272  	msg = bl.prefix + " " + msg
   273  
   274  	when := time.Now()
   275  	if bl.enableFuncCallDepth {
   276  		_, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth)
   277  		if !ok {
   278  			file = "???"
   279  			line = 0
   280  		}
   281  		_, filename := path.Split(file)
   282  		msg = "[" + filename + ":" + strconv.Itoa(line) + "] " + msg
   283  	}
   284  
   285  	//set level info in front of filename info
   286  	if logLevel == levelLoggerImpl {
   287  		// set to emergency to ensure all log will be print out correctly
   288  		logLevel = LevelEmergency
   289  	} else {
   290  		msg = levelPrefix[logLevel] + " " + msg
   291  	}
   292  
   293  	if bl.asynchronous {
   294  		lm := logMsgPool.Get().(*logMsg)
   295  		lm.level = logLevel
   296  		lm.msg = msg
   297  		lm.when = when
   298  		if bl.outputs != nil {
   299  			bl.msgChan <- lm
   300  		} else {
   301  			logMsgPool.Put(lm)
   302  		}
   303  	} else {
   304  		bl.writeToLoggers(when, msg, logLevel)
   305  	}
   306  	return nil
   307  }
   308  
   309  // SetLevel Set log message level.
   310  // If message level (such as LevelDebug) is higher than logger level (such as LevelWarning),
   311  // log providers will not even be sent the message.
   312  func (bl *BeeLogger) SetLevel(l int) {
   313  	bl.level = l
   314  }
   315  
   316  // GetLevel Get Current log message level.
   317  func (bl *BeeLogger) GetLevel() int {
   318  	return bl.level
   319  }
   320  
   321  // SetLogFuncCallDepth set log funcCallDepth
   322  func (bl *BeeLogger) SetLogFuncCallDepth(d int) {
   323  	bl.loggerFuncCallDepth = d
   324  }
   325  
   326  // GetLogFuncCallDepth return log funcCallDepth for wrapper
   327  func (bl *BeeLogger) GetLogFuncCallDepth() int {
   328  	return bl.loggerFuncCallDepth
   329  }
   330  
   331  // EnableFuncCallDepth enable log funcCallDepth
   332  func (bl *BeeLogger) EnableFuncCallDepth(b bool) {
   333  	bl.enableFuncCallDepth = b
   334  }
   335  
   336  // set prefix
   337  func (bl *BeeLogger) SetPrefix(s string) {
   338  	bl.prefix = s
   339  }
   340  
   341  // start logger chan reading.
   342  // when chan is not empty, write logs.
   343  func (bl *BeeLogger) startLogger() {
   344  	gameOver := false
   345  	for {
   346  		select {
   347  		case bm := <-bl.msgChan:
   348  			bl.writeToLoggers(bm.when, bm.msg, bm.level)
   349  			logMsgPool.Put(bm)
   350  		case sg := <-bl.signalChan:
   351  			// Now should only send "flush" or "close" to bl.signalChan
   352  			bl.flush()
   353  			if sg == "close" {
   354  				for _, l := range bl.outputs {
   355  					l.Destroy()
   356  				}
   357  				bl.outputs = nil
   358  				gameOver = true
   359  			}
   360  			bl.wg.Done()
   361  		}
   362  		if gameOver {
   363  			break
   364  		}
   365  	}
   366  }
   367  
   368  // Emergency Log EMERGENCY level message.
   369  func (bl *BeeLogger) Emergency(format string, v ...interface{}) {
   370  	if LevelEmergency > bl.level {
   371  		return
   372  	}
   373  	bl.writeMsg(LevelEmergency, format, v...)
   374  }
   375  
   376  // Alert Log ALERT level message.
   377  func (bl *BeeLogger) Alert(format string, v ...interface{}) {
   378  	if LevelAlert > bl.level {
   379  		return
   380  	}
   381  	bl.writeMsg(LevelAlert, format, v...)
   382  }
   383  
   384  // Critical Log CRITICAL level message.
   385  func (bl *BeeLogger) Critical(format string, v ...interface{}) {
   386  	if LevelCritical > bl.level {
   387  		return
   388  	}
   389  	bl.writeMsg(LevelCritical, format, v...)
   390  }
   391  
   392  // Error Log ERROR level message.
   393  func (bl *BeeLogger) Error(format string, v ...interface{}) {
   394  	if LevelError > bl.level {
   395  		return
   396  	}
   397  	bl.writeMsg(LevelError, format, v...)
   398  }
   399  
   400  // Warning Log WARNING level message.
   401  func (bl *BeeLogger) Warning(format string, v ...interface{}) {
   402  	if LevelWarn > bl.level {
   403  		return
   404  	}
   405  	bl.writeMsg(LevelWarn, format, v...)
   406  }
   407  
   408  // Notice Log NOTICE level message.
   409  func (bl *BeeLogger) Notice(format string, v ...interface{}) {
   410  	if LevelNotice > bl.level {
   411  		return
   412  	}
   413  	bl.writeMsg(LevelNotice, format, v...)
   414  }
   415  
   416  // Informational Log INFORMATIONAL level message.
   417  func (bl *BeeLogger) Informational(format string, v ...interface{}) {
   418  	if LevelInfo > bl.level {
   419  		return
   420  	}
   421  	bl.writeMsg(LevelInfo, format, v...)
   422  }
   423  
   424  // Debug Log DEBUG level message.
   425  func (bl *BeeLogger) Debug(format string, v ...interface{}) {
   426  	if LevelDebug > bl.level {
   427  		return
   428  	}
   429  	bl.writeMsg(LevelDebug, format, v...)
   430  }
   431  
   432  // Warn Log WARN level message.
   433  // compatibility alias for Warning()
   434  func (bl *BeeLogger) Warn(format string, v ...interface{}) {
   435  	if LevelWarn > bl.level {
   436  		return
   437  	}
   438  	bl.writeMsg(LevelWarn, format, v...)
   439  }
   440  
   441  // Info Log INFO level message.
   442  // compatibility alias for Informational()
   443  func (bl *BeeLogger) Info(format string, v ...interface{}) {
   444  	if LevelInfo > bl.level {
   445  		return
   446  	}
   447  	bl.writeMsg(LevelInfo, format, v...)
   448  }
   449  
   450  // Trace Log TRACE level message.
   451  // compatibility alias for Debug()
   452  func (bl *BeeLogger) Trace(format string, v ...interface{}) {
   453  	if LevelDebug > bl.level {
   454  		return
   455  	}
   456  	bl.writeMsg(LevelDebug, format, v...)
   457  }
   458  
   459  // Flush flush all chan data.
   460  func (bl *BeeLogger) Flush() {
   461  	if bl.asynchronous {
   462  		bl.signalChan <- "flush"
   463  		bl.wg.Wait()
   464  		bl.wg.Add(1)
   465  		return
   466  	}
   467  	bl.flush()
   468  }
   469  
   470  // Close close logger, flush all chan data and destroy all adapters in BeeLogger.
   471  func (bl *BeeLogger) Close() {
   472  	if bl.asynchronous {
   473  		bl.signalChan <- "close"
   474  		bl.wg.Wait()
   475  		close(bl.msgChan)
   476  	} else {
   477  		bl.flush()
   478  		for _, l := range bl.outputs {
   479  			l.Destroy()
   480  		}
   481  		bl.outputs = nil
   482  	}
   483  	close(bl.signalChan)
   484  }
   485  
   486  // Reset close all outputs, and set bl.outputs to nil
   487  func (bl *BeeLogger) Reset() {
   488  	bl.Flush()
   489  	for _, l := range bl.outputs {
   490  		l.Destroy()
   491  	}
   492  	bl.outputs = nil
   493  }
   494  
   495  func (bl *BeeLogger) flush() {
   496  	if bl.asynchronous {
   497  		for {
   498  			if len(bl.msgChan) > 0 {
   499  				bm := <-bl.msgChan
   500  				bl.writeToLoggers(bm.when, bm.msg, bm.level)
   501  				logMsgPool.Put(bm)
   502  				continue
   503  			}
   504  			break
   505  		}
   506  	}
   507  	for _, l := range bl.outputs {
   508  		l.Flush()
   509  	}
   510  }
   511  
   512  // beeLogger references the used application logger.
   513  var beeLogger = NewLogger()
   514  
   515  // GetBeeLogger returns the default BeeLogger
   516  func GetBeeLogger() *BeeLogger {
   517  	return beeLogger
   518  }
   519  
   520  var beeLoggerMap = struct {
   521  	sync.RWMutex
   522  	logs map[string]*log.Logger
   523  }{
   524  	logs: map[string]*log.Logger{},
   525  }
   526  
   527  // GetLogger returns the default BeeLogger
   528  func GetLogger(prefixes ...string) *log.Logger {
   529  	prefix := append(prefixes, "")[0]
   530  	if prefix != "" {
   531  		prefix = fmt.Sprintf(`[%s] `, strings.ToUpper(prefix))
   532  	}
   533  	beeLoggerMap.RLock()
   534  	l, ok := beeLoggerMap.logs[prefix]
   535  	if ok {
   536  		beeLoggerMap.RUnlock()
   537  		return l
   538  	}
   539  	beeLoggerMap.RUnlock()
   540  	beeLoggerMap.Lock()
   541  	defer beeLoggerMap.Unlock()
   542  	l, ok = beeLoggerMap.logs[prefix]
   543  	if !ok {
   544  		l = log.New(beeLogger, prefix, 0)
   545  		beeLoggerMap.logs[prefix] = l
   546  	}
   547  	return l
   548  }
   549  
   550  // Reset will remove all the adapter
   551  func Reset() {
   552  	beeLogger.Reset()
   553  }
   554  
   555  // Async set the beelogger with Async mode and hold msglen messages
   556  func Async(msgLen ...int64) *BeeLogger {
   557  	return beeLogger.Async(msgLen...)
   558  }
   559  
   560  // SetLevel sets the global log level used by the simple logger.
   561  func SetLevel(l int) {
   562  	beeLogger.SetLevel(l)
   563  }
   564  
   565  // SetPrefix sets the prefix
   566  func SetPrefix(s string) {
   567  	beeLogger.SetPrefix(s)
   568  }
   569  
   570  // EnableFuncCallDepth enable log funcCallDepth
   571  func EnableFuncCallDepth(b bool) {
   572  	beeLogger.enableFuncCallDepth = b
   573  }
   574  
   575  // SetLogFuncCall set the CallDepth, default is 4
   576  func SetLogFuncCall(b bool) {
   577  	beeLogger.EnableFuncCallDepth(b)
   578  	beeLogger.SetLogFuncCallDepth(4)
   579  }
   580  
   581  // SetLogFuncCallDepth set log funcCallDepth
   582  func SetLogFuncCallDepth(d int) {
   583  	beeLogger.loggerFuncCallDepth = d
   584  }
   585  
   586  // SetLogger sets a new logger.
   587  func SetLogger(adapter string, config ...string) error {
   588  	return beeLogger.SetLogger(adapter, config...)
   589  }
   590  
   591  // Emergency logs a message at emergency level.
   592  func Emergency(f interface{}, v ...interface{}) {
   593  	beeLogger.Emergency(formatLog(f, v...))
   594  }
   595  
   596  // Alert logs a message at alert level.
   597  func Alert(f interface{}, v ...interface{}) {
   598  	beeLogger.Alert(formatLog(f, v...))
   599  }
   600  
   601  // Critical logs a message at critical level.
   602  func Critical(f interface{}, v ...interface{}) {
   603  	beeLogger.Critical(formatLog(f, v...))
   604  }
   605  
   606  // Error logs a message at error level.
   607  func Error(f interface{}, v ...interface{}) {
   608  	beeLogger.Error(formatLog(f, v...))
   609  }
   610  
   611  // Warning logs a message at warning level.
   612  func Warning(f interface{}, v ...interface{}) {
   613  	beeLogger.Warn(formatLog(f, v...))
   614  }
   615  
   616  // Warn compatibility alias for Warning()
   617  func Warn(f interface{}, v ...interface{}) {
   618  	beeLogger.Warn(formatLog(f, v...))
   619  }
   620  
   621  // Notice logs a message at notice level.
   622  func Notice(f interface{}, v ...interface{}) {
   623  	beeLogger.Notice(formatLog(f, v...))
   624  }
   625  
   626  // Informational logs a message at info level.
   627  func Informational(f interface{}, v ...interface{}) {
   628  	beeLogger.Info(formatLog(f, v...))
   629  }
   630  
   631  // Info compatibility alias for Warning()
   632  func Info(f interface{}, v ...interface{}) {
   633  	beeLogger.Info(formatLog(f, v...))
   634  }
   635  
   636  // Debug logs a message at debug level.
   637  func Debug(f interface{}, v ...interface{}) {
   638  	beeLogger.Debug(formatLog(f, v...))
   639  }
   640  
   641  // Trace logs a message at trace level.
   642  // compatibility alias for Warning()
   643  func Trace(f interface{}, v ...interface{}) {
   644  	beeLogger.Trace(formatLog(f, v...))
   645  }
   646  
   647  func formatLog(f interface{}, v ...interface{}) string {
   648  	var msg string
   649  	switch f.(type) {
   650  	case string:
   651  		msg = f.(string)
   652  		if len(v) == 0 {
   653  			return msg
   654  		}
   655  		if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") {
   656  			//format string
   657  		} else {
   658  			//do not contain format char
   659  			msg += strings.Repeat(" %v", len(v))
   660  		}
   661  	default:
   662  		msg = fmt.Sprint(f)
   663  		if len(v) == 0 {
   664  			return msg
   665  		}
   666  		msg += strings.Repeat(" %v", len(v))
   667  	}
   668  	return fmt.Sprintf(msg, v...)
   669  }