package f5 import ( "fmt" "os" "q5" "sync" "time" ) const ( LOG_DEBUG = 0 LOG_INFO = iota LOG_NOTICE = iota LOG_WARNING = iota LOG_ERROR = iota LOG_ALERT = iota LOG_EMERGENCY = iota ) const ( SYS_LOG_FILENAME = "log_%d_%s.log" ) type logMsgNode struct { category int32 logMsg string next *logMsgNode } type sysLog struct { logLevel int32 topNode *logMsgNode botNode *logMsgNode msgMutex sync.Mutex chGoSaveExit chan int } func (this *sysLog) init() { this.chGoSaveExit = make(chan int) go this.goSaveToFile() } func (this *sysLog) unInit() { this.chGoSaveExit <- 1 } func (this *sysLog) Emergency(format string, args ...interface{}) { if this.logLevel > LOG_EMERGENCY { return } this.addLog(LOG_EMERGENCY, "[EMERGENCY]", format, args...) } func (this *sysLog) Alert(format string, args ...interface{}) { if this.logLevel > LOG_ALERT { return } this.addLog(LOG_ALERT, "[ALERT]", format, args...) } func (this *sysLog) Error(format string, args ...interface{}) { if this.logLevel > LOG_ERROR { return } this.addLog(LOG_ERROR, "[ERROR]", format, args...) } func (this *sysLog) Warning(format string, args ...interface{}) { if this.logLevel > LOG_WARNING { return } this.addLog(LOG_WARNING, "[WARNING]", format, args...) } func (this *sysLog) Notice(format string, args ...interface{}) { if this.logLevel > LOG_NOTICE { return } this.addLog(LOG_NOTICE, "[NOTICE]", format, args...) } func (this *sysLog) Info(format string, args ...interface{}) { if this.logLevel > LOG_INFO { return } this.addLog(LOG_INFO, "[INFO]", format, args...) } func (this *sysLog) Debug(format string, args ...interface{}) { if this.logLevel > LOG_DEBUG { return } this.addLog(LOG_DEBUG, "[DEBUG]", format, args...) } func (this *sysLog) addLog(category int32, prefixStr string, format string, args ...interface{}) { p := &logMsgNode{} p.category = category p.logMsg = q5.FormatUnixDateTime(_app.GetNowSeconds(), _app.GetLocation()) + prefixStr + " " + fmt.Sprintf(format, args...) + "\n" if category == LOG_INFO || q5.IsDebug() { fmt.Print(p.logMsg) } this.msgMutex.Lock() defer this.msgMutex.Unlock() if this.botNode != nil { this.botNode.next = p this.botNode = p } else { this.topNode = p this.botNode = p } } func (this *sysLog) goSaveToFile() { var workNode *logMsgNode for { select { case <-this.chGoSaveExit: return case <-time.After(time.Millisecond * 10): } this.msgMutex.Lock() workNode = this.topNode this.topNode = nil this.botNode = nil this.msgMutex.Unlock() if workNode != nil { logDir := fmt.Sprintf(SYS_LOG_ROOT, GetApp().GetPkgName()) fileName := fmt.Sprintf(TGLOG_FILENAME, os.Getpid(), q5.FormatUnixDateEx(_app.GetNowSeconds(), _app.GetLocation())) q5.ForceCreateDir(logDir) if f, err := os.OpenFile(logDir+fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err == nil { for workNode != nil { f.Write([]byte(workNode.logMsg)) workNode = workNode.next } f.Close() } else { fmt.Println(err) } } } }