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