qoobing.com/gomod/log@v1.2.8/log.go (about)

     1  // Distributed under the MIT software license, see the accompanying
     2  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
     3  package log
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"log"
     9  	"os"
    10  	"runtime/debug"
    11  	"strings"
    12  	"sync"
    13  	"time"
    14  
    15  	"qoobing.com/gomod/str"
    16  )
    17  
    18  const (
    19  	PANIC       LogLevel = 0
    20  	FATAL       LogLevel = 1
    21  	ERROR       LogLevel = 2
    22  	NOTICE      LogLevel = 3
    23  	WARNING     LogLevel = 4
    24  	INFO        LogLevel = 5
    25  	DEBUG       LogLevel = 9
    26  	ErrLogLevel          = "~~~~~invalid loglevel~~~~~"
    27  	ErrLogPanic          = "~~~~panic~~~~~~"
    28  )
    29  
    30  var (
    31  	mapStrToLevel = map[string]LogLevel{
    32  		"PANIC":   PANIC,
    33  		"FATAL":   FATAL,
    34  		"ERROR":   ERROR,
    35  		"NOTICE":  NOTICE,
    36  		"WARNING": WARNING,
    37  		"INFO":    INFO,
    38  		"DEBUG":   DEBUG,
    39  	}
    40  	mapLevelToStr = map[LogLevel]string{
    41  		PANIC:   "PANIC",
    42  		FATAL:   "FATAL",
    43  		ERROR:   "ERROR",
    44  		NOTICE:  "NOTICE",
    45  		WARNING: "WARNING",
    46  		INFO:    "INFO",
    47  		DEBUG:   "DEBUG",
    48  	}
    49  )
    50  
    51  var (
    52  	golog        *log.Logger        = nil
    53  	mylog        *Logger            = nil
    54  	logidCreator LogidCreator       = nil
    55  	modulelogs   map[string]*Logger = map[string]*Logger{}
    56  )
    57  
    58  type LogLevel int
    59  type Logger struct {
    60  	module   string
    61  	golog    *log.Logger
    62  	loglevel LogLevel
    63  }
    64  
    65  type LogidCreator interface {
    66  	Cleanup()
    67  	GetLogid() string
    68  	SetLogid(logid string)
    69  }
    70  
    71  func New(module string) *Logger {
    72  	if module == "" {
    73  		module = "undefine"
    74  	}
    75  	if _, ok := modulelogs[module]; ok {
    76  		return modulelogs[module]
    77  	} else {
    78  		modulelogs[module] = &Logger{
    79  			module:   module,
    80  			golog:    golog,
    81  			loglevel: DEBUG,
    82  		}
    83  		return modulelogs[module]
    84  	}
    85  }
    86  
    87  // SetLogLevel set new log level
    88  func (log *Logger) SetLogLevel(newlv LogLevel) (oldlv LogLevel) {
    89  	oldlv = log.loglevel
    90  	log.loglevel = newlv
    91  	return oldlv
    92  }
    93  
    94  // SetLogLevelByName set new log level by level name
    95  func (log *Logger) SetLogLevelByName(newlv string) (oldlv string) {
    96  	if newlevel, ok := mapStrToLevel[newlv]; ok {
    97  		oldlevel := log.loglevel
    98  		log.loglevel = newlevel
    99  		return mapLevelToStr[oldlevel]
   100  	}
   101  	return ErrLogLevel
   102  }
   103  
   104  func (log *Logger) Print(prefix string, v interface{}) {
   105  	var str = ""
   106  	if pkg, err := json.Marshal(v); err != nil {
   107  		str = err.Error()
   108  	} else {
   109  		str = string(pkg)
   110  	}
   111  	log.logwrite(DEBUG, 3, prefix+"%s\n", str)
   112  }
   113  
   114  func (log *Logger) PrintPretty(prefix string, v interface{}) {
   115  	var preety = ""
   116  	if pkg, err := json.MarshalIndent(v, "==", "  "); err != nil {
   117  		preety = err.Error()
   118  	} else {
   119  		preety = string(pkg)
   120  	}
   121  	log.logwrite(DEBUG, 3, prefix+"%s\n", preety)
   122  }
   123  
   124  func (log *Logger) Debugf(format string, v ...interface{}) {
   125  	log.logwrite(DEBUG, 3, format, v...)
   126  }
   127  
   128  func (log *Logger) DebugfWithDepth(calldepth int, format string, v ...interface{}) {
   129  	calldepth += 3
   130  	log.logwrite(DEBUG, calldepth, format, v...)
   131  }
   132  
   133  func (log *Logger) Noticef(format string, v ...interface{}) {
   134  	log.logwrite(NOTICE, 3, format, v...)
   135  }
   136  
   137  func (log *Logger) NoticefWithDepth(calldepth int, format string, v ...interface{}) {
   138  	calldepth += 3
   139  	log.logwrite(NOTICE, calldepth, format, v...)
   140  }
   141  
   142  func (log *Logger) Warningf(format string, v ...interface{}) {
   143  	log.logwrite(WARNING, 3, format, v...)
   144  }
   145  
   146  func (log *Logger) Infof(format string, v ...interface{}) {
   147  	log.logwrite(INFO, 3, format, v...)
   148  }
   149  
   150  func (log *Logger) Errorf(format string, v ...interface{}) {
   151  	log.logwrite(ERROR, 3, format, v...)
   152  }
   153  
   154  func (log *Logger) Fatalf(format string, v ...interface{}) {
   155  	log.logwrite(FATAL, 3, format, v...)
   156  }
   157  
   158  func (log *Logger) Panicf(format string, v ...interface{}) {
   159  	log.logwrite(PANIC, 3, format, v...)
   160  }
   161  
   162  func (log *Logger) GetLogidStr(format string) string {
   163  	if logidCreator != nil {
   164  		return fmt.Sprintf(format, logidCreator.GetLogid())
   165  	}
   166  	return ""
   167  }
   168  
   169  func (log *Logger) logwrite(typ LogLevel, calldepth int, format string, v ...interface{}) {
   170  	if typ > log.loglevel {
   171  		return
   172  	}
   173  
   174  	var (
   175  		idstr  = log.GetLogidStr("[%s] ")
   176  		prestr = idstr // + "[" + log.module + "] "
   177  	)
   178  
   179  	format = strings.Trim(format, "\n")
   180  	switch typ {
   181  	case PANIC:
   182  		log.golog.SetPrefix("\x1b[31m" + "PANI ")
   183  	case FATAL:
   184  		log.golog.SetPrefix("\x1b[31m" + "FATA ")
   185  	case WARNING:
   186  		log.golog.SetPrefix("\x1b[32m" + "WARN ")
   187  	case ERROR:
   188  		log.golog.SetPrefix("\x1b[32m" + "ERRO ")
   189  	case INFO:
   190  		log.golog.SetPrefix("INFO ")
   191  	case NOTICE:
   192  		log.golog.SetPrefix("NOTI ")
   193  	case DEBUG:
   194  		log.golog.SetPrefix("DBUG ")
   195  	default:
   196  		log.golog.SetPrefix("UNKN ")
   197  	}
   198  
   199  	if mylog == log {
   200  		calldepth = calldepth + 1
   201  	}
   202  
   203  	if typ == FATAL || typ == WARNING || typ == ERROR {
   204  		log.golog.Output(calldepth, prestr+fmt.Sprintf(format+"\x1b[0m\n", v...))
   205  	} else if typ == NOTICE {
   206  		calldepth = calldepth + 2
   207  		log.golog.Output(calldepth, prestr+fmt.Sprintf(format+"\n", v...))
   208  	} else if typ == PANIC {
   209  		stack := strings.Replace(string(debug.Stack()), "\n", "\n==    ", -1)
   210  		stack = str.SkipLine(stack, calldepth*2+1)
   211  		v = append(v, stack)
   212  		panicstr := fmt.Sprintf(prestr+format+"\x1b[0m. Panic stack:\n%s\n", v...)
   213  		log.golog.Output(calldepth, panicstr)
   214  		panic(ErrLogPanic)
   215  	} else {
   216  		log.golog.Output(calldepth, prestr+fmt.Sprintf(format+"\n", v...))
   217  	}
   218  }
   219  
   220  func needWriteLogToFile() bool {
   221  	if cls, ok := os.LookupEnv("QOOLOG_CLOSE_FILELOG"); ok && cls != "N" && cls != "n" {
   222  		return false
   223  	} else if ink8s, ok := os.LookupEnv("KUBERNETES_PORT"); ok && ink8s != "" {
   224  		return false
   225  	}
   226  	return true
   227  }
   228  
   229  // //////////////////////////////////////////////////////////////////////////////////
   230  // ///////////////////////Initialize/////////////////////////////////////////////////
   231  // //////////////////////////////////////////////////////////////////////////////////
   232  var once sync.Once = sync.Once{}
   233  
   234  // init
   235  func init() {
   236  	once.Do(initlog)
   237  }
   238  
   239  // initlog
   240  func initlog() {
   241  	// Step 1. create base writer & cache writer for ALL log
   242  	var (
   243  		logDir          = "./logs/"
   244  		logName         = getExeFilename()
   245  		logDirsOptional = []string{"./log", "/var/log"}
   246  		logSplitTag     = "20060102" //20060102150405
   247  		baseWriter      = NewBaseWriter(nil, os.Stdout, nil)
   248  		gologFlags      = log.Ldate | log.Lmicroseconds | log.Lshortfile
   249  	)
   250  
   251  	// Step 2. init golog(golang std logger) & mylog(myself defined logger)
   252  	golog = log.New(NewCacheWriter(baseWriter), "", gologFlags)
   253  	mylog = New("system")
   254  
   255  	// Step 3. backgroud split log (log rotate) if need
   256  	if needWriteLogToFile() {
   257  		go func() {
   258  			baseWriter.OpenLogFile(logDir, logName, logDirsOptional)
   259  			for {
   260  				tag := time.Now().Local().Format(logSplitTag)
   261  				baseWriter.TryBackupLogFile(tag)
   262  				time.Sleep(2 * time.Minute)
   263  			}
   264  		}()
   265  	}
   266  }