github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/framework/logs/log.go (about)

     1  // the package is exported from github.com/beego/beego/v2/core/logs
     2  
     3  // Copyright 2023. All Rights Reserved.
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //      http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  // Package logs provide a general log interface
    18  // Usage:
    19  //
    20  // import "github.com/mdaxf/iac/framework/logs"
    21  //
    22  //	log := NewLogger(10000)
    23  //	log.SetLogger("console", "")
    24  //
    25  //	> the first params stand for how many channel
    26  //
    27  // Use it like this:
    28  //
    29  //	log.Trace("trace")
    30  //	log.Info("info")
    31  //	log.Warn("warning")
    32  //	log.Debug("debug")
    33  //	log.Critical("critical")
    34  package logs
    35  
    36  import (
    37  	"fmt"
    38  	"log"
    39  	"os"
    40  	"runtime"
    41  	"strings"
    42  	"sync"
    43  	"time"
    44  )
    45  
    46  // RFC5424 log message levels.
    47  const (
    48  	LevelEmergency = iota
    49  	LevelAlert
    50  	LevelCritical
    51  	LevelError
    52  	LevelWarning
    53  	LevelNotice
    54  	LevelInformational
    55  	LevelDebug
    56  	LeverPerformance
    57  )
    58  
    59  // levelLogLogger is defined to implement log.Logger
    60  // the real log level will be LevelEmergency
    61  const levelLoggerImpl = -1
    62  
    63  // Name for adapter with iac official support
    64  const (
    65  	AdapterConsole    = "console"
    66  	AdapterFile       = "file"
    67  	AdapterMultiFile  = "multifile"
    68  	AdapterMail       = "smtp"
    69  	AdapterConn       = "conn"
    70  	AdapterEs         = "es"
    71  	AdapterSlack      = "slack"
    72  	AdapterAliLS      = "alils"
    73  	AdapterDocumentDB = "documentdb"
    74  )
    75  
    76  // Legacy log level constants to ensure backwards compatibility.
    77  const (
    78  	LevelInfo  = LevelInformational
    79  	LevelTrace = LevelDebug
    80  	LevelWarn  = LevelWarning
    81  )
    82  
    83  type newLoggerFunc func() Logger
    84  
    85  // Logger defines the behavior of a log provider.
    86  type Logger interface {
    87  	Init(config string) error
    88  	WriteMsg(lm *LogMsg) error
    89  	Destroy()
    90  	Flush()
    91  	SetFormatter(f LogFormatter)
    92  }
    93  
    94  var (
    95  	adapters    = make(map[string]newLoggerFunc)
    96  	levelPrefix = [LeverPerformance + 1]string{"[M]", "[A]", "[C]", "[E]", "[W]", "[N]", "[I]", "[D]", "[P]"}
    97  )
    98  
    99  // Register makes a log provide available by the provided name.
   100  // If Register is called twice with the same name or if driver is nil,
   101  // it panics.
   102  func Register(name string, log newLoggerFunc) {
   103  	if log == nil {
   104  		panic("logs: Register provide is nil")
   105  	}
   106  	if _, dup := adapters[name]; dup {
   107  		panic("logs: Register called twice for provider " + name)
   108  	}
   109  	adapters[name] = log
   110  }
   111  
   112  // IACLogger is default logger in iac application.
   113  // Can contain several providers and log message into all providers.
   114  type IACLogger struct {
   115  	lock                sync.Mutex
   116  	init                bool
   117  	enableFuncCallDepth bool
   118  	enableFullFilePath  bool
   119  	asynchronous        bool
   120  	// Whether to discard logs when buffer is full and asynchronous is true
   121  	// No discard by default
   122  	logWithNonBlocking  bool
   123  	wg                  sync.WaitGroup
   124  	level               int
   125  	loggerFuncCallDepth int
   126  	prefix              string
   127  	msgChanLen          int64
   128  	msgChan             chan *LogMsg
   129  	closeChan           chan struct{}
   130  	flushChan           chan struct{}
   131  	outputs             []*nameLogger
   132  	globalFormatter     string
   133  	Perf                bool
   134  	Threhold            int
   135  }
   136  
   137  const defaultAsyncMsgLen = 1e3
   138  
   139  type nameLogger struct {
   140  	Logger
   141  	name string
   142  }
   143  
   144  const moduleName = "logger"
   145  
   146  var logMsgPool *sync.Pool
   147  
   148  // NewLogger returns a new IACLogger.
   149  // channelLen: the number of messages in chan(used where asynchronous is true).
   150  // if the buffering chan is full, logger adapters write to file or other way.
   151  // func NewLogger(channelLens ...int64) *IACLogger {
   152  func NewLogger(channelLens ...int64) *IACLogger {
   153  	bl := new(IACLogger)
   154  	bl.level = LevelDebug
   155  	bl.loggerFuncCallDepth = 3
   156  	bl.msgChanLen = append(channelLens, 0)[0]
   157  	if bl.msgChanLen <= 0 {
   158  		bl.msgChanLen = defaultAsyncMsgLen
   159  	}
   160  	bl.Perf = true
   161  	bl.flushChan = make(chan struct{}, 1)
   162  	bl.closeChan = make(chan struct{}, 1)
   163  	bl.Threhold = 10
   164  	//	bl.setLogger(AdapterConsole)
   165  	return bl
   166  }
   167  
   168  func New() *IACLogger {
   169  	bl := &IACLogger{}
   170  	bl.level = LevelDebug
   171  	bl.loggerFuncCallDepth = 3
   172  	bl.msgChanLen = 0
   173  	if bl.msgChanLen <= 0 {
   174  		bl.msgChanLen = defaultAsyncMsgLen
   175  	}
   176  	bl.Perf = true
   177  	bl.flushChan = make(chan struct{}, 1)
   178  	bl.closeChan = make(chan struct{}, 1)
   179  	bl.Threhold = 10
   180  	bl.setLogger(AdapterConsole)
   181  	return bl
   182  }
   183  
   184  // Async sets the log to asynchronous and start the goroutine
   185  func (bl *IACLogger) Async(msgLen ...int64) *IACLogger {
   186  	bl.lock.Lock()
   187  	defer bl.lock.Unlock()
   188  	if bl.asynchronous {
   189  		return bl
   190  	}
   191  	bl.asynchronous = true
   192  	if len(msgLen) > 0 && msgLen[0] > 0 {
   193  		bl.msgChanLen = msgLen[0]
   194  	}
   195  	bl.msgChan = make(chan *LogMsg, bl.msgChanLen)
   196  	logMsgPool = &sync.Pool{
   197  		New: func() interface{} {
   198  			return &LogMsg{}
   199  		},
   200  	}
   201  	bl.wg.Add(1)
   202  	go bl.startLogger()
   203  	return bl
   204  }
   205  
   206  // AsyncNonBlockWrite Non-blocking write in asynchronous mode
   207  // Only works if asynchronous write logging is set
   208  func (bl *IACLogger) AsyncNonBlockWrite() *IACLogger {
   209  	if !bl.asynchronous {
   210  		return bl
   211  	}
   212  	bl.logWithNonBlocking = true
   213  	return bl
   214  }
   215  
   216  // SetLogger provides a given logger adapter into IACLogger with config string.
   217  // config must in in JSON format like {"interval":360}}
   218  func (bl *IACLogger) setLogger(adapterName string, configs ...string) error {
   219  	config := append(configs, "{}")[0]
   220  	//	fmt.Println("log config:", config)
   221  	for _, l := range bl.outputs {
   222  		if l.name == adapterName {
   223  			return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName)
   224  		}
   225  	}
   226  	//	fmt.Println("adapterName:", adapterName)
   227  	logAdapter, ok := adapters[adapterName]
   228  	//	fmt.Println("logAdapter:", logAdapter)
   229  	if !ok {
   230  		return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
   231  	}
   232  
   233  	lg := logAdapter()
   234  	//	fmt.Println("lg:", lg)
   235  	err := lg.Init(config)
   236  	//	fmt.Println("err:", err)
   237  	if err != nil {
   238  		return err
   239  	}
   240  
   241  	// Global formatter overrides the default set formatter
   242  	if len(bl.globalFormatter) > 0 {
   243  		fmtr, ok := GetFormatter(bl.globalFormatter)
   244  		if !ok {
   245  			return fmt.Errorf("the formatter with name: %s not found", bl.globalFormatter)
   246  		}
   247  		lg.SetFormatter(fmtr)
   248  	}
   249  
   250  	bl.outputs = append(bl.outputs, &nameLogger{name: adapterName, Logger: lg})
   251  	return nil
   252  }
   253  
   254  // SetLogger provides a given logger adapter into IACLogger with config string.
   255  // config must in in JSON format like {"interval":360}}
   256  func (bl *IACLogger) SetLogger(adapterName string, configs ...string) error {
   257  	bl.lock.Lock()
   258  	defer bl.lock.Unlock()
   259  	if !bl.init {
   260  		bl.Perf = true
   261  		bl.Threhold = 10
   262  		bl.outputs = []*nameLogger{}
   263  		bl.init = true
   264  	}
   265  	return bl.setLogger(adapterName, configs...)
   266  }
   267  
   268  // DelLogger removes a logger adapter in IACLogger.
   269  func (bl *IACLogger) DelLogger(adapterName string) error {
   270  	bl.lock.Lock()
   271  	defer bl.lock.Unlock()
   272  	outputs := make([]*nameLogger, 0, len(bl.outputs))
   273  	for _, lg := range bl.outputs {
   274  		if lg.name == adapterName {
   275  			lg.Destroy()
   276  		} else {
   277  			outputs = append(outputs, lg)
   278  		}
   279  	}
   280  	if len(outputs) == len(bl.outputs) {
   281  		return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
   282  	}
   283  	bl.outputs = outputs
   284  	return nil
   285  }
   286  
   287  func (bl *IACLogger) writeToLoggers(lm *LogMsg) {
   288  	for _, l := range bl.outputs {
   289  		err := l.WriteMsg(lm)
   290  		if err != nil {
   291  			fmt.Fprintf(os.Stderr, "unable to WriteMsg to adapter:%v,error:%v\n", l.name, err)
   292  		}
   293  	}
   294  }
   295  
   296  func (bl *IACLogger) Write(p []byte) (n int, err error) {
   297  	if len(p) == 0 {
   298  		return 0, nil
   299  	}
   300  	// writeMsg will always add a '\n' character
   301  	if p[len(p)-1] == '\n' {
   302  		p = p[0 : len(p)-1]
   303  	}
   304  	lm := &LogMsg{
   305  		Msg:   string(p),
   306  		Level: levelLoggerImpl,
   307  		When:  time.Now(),
   308  	}
   309  
   310  	// set levelLoggerImpl to ensure all log message will be write out
   311  	err = bl.writeMsg(lm)
   312  	if err == nil {
   313  		return len(p), nil
   314  	}
   315  	return 0, err
   316  }
   317  
   318  func (bl *IACLogger) writeMsg(lm *LogMsg) error {
   319  	if !bl.init {
   320  		bl.lock.Lock()
   321  		bl.setLogger(AdapterConsole)
   322  		bl.lock.Unlock()
   323  		bl.Perf = true
   324  		bl.Threhold = 10
   325  	}
   326  
   327  	var (
   328  		file string
   329  		line int
   330  		ok   bool
   331  	)
   332  
   333  	_, file, line, ok = runtime.Caller(bl.loggerFuncCallDepth)
   334  	if !ok {
   335  		file = "???"
   336  		line = 0
   337  	}
   338  	lm.FilePath = file
   339  	lm.LineNumber = line
   340  	lm.Prefix = bl.prefix
   341  
   342  	lm.enableFullFilePath = bl.enableFullFilePath
   343  	lm.enableFuncCallDepth = bl.enableFuncCallDepth
   344  
   345  	// set level info in front of filename info
   346  	if lm.Level == levelLoggerImpl {
   347  		// set to emergency to ensure all log will be print out correctly
   348  		lm.Level = LevelEmergency
   349  	}
   350  
   351  	if bl.asynchronous {
   352  		logM := logMsgPool.Get().(*LogMsg)
   353  		logM.Level = lm.Level
   354  		logM.Msg = lm.Msg
   355  		logM.When = lm.When
   356  		logM.Args = lm.Args
   357  		logM.FilePath = lm.FilePath
   358  		logM.LineNumber = lm.LineNumber
   359  		logM.Prefix = lm.Prefix
   360  
   361  		if bl.outputs != nil {
   362  			if bl.logWithNonBlocking {
   363  				select {
   364  				case bl.msgChan <- lm:
   365  				// discard log when channel is full
   366  				default:
   367  				}
   368  			} else {
   369  				bl.msgChan <- lm
   370  			}
   371  		} else {
   372  			logMsgPool.Put(lm)
   373  		}
   374  	} else {
   375  		bl.writeToLoggers(lm)
   376  	}
   377  	return nil
   378  }
   379  
   380  // SetLevel sets log message level.
   381  // If message level (such as LevelDebug) is higher than logger level (such as LevelWarning),
   382  // log providers will not be sent the message.
   383  func (bl *IACLogger) SetLevel(l int) {
   384  	bl.level = l
   385  }
   386  
   387  // GetLevel Get Current log message level.
   388  func (bl *IACLogger) GetLevel() int {
   389  	return bl.level
   390  }
   391  
   392  // SetLogFuncCallDepth set log funcCallDepth
   393  func (bl *IACLogger) SetLogFuncCallDepth(d int) {
   394  	bl.loggerFuncCallDepth = d
   395  }
   396  
   397  // GetLogFuncCallDepth return log funcCallDepth for wrapper
   398  func (bl *IACLogger) GetLogFuncCallDepth() int {
   399  	return bl.loggerFuncCallDepth
   400  }
   401  
   402  // EnableFuncCallDepth enable log funcCallDepth
   403  func (bl *IACLogger) EnableFuncCallDepth(b bool) {
   404  	bl.enableFuncCallDepth = b
   405  }
   406  
   407  // set prefix
   408  func (bl *IACLogger) SetPrefix(s string) {
   409  	bl.prefix = s
   410  }
   411  
   412  // start logger chan reading.
   413  // when chan is not empty, write logs.
   414  func (bl *IACLogger) startLogger() {
   415  	gameOver := false
   416  	for {
   417  		select {
   418  		case bm, ok := <-bl.msgChan:
   419  			// this is a terrible design to have a signal channel that accept two inputs
   420  			// so we only handle the msg if the channel is not closed
   421  			if ok {
   422  				bl.writeToLoggers(bm)
   423  				logMsgPool.Put(bm)
   424  			}
   425  		case <-bl.closeChan:
   426  			bl.flush()
   427  			for _, l := range bl.outputs {
   428  				l.Destroy()
   429  			}
   430  			bl.outputs = nil
   431  			gameOver = true
   432  			bl.wg.Done()
   433  		case <-bl.flushChan:
   434  			bl.flush()
   435  			bl.wg.Done()
   436  		}
   437  		if gameOver {
   438  			break
   439  		}
   440  	}
   441  }
   442  
   443  func (bl *IACLogger) setGlobalFormatter(fmtter string) error {
   444  	bl.globalFormatter = fmtter
   445  	return nil
   446  }
   447  
   448  // SetGlobalFormatter sets the global formatter for all log adapters
   449  // don't forget to register the formatter by invoking RegisterFormatter
   450  func SetGlobalFormatter(fmtter string) error {
   451  	return iacLogger.setGlobalFormatter(fmtter)
   452  }
   453  
   454  // Emergency Log EMERGENCY level message.
   455  func (bl *IACLogger) Emergency(format string, v ...interface{}) {
   456  	if LevelEmergency > bl.level {
   457  		return
   458  	}
   459  
   460  	lm := &LogMsg{
   461  		Level: LevelEmergency,
   462  		Msg:   format,
   463  		When:  time.Now(),
   464  	}
   465  	if len(v) > 0 {
   466  		lm.Msg = fmt.Sprintf(lm.Msg, v...)
   467  	}
   468  
   469  	bl.writeMsg(lm)
   470  }
   471  
   472  // Alert Log ALERT level message.
   473  func (bl *IACLogger) Alert(format string, v ...interface{}) {
   474  	if LevelAlert > bl.level {
   475  		return
   476  	}
   477  
   478  	lm := &LogMsg{
   479  		Level: LevelAlert,
   480  		Msg:   format,
   481  		When:  time.Now(),
   482  		Args:  v,
   483  	}
   484  	bl.writeMsg(lm)
   485  }
   486  
   487  // Critical Log CRITICAL level message.
   488  func (bl *IACLogger) Critical(format string, v ...interface{}) {
   489  	if LevelCritical > bl.level {
   490  		return
   491  	}
   492  	lm := &LogMsg{
   493  		Level: LevelCritical,
   494  		Msg:   format,
   495  		When:  time.Now(),
   496  		Args:  v,
   497  	}
   498  
   499  	bl.writeMsg(lm)
   500  }
   501  
   502  // Error Log ERROR level message.
   503  func (bl *IACLogger) Error(format string, v ...interface{}) {
   504  	if LevelError > bl.level {
   505  		return
   506  	}
   507  	lm := &LogMsg{
   508  		Level: LevelError,
   509  		Msg:   format,
   510  		When:  time.Now(),
   511  		Args:  v,
   512  	}
   513  
   514  	bl.writeMsg(lm)
   515  }
   516  
   517  // Warning Log WARNING level message.
   518  func (bl *IACLogger) Warning(format string, v ...interface{}) {
   519  	if LevelWarn > bl.level {
   520  		return
   521  	}
   522  	lm := &LogMsg{
   523  		Level: LevelWarn,
   524  		Msg:   format,
   525  		When:  time.Now(),
   526  		Args:  v,
   527  	}
   528  
   529  	bl.writeMsg(lm)
   530  }
   531  
   532  // Notice Log NOTICE level message.
   533  func (bl *IACLogger) Notice(format string, v ...interface{}) {
   534  	if LevelNotice > bl.level {
   535  		return
   536  	}
   537  	lm := &LogMsg{
   538  		Level: LevelNotice,
   539  		Msg:   format,
   540  		When:  time.Now(),
   541  		Args:  v,
   542  	}
   543  
   544  	bl.writeMsg(lm)
   545  }
   546  
   547  // Informational Log INFORMATIONAL level message.
   548  func (bl *IACLogger) Informational(format string, v ...interface{}) {
   549  	if LevelInfo > bl.level {
   550  		return
   551  	}
   552  	lm := &LogMsg{
   553  		Level: LevelInfo,
   554  		Msg:   format,
   555  		When:  time.Now(),
   556  		Args:  v,
   557  	}
   558  
   559  	bl.writeMsg(lm)
   560  }
   561  
   562  // Debug Log DEBUG level message.
   563  func (bl *IACLogger) Debug(format string, v ...interface{}) {
   564  	if LevelDebug > bl.level {
   565  		return
   566  	}
   567  	lm := &LogMsg{
   568  		Level: LevelDebug,
   569  		Msg:   format,
   570  		When:  time.Now(),
   571  		Args:  v,
   572  	}
   573  
   574  	bl.writeMsg(lm)
   575  }
   576  
   577  // Warn Log WARN level message.
   578  // compatibility alias for Warning()
   579  func (bl *IACLogger) Warn(format string, v ...interface{}) {
   580  	if LevelWarn > bl.level {
   581  		return
   582  	}
   583  	lm := &LogMsg{
   584  		Level: LevelWarn,
   585  		Msg:   format,
   586  		When:  time.Now(),
   587  		Args:  v,
   588  	}
   589  
   590  	bl.writeMsg(lm)
   591  }
   592  
   593  // Info Log INFO level message.
   594  // compatibility alias for Informational()
   595  func (bl *IACLogger) Info(format string, v ...interface{}) {
   596  	if LevelInfo > bl.level {
   597  		return
   598  	}
   599  	lm := &LogMsg{
   600  		Level: LevelInfo,
   601  		Msg:   format,
   602  		When:  time.Now(),
   603  		Args:  v,
   604  	}
   605  
   606  	bl.writeMsg(lm)
   607  }
   608  
   609  // Performance level message./
   610  func (bl *IACLogger) Performance(elapsed time.Duration, format string, v ...interface{}) {
   611  
   612  	//	fmt.Println(bl, bl.Perf, bl.Threhold, elapsed.Milliseconds(), format, v)
   613  
   614  	if bl == nil {
   615  		return
   616  	}
   617  	if bl.Perf {
   618  
   619  		if elsapsedTime := elapsed.Milliseconds(); elsapsedTime > int64(bl.Threhold) {
   620  
   621  			lm := &LogMsg{
   622  				Level: LeverPerformance,
   623  				Msg:   format,
   624  				When:  time.Now(),
   625  				Args:  v,
   626  			}
   627  
   628  			bl.writeMsg(lm)
   629  
   630  			//	lm.Level = LevelDebug
   631  			//	bl.writeMsg(lm)
   632  		}
   633  	}
   634  }
   635  
   636  // Trace Log TRACE level message.
   637  // compatibility alias for Debug()
   638  func (bl *IACLogger) Trace(format string, v ...interface{}) {
   639  	if LevelDebug > bl.level {
   640  		return
   641  	}
   642  	lm := &LogMsg{
   643  		Level: LevelDebug,
   644  		Msg:   format,
   645  		When:  time.Now(),
   646  		Args:  v,
   647  	}
   648  
   649  	bl.writeMsg(lm)
   650  }
   651  
   652  // Flush flush all chan data.
   653  func (bl *IACLogger) Flush() {
   654  	if bl.asynchronous {
   655  		bl.flushChan <- struct{}{}
   656  		bl.wg.Wait()
   657  		bl.wg.Add(1)
   658  		return
   659  	}
   660  	bl.flush()
   661  }
   662  
   663  // Close close logger, flush all chan data and destroy all adapters in IACLogger.
   664  func (bl *IACLogger) Close() {
   665  	if bl.asynchronous {
   666  		bl.closeChan <- struct{}{}
   667  		bl.wg.Wait()
   668  		close(bl.msgChan)
   669  	} else {
   670  		bl.flush()
   671  		for _, l := range bl.outputs {
   672  			l.Destroy()
   673  		}
   674  		bl.outputs = nil
   675  	}
   676  	close(bl.flushChan)
   677  	close(bl.closeChan)
   678  }
   679  
   680  // Reset close all outputs, and set bl.outputs to nil
   681  func (bl *IACLogger) Reset() {
   682  	bl.Flush()
   683  	for _, l := range bl.outputs {
   684  		l.Destroy()
   685  	}
   686  	bl.outputs = nil
   687  }
   688  
   689  func (bl *IACLogger) flush() {
   690  	if bl.asynchronous {
   691  		for {
   692  			if len(bl.msgChan) > 0 {
   693  				bm, ok := <-bl.msgChan
   694  				if !ok {
   695  					continue
   696  				}
   697  				bl.writeToLoggers(bm)
   698  				logMsgPool.Put(bm)
   699  				continue
   700  			}
   701  			break
   702  		}
   703  	}
   704  	for _, l := range bl.outputs {
   705  		l.Flush()
   706  	}
   707  }
   708  
   709  // iacLogger references the used application logger.
   710  var iacLogger = NewLogger()
   711  
   712  // GetIACLogger returns the default IACLogger
   713  func GetIACLogger() *IACLogger {
   714  	return iacLogger
   715  }
   716  
   717  var iacLoggerMap = struct {
   718  	sync.RWMutex
   719  	logs map[string]*log.Logger
   720  }{
   721  	logs: map[string]*log.Logger{},
   722  }
   723  
   724  // GetLogger returns the default IACLogger
   725  func GetLogger(prefixes ...string) *log.Logger {
   726  	prefix := append(prefixes, "")[0]
   727  	if prefix != "" {
   728  		prefix = fmt.Sprintf(`[%s] `, strings.ToUpper(prefix))
   729  	}
   730  	iacLoggerMap.RLock()
   731  	l, ok := iacLoggerMap.logs[prefix]
   732  	if ok {
   733  		iacLoggerMap.RUnlock()
   734  		return l
   735  	}
   736  	iacLoggerMap.RUnlock()
   737  	iacLoggerMap.Lock()
   738  	defer iacLoggerMap.Unlock()
   739  	l, ok = iacLoggerMap.logs[prefix]
   740  	if !ok {
   741  		l = log.New(iacLogger, prefix, 0)
   742  		iacLoggerMap.logs[prefix] = l
   743  	}
   744  	return l
   745  }
   746  
   747  // EnableFullFilePath enables full file path logging. Disabled by default
   748  // e.g "/home/Documents/GitHub/iac/mainapp/" instead of "mainapp"
   749  func EnableFullFilePath(b bool) {
   750  	iacLogger.enableFullFilePath = b
   751  }
   752  
   753  // Reset will remove all the adapter
   754  func Reset() {
   755  	iacLogger.Reset()
   756  }
   757  
   758  // Async set the beelogger with Async mode and hold msglen messages
   759  func Async(msgLen ...int64) *IACLogger {
   760  	return iacLogger.Async(msgLen...)
   761  }
   762  
   763  // SetLevel sets the global log level used by the simple logger.
   764  func SetLevel(l int) {
   765  	iacLogger.SetLevel(l)
   766  }
   767  
   768  // SetPrefix sets the prefix
   769  func SetPrefix(s string) {
   770  	iacLogger.SetPrefix(s)
   771  }
   772  
   773  // EnableFuncCallDepth enable log funcCallDepth
   774  func EnableFuncCallDepth(b bool) {
   775  	iacLogger.enableFuncCallDepth = b
   776  }
   777  
   778  // SetLogFuncCall set the CallDepth, default is 4
   779  func SetLogFuncCall(b bool) {
   780  	iacLogger.EnableFuncCallDepth(b)
   781  	iacLogger.SetLogFuncCallDepth(3)
   782  }
   783  
   784  // SetLogFuncCallDepth set log funcCallDepth
   785  func SetLogFuncCallDepth(d int) {
   786  	iacLogger.loggerFuncCallDepth = d
   787  }
   788  
   789  // SetLogger sets a new logger.
   790  func SetLogger(adapter string, config ...string) error {
   791  	return iacLogger.SetLogger(adapter, config...)
   792  }
   793  
   794  // Emergency logs a message at emergency level.
   795  func Emergency(f interface{}, v ...interface{}) {
   796  	iacLogger.Emergency(formatPattern(f, v...), v...)
   797  }
   798  
   799  // Alert logs a message at alert level.
   800  func Alert(f interface{}, v ...interface{}) {
   801  	iacLogger.Alert(formatPattern(f, v...), v...)
   802  }
   803  
   804  // Critical logs a message at critical level.
   805  func Critical(f interface{}, v ...interface{}) {
   806  	iacLogger.Critical(formatPattern(f, v...), v...)
   807  }
   808  
   809  // Error logs a message at error level.
   810  func Error(f interface{}, v ...interface{}) {
   811  	iacLogger.Error(formatPattern(f, v...), v...)
   812  }
   813  
   814  // Warning logs a message at warning level.
   815  func Warning(f interface{}, v ...interface{}) {
   816  	iacLogger.Warn(formatPattern(f, v...), v...)
   817  }
   818  
   819  // Warn compatibility alias for Warning()
   820  func Warn(f interface{}, v ...interface{}) {
   821  	iacLogger.Warn(formatPattern(f, v...), v...)
   822  }
   823  
   824  // Notice logs a message at notice level.
   825  func Notice(f interface{}, v ...interface{}) {
   826  	iacLogger.Notice(formatPattern(f, v...), v...)
   827  }
   828  
   829  // Informational logs a message at info level.
   830  func Informational(f interface{}, v ...interface{}) {
   831  	iacLogger.Info(formatPattern(f, v...), v...)
   832  }
   833  
   834  // Info compatibility alias for Warning()
   835  func Info(f interface{}, v ...interface{}) {
   836  	iacLogger.Info(formatPattern(f, v...), v...)
   837  }
   838  
   839  // Debug logs a message at debug level.
   840  func Debug(f interface{}, v ...interface{}) {
   841  	iacLogger.Debug(formatPattern(f, v...), v...)
   842  }
   843  
   844  // Trace logs a message at trace level.
   845  // compatibility alias for Warning()
   846  func Trace(f interface{}, v ...interface{}) {
   847  	iacLogger.Trace(formatPattern(f, v...), v...)
   848  }
   849  
   850  func formatPattern(f interface{}, v ...interface{}) string {
   851  	var msg string
   852  	switch f.(type) {
   853  	case string:
   854  		msg = f.(string)
   855  		if len(v) == 0 {
   856  			return msg
   857  		}
   858  		if !strings.Contains(msg, "%") {
   859  			// do not contain format char
   860  			msg += strings.Repeat(" %v", len(v))
   861  		}
   862  	default:
   863  		msg = fmt.Sprint(f)
   864  		if len(v) == 0 {
   865  			return msg
   866  		}
   867  		msg += strings.Repeat(" %v", len(v))
   868  	}
   869  	return msg
   870  }