package icslog import ( "bytes" "fmt" "io/ioutil" "log" "os" "path/filepath" "runtime/debug" "strconv" "strings" "sync" "time" "gitlab.com/cinnamon/voiceagent/icsconf" "gitlab.com/cinnamon/voiceagent/icserror" "gitlab.com/cinnamon/voiceagent/icsutil" ) type IcsLog struct { logger *log.Logger Output int Level int Path string LogFileName string LogFile *os.File DiskLimit int DelDay int DelHour int isRotate bool logSize int rotateNum int buf bytes.Buffer CurrentDate time.Time conf *icsconf.LogConfig //conf *icsconf.IcsConfig IsDiskFull bool M *sync.Mutex } //default max log size 30 megabytes const DEFAULT_LOG_MAX_SIZE = 30 //default log rotate num const DEFAULT_LOG_ROTATE_NUM = 10 //max log rotate num const MAX_LOG_ROTATE_NUM = 99 const ( LOG_LEVEL_DEBUG2 = iota LOG_LEVEL_DEBUG1 LOG_LEVEL_DEBUG LOG_LEVEL_STATIS LOG_LEVEL_INFO LOG_LEVEL_WARN LOG_LEVEL_ERROR LOG_LEVEL_FATAL LOG_LEVEL_MAX ) //log output const ( LOG_OUTPUT_FILE = 1 << (32 - 1 - iota) LOG_OUTPUT_STDOUT ) var IcsLogLevelStr [LOG_LEVEL_MAX]string var gIcsLog *IcsLog var onceLog sync.Once func init() { IcsLogLevelStr[LOG_LEVEL_DEBUG2] = "DEBUG2" IcsLogLevelStr[LOG_LEVEL_DEBUG1] = "DEBUG1" IcsLogLevelStr[LOG_LEVEL_DEBUG] = "DEBUG" IcsLogLevelStr[LOG_LEVEL_STATIS] = "STATISTICS" IcsLogLevelStr[LOG_LEVEL_INFO] = "INFO" IcsLogLevelStr[LOG_LEVEL_WARN] = "WARN" IcsLogLevelStr[LOG_LEVEL_ERROR] = "ERROR" IcsLogLevelStr[LOG_LEVEL_FATAL] = "FATAL" } //if fail, return icserror func NewIcsLog(conf *icsconf.LogConfig, level int, output int, path string, disklimit int) (*IcsLog, *icserror.IcsError) { //func NewIcsLog(conf *icsconf.IcsConfig, level int, output int, path string, disklimit int) (*IcsLog, *icserror.IcsError) { //func NewIcsLog(conf *icsconf.IcsConfig, level interface{}, output interface{}, path string, disklimit int) (*IcsLog, *icserror.IcsError) { var reterr *icserror.IcsError = nil //singleton onceLog.Do(func() { gIcsLog = &IcsLog{ conf: conf, Level: level, Output: output, Path: path, DiskLimit: disklimit, IsDiskFull: false, logSize: DEFAULT_LOG_MAX_SIZE, rotateNum: DEFAULT_LOG_ROTATE_NUM, } gIcsLog.M = &sync.Mutex{} gIcsLog.isRotate = strings.Compare("YES", strings.ToUpper(gIcsLog.conf.RotateConfig.YesNo)) == 0 //gIcsLog.isRotate = strings.Compare("YES", strings.ToUpper(gIcsLog.conf.LogConfig.RotateConfig.YesNo)) == 0 var serr error gIcsLog.logSize, serr = strconv.Atoi(gIcsLog.conf.RotateConfig.Size) //gIcsLog.logSize, serr = strconv.Atoi(gIcsLog.conf.LogConfig.RotateConfig.Size) if serr != nil { gIcsLog.logSize = DEFAULT_LOG_MAX_SIZE } gIcsLog.rotateNum, serr = strconv.Atoi(gIcsLog.conf.RotateConfig.Num) //gIcsLog.rotateNum, serr = strconv.Atoi(gIcsLog.conf.LogConfig.RotateConfig.Num) if serr != nil { gIcsLog.rotateNum = DEFAULT_LOG_ROTATE_NUM } if gIcsLog.rotateNum > MAX_LOG_ROTATE_NUM { gIcsLog.rotateNum = MAX_LOG_ROTATE_NUM } gIcsLog.logger = log.New(&gIcsLog.buf, "", log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile) gIcsLog.CurrentDate = time.Now() gIcsLog.DelDay = conf.DelConfig.DelDay gIcsLog.DelHour = conf.DelConfig.DelHour //make log file - icssoe.log-yyyymmdd yyyy, mm, dd := gIcsLog.CurrentDate.Date() gIcsLog.LogFileName = fmt.Sprintf("%s/icsbot.log-%d%02d%02d", gIcsLog.Path, yyyy, mm, dd) stat, err := os.Stat(gIcsLog.LogFileName) if err == nil { if gIcsLog.checkLogRotate() && stat.Size()/ONEMB >= int64(gIcsLog.logSize) { rotateNum := gIcsLog.getTodayLogFileNum() //fmt.Println("rotate num:", rotateNum) if rotateNum > 0 && rotateNum < gIcsLog.rotateNum { gIcsLog.shiftLogFiles(rotateNum) var oerr error oerr = os.MkdirAll(filepath.Dir(gIcsLog.LogFileName), 0777) if oerr != nil { icserror.ICSERRMakeDir.SetError(oerr) icserror.ICSERRMakeDir.PrintWithCaller(0) return } gIcsLog.LogFile, oerr = os.OpenFile(gIcsLog.LogFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if oerr != nil { //fmt.Println(gIcsLog.LogFileName) icserror.ICSERRFileOpen.SetError(oerr) reterr = icserror.ICSERRFileOpen reterr.PrintWithCaller(0) return } } } else if stat.Size()/ONEMB < int64(gIcsLog.logSize) { var oerr error oerr = os.MkdirAll(filepath.Dir(gIcsLog.LogFileName), 0777) if oerr != nil { icserror.ICSERRMakeDir.SetError(oerr) icserror.ICSERRMakeDir.PrintWithCaller(0) return } gIcsLog.LogFile, oerr = os.OpenFile(gIcsLog.LogFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if oerr != nil { //fmt.Println(gIcsLog.LogFileName) icserror.ICSERRFileOpen.SetError(oerr) reterr = icserror.ICSERRFileOpen reterr.PrintWithCaller(0) return } } } else { var oerr error oerr = os.MkdirAll(filepath.Dir(gIcsLog.LogFileName), 0777) if oerr != nil { icserror.ICSERRMakeDir.SetError(oerr) icserror.ICSERRMakeDir.PrintWithCaller(0) return } gIcsLog.LogFile, oerr = os.OpenFile(gIcsLog.LogFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if oerr != nil { //fmt.Println(gIcsLog.LogFileName) icserror.ICSERRFileOpen.SetError(oerr) reterr = icserror.ICSERRFileOpen reterr.PrintWithCaller(0) return } } }) return gIcsLog, reterr } func GetIcsLog() *IcsLog { return gIcsLog } func GetLogLevelID(str string) int { switch str { case "DEBUG2": return LOG_LEVEL_DEBUG2 case "DEBUG1": return LOG_LEVEL_DEBUG1 case "DEBUG": return LOG_LEVEL_DEBUG case "STATISTICS": return LOG_LEVEL_STATIS case "INFO": return LOG_LEVEL_INFO case "WARN": return LOG_LEVEL_WARN case "ERROR": return LOG_LEVEL_ERROR case "FATAL": return LOG_LEVEL_FATAL default: return -1 } } func GetLogOutputID(str string) int { switch str { case "FILE": return LOG_OUTPUT_FILE default: return LOG_OUTPUT_STDOUT } } func (s *IcsLog) RecvDelLog() { //var derr *icserror.IcsError = nil delLogCount := 0 defer func() { if err := recover(); err != nil { switch v := err.(type) { case error: icserror.ICSERRFileOpen.SetError(v) s.Printf(LOG_LEVEL_WARN, -1, "PANIC! %s\n%s", icserror.ICSERRFileOpen.GetError().Error(), string(debug.Stack())) default: s.Print(LOG_LEVEL_WARN, -1, icserror.ICSERRFileOpen.GetError().Error()) } } //derr := icserror.ICSERRFileOpen }() // 1. Get Log Del Time yyyy, mm, dd := s.CurrentDate.Date() curTime, _ := time.Parse("2006-01-02", fmt.Sprintf("%d-%02d-%02d", yyyy, mm, dd)) delTime := curTime.AddDate(0, 0, -s.DelDay) files, rderr := ioutil.ReadDir(s.Path) if rderr != nil { s.Printf(LOG_LEVEL_ERROR, -1, " Read Log Dir error - %s \n", rderr) fmt.Printf("Read Log Dir error - %s", rderr) } else { var logYYYY, logMM, logDD string for _, file := range files { /* TODO 1. 로그 파일을 시간으로 변환 2. 현재 시간 - 삭제기간 3. 둘 시간 차이가 0 이상 나면 삭제대상 */ logTime := strings.SplitN(file.Name(), "-", -1)[1] logYYYY, logMM, logDD = logTime[:4], logTime[4:6], logTime[6:8] chgLogTime, perr := time.Parse("2006-01-02", fmt.Sprintf("%s-%s-%s", logYYYY, logMM, logDD)) if perr != nil { s.Printf(LOG_LEVEL_ERROR, -1, " Log Time Parse error - %s \n", perr) fmt.Printf("Log Time Parse error - %s", perr) } else { diff := delTime.Sub(chgLogTime) // diff > 0 => delete log if diff > 0 { delResult := icsutil.DeleteFile(s.Path, file.Name()) if delResult != "" { s.Printf(LOG_LEVEL_ERROR, -1, " Delete File error - %s \n", delResult) } else { s.Printf(LOG_LEVEL_INFO, -1, " Delete %s!!!!\n", file.Name()) fmt.Printf("Delete %s!!!!\n", file.Name()) delLogCount += 1 } } } } } s.Printf(LOG_LEVEL_INFO, -1, " Delete File Count - %d \n", delLogCount) fmt.Printf("Log Delete Count : %d\n", delLogCount) } func DelVoice() { s := GetIcsLog() conf := icsconf.GetIcsConfig() //var derr *icserror.IcsError = nil delVCount := 0 defer func() { if err := recover(); err != nil { switch v := err.(type) { case error: icserror.ICSERRFileOpen.SetError(v) s.Printf(LOG_LEVEL_WARN, -1, "PANIC! %s\n%s", icserror.ICSERRFileOpen.GetError().Error(), string(debug.Stack())) default: s.Print(LOG_LEVEL_WARN, -1, icserror.ICSERRFileOpen.GetError().Error()) } } //derr = icserror.ICSERRFileOpen }() yyyy, mm, dd := s.CurrentDate.Date() curTime, _ := time.Parse("2006-01-02", fmt.Sprintf("%d-%02d-%02d", yyyy, mm, dd)) delTime := curTime.AddDate(0, 0, -conf.VoiceConfig.DelVConfig.DelVDay) files, rderr := ioutil.ReadDir(conf.VoiceConfig.Path) if rderr != nil { s.Printf(LOG_LEVEL_ERROR, -1, " Read Voice Dir error - %s \n", rderr) fmt.Printf("Read Voice Dir error - %s\n", rderr) } else { var YYYY, MM, DD string for _, file := range files { YYYY, MM, DD = file.Name()[:4], file.Name()[4:6], file.Name()[6:8] chgVTime, perr := time.Parse("2006-01-02", fmt.Sprintf("%s-%s-%s", YYYY, MM, DD)) if perr != nil { s.Printf(LOG_LEVEL_ERROR, -1, " Voice Time Parse error - %s \n", perr) fmt.Printf("Voice Time Parse error - %s\n", perr) } else { diff := delTime.Sub(chgVTime) if diff > 0 { delResult := os.RemoveAll(fmt.Sprintf("%s/%s", conf.VoiceConfig.Path, file.Name())) if delResult != nil { s.Printf(LOG_LEVEL_ERROR, -1, " Delete File error - %s \n", delResult) fmt.Printf("Delete File error [%s] - %s \n", file.Name(), delResult.Error()) } else { s.Printf(LOG_LEVEL_INFO, -1, " Delete %s \n", file.Name()) fmt.Printf("Delete %s \n", file.Name()) delVCount += 1 } } } } } s.Printf(LOG_LEVEL_INFO, -1, " Voice Delete Count - %d \n", delVCount) fmt.Printf("Voice Delete Count : %d\n", delVCount) }