package f5 import ( "fmt" "os" "q5" "sync" "time" ) 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) SetPolyLog(isPolyLog bool) { this.isPolyLog = isPolyLog } func (this *tgLog) AddTrackLog( gameId int32, accountId string, distinctId string, ip string, eventName string, prop map[string]string) { logObj := struct { AccountId string `json:"#account_id"` DistinctId string `json:"#distinct_id"` Type string `json:"#type""` Time string `json:"#time"` Ip string `json:"#ip""` EventName string `json:"#event_name""` Properties map[string]string `json:"properties"` }{ AccountId: accountId, DistinctId: distinctId, Type: "track", Time: q5.FormatUnixDateTime(_app.GetRealSeconds(), _app.GetLocation()), EventName: eventName, Ip: ip, Properties: prop, } p := new(tgLogMsgNode) p.gameId = gameId p.jsonStr = q5.EncodeJson(logObj) 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) AddCustomLog( gameId int32, accountId string, distinctId string, ip string, prop map[string]interface{}) { logObj := struct { AccountId string `json:"#account_id"` DistinctId string `json:"#distinct_id"` Type string `json:"#type""` Time string `json:"#time"` Ip string `json:"#ip""` EventName string `json:"#event_name""` Properties map[string]interface{} `json:"properties"` }{ AccountId: accountId, DistinctId: distinctId, Type: "track", Time: q5.FormatUnixDateTime(_app.GetRealSeconds(), _app.GetLocation()), EventName: "custom_event", Ip: ip, Properties: prop, } p := new(tgLogMsgNode) p.gameId = gameId p.jsonStr = q5.EncodeJson(logObj) 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() workNode = this.topNode this.topNode = nil this.botNode = nil this.msgMutex.Unlock() if workNode != nil { for workNode != nil { f := this.getLogFile(workNode.gameId) if f != nil { f.Write([]byte(workNode.jsonStr + "\n")) f.Close() } workNode = workNode.next } } } } func (this *tgLog) getLogFile(gameId int32) *os.File { fileName := fmt.Sprintf(TGLOG_FILENAME, os.Getpid(), q5.FormatUnixDateEx(_app.GetRealSeconds(), _app.GetLocation())) 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_CREATE|os.O_APPEND, 0666); err == nil { return f } else { _sysLog.Warning("tgLog.goSaveToFile err:%s", err) return nil } }