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 }