diff --git a/app.go b/app.go index 0678b1d..649e77c 100644 --- a/app.go +++ b/app.go @@ -9,6 +9,7 @@ type App_ struct { nodeId int instanceId int terminated bool + pkgName string flags map[int32]int32 servicing bool contextHash map[int32]q5.XParams @@ -28,6 +29,8 @@ func (this *App_) Init() { nil, 1000 * 60, 5000) + _SysLog = new(SysLog_) + _SysLog.Init() flag.IntVar(&this.nodeId, "n", 0, "node id") flag.IntVar(&this.instanceId, "i", 0, "instance id") flag.Parse() @@ -61,6 +64,14 @@ func (this *App_) GetNodeId() uint32 { return uint32(this.nodeId) } +func (this *App_) GetPkgName() string { + return this.pkgName +} + +func (this *App_) SetPkgName(pkgName string) { + this.pkgName = pkgName +} + func (this *App_) HasFlag(flag int32) bool { _, ok := this.flags[flag] return ok diff --git a/global.go b/global.go index c68bf36..59b70a2 100644 --- a/global.go +++ b/global.go @@ -4,7 +4,12 @@ import "q5" var App *App_ var _Timer *q5.Timer +var _SysLog *SysLog_ func Timer() *q5.Timer { return _Timer } + +func SysLog() *SysLog_ { + return _SysLog +} diff --git a/syslog.go b/syslog.go index c91168f..a14969d 100644 --- a/syslog.go +++ b/syslog.go @@ -1,15 +1,141 @@ package f5 -type SysLog_ struct { +import "os" +import "sync" +import "time" +import "fmt" +import "q5" +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_ROOT = "/data/logs/%s/logs/" +const SYS_LOG_FILENAME = "log_%d_%s.log" + +type LogMsgNode struct { + logMsg string + next *LogMsgNode } -var SysLog *SysLog_ +type SysLog_ struct { + logLevel int32 + debuging bool + 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("[EMERGENCY]", format, args...) +} + +func (this *SysLog_) Alert(format string, args ...interface{}) { + if this.logLevel > LOG_ALERT { + return + } + this.addLog("[ALERT]", format, args...) +} + +func (this *SysLog_) Error(format string, args ...interface{}) { + if this.logLevel > LOG_ERROR { + return + } + this.addLog("[ERROR]", format, args...) +} + +func (this *SysLog_) Warning(format string, args ...interface{}) { + if this.logLevel > LOG_WARNING { + return + } + this.addLog("[WARNING]", format, args...) +} + +func (this *SysLog_) Notice(format string, args ...interface{}) { + if this.logLevel > LOG_NOTICE { + return + } + this.addLog("[NOTICE]", format, args...) +} + +func (this *SysLog_) Info(format string, args ...interface{}) { + if this.logLevel > LOG_INFO { + return + } + this.addLog("[INFO]", format, args...) +} + +func (this *SysLog_) Debug(format string, args ...interface{}) { + if this.logLevel > LOG_DEBUG { + return + } + this.addLog("[DEBUG]", format, args...) +} + +func (this *SysLog_) addLog(category string, format string, args ...interface{}) { + p := &LogMsgNode{} + p.logMsg = time.Now().Format("2006-01-02 15:04:05") + category + " " + fmt.Sprintf(format, args...) + "\n" + if this.debuging { + 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 * 1000 * 10): + } + { + this.msgMutex.Lock() + defer this.msgMutex.Unlock() + workNode = this.topNode + this.topNode = nil + this.botNode = nil + } + if workNode != nil { + logDir := fmt.Sprintf(SYS_LOG_ROOT, App.GetPkgName()) + fileName := fmt.Sprintf(TGLOG_FILENAME, os.Getpid(), time.Now().Format("20060102")) + q5.ForceCreateDir(logDir) + if f, err := os.OpenFile(logDir + fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err == nil { + defer f.Close() + for workNode != nil { + f.Write([]byte(workNode.logMsg)) + workNode = workNode.next + } + } else { + fmt.Println(err) + } + } + } } diff --git a/tglog.go b/tglog.go index 844eb9b..7109d75 100644 --- a/tglog.go +++ b/tglog.go @@ -1 +1,117 @@ package f5 + +import "os" +import "fmt" +import "sync" +import "time" +import "q5" + +const TGLOG_ROOT = "/data/logs/%s/upload/" +const POLY_TGLOG_ROOT = "/data/logs/%s/%s/upload/" +const TGLOG_FILENAME = "log_%d_%s.log" + +type TGLogMsgNode struct { + gameId int32 + jsonStr string + next *TGLogMsgNode +} + +type TGLog_ struct { + isPolyLog bool + topNode *TGLogMsgNode + botNode *TGLogMsgNode + msgMutex sync.Mutex + chGoSaveExit chan int +} + +func (this *TGLog_) Init() { + this.chGoSaveExit = make(chan int) + go this.goSaveToFile() +} + +func (this *TGLog_) UnInit() { + this.chGoSaveExit <- 1 +} + +func (this *TGLog_) AddTrackLog( + gameId int32, + accountId string, + remoteAddr string, + logClass1 int32, + logClass2 int32, + prop *q5.XObject) { + eventName := fmt.Sprintf("event_%d_%d", logClass1, logClass2) + this.AddTrackLogEx(gameId, accountId, remoteAddr, eventName, prop) +} + +func (this *TGLog_) AddTrackLogEx( + gameId int32, + accountId string, + remoteAddr string, + eventName string, + prop *q5.XObject) { + var xobj *q5.MutableXObject + xobj.SetXValue("#account_id", new(q5.XValue).SetString(accountId)) + xobj.SetXValue("#type", new(q5.XValue).SetString("track")) + xobj.SetXValue("#time", new(q5.XValue).SetString(time.Now().Format("2006-01-02 15:04:05"))) + xobj.SetXValue("#event_name", new(q5.XValue).SetString("eventName")) + + xobj.SetXObject("#properties", prop) + + p := new(TGLogMsgNode) + p.gameId = gameId + p.jsonStr = xobj.ToJsonStr() + 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 *TGLog_) goSaveToFile() { + var workNode *TGLogMsgNode + for { + select { + case <-this.chGoSaveExit: + return + case <-time.After(time.Millisecond * 1000 * 10): + } + { + this.msgMutex.Lock() + defer this.msgMutex.Unlock() + workNode = this.topNode + this.topNode = nil + this.botNode = nil + } + if workNode != nil { + for workNode != nil { + f := this.getLogFile(workNode.gameId) + if f != nil { + defer f.Close() + f.Write([]byte(workNode.jsonStr + "\n")) + } + workNode = workNode.next + } + } + } +} + +func (this *TGLog_) getLogFile(gameId int32) *os.File { + fileName := fmt.Sprintf(TGLOG_FILENAME, os.Getpid(), time.Now().Format("20060102")) + logDir := "" + if this.isPolyLog { + logDir = fmt.Sprintf(POLY_TGLOG_ROOT, App.GetPkgName(), gameId) + } else { + logDir = fmt.Sprintf(TGLOG_ROOT, App.GetPkgName()) + } + q5.ForceCreateDir(logDir) + if f, err := os.OpenFile(logDir + fileName, os.O_WRONLY|os.O_APPEND, 0666); err == nil { + return f + } else { + return nil + } +}