package impl_localfile import ( "fmt" "path/filepath" "strconv" "strings" "sync" "time" "goutil/fileUtil" "goutil/timeUtil" ) const ( con_SEPERATOR = "\n------------------------------------------------------\n" ) // Logger // @description: 日志对象 type Logger struct { logPath string loggerMap map[levelType]*fileLog bufPool *sync.Pool // 压缩属性 // 上一次日志压缩的日期 时间戳 preCompressDate int64 // 压缩锁对象 compressLock sync.Mutex } // NewLogger // @description: 构造日志对象 // parameter: // // @*Logger: func NewLogger() *Logger { log := &Logger{ logPath: "Log", loggerMap: make(map[levelType]*fileLog, 4), bufPool: &sync.Pool{ New: func() interface{} { return &strings.Builder{} }, }, } // 初始化基础日志 for lv := range levels { log.loggerMap[levelType(lv)] = newLog(log.logPath, levelType(lv)) } return log } // log // @description: 记录日志 // parameter: // // @receiver l: // @logInfo: // @lv: // @ifIncludeHour: // // return: func (l *Logger) log(logInfo string, lv levelType, ifIncludeHour bool) { buf := l.bufPool.Get().(*strings.Builder) defer l.bufPool.Put(buf) buf.Reset() // 组装所有需要写入的内容 // 获取当前时间 buf.WriteString(time.Now().Format("2006-01-02 15:04:05")) buf.WriteString("---->\n") buf.WriteString(logInfo) // 加上最后的分隔符 buf.WriteString(con_SEPERATOR) // 写入之前检查 l.checkCompress() // 构造对象并添加到队列中 l.loggerMap[lv].msgChan <- newLogObject(buf.String(), lv, ifIncludeHour) } // SetLogPath // @description: 设置文件路径 // parameter: // // @receiver l: // @_logPath: // // return: func (l *Logger) SetLogPath(_logPath string) { l.logPath = _logPath for _, lf := range l.loggerMap { lf.SetLogPath(_logPath) } } // checkCompress // @description: 压缩 // parameter: // // @receiver l: // // return: func (l *Logger) checkCompress() { // 不用压缩,直接返回 if !l.preCompress() { return } // 日志压缩 go l.doCompress() } // closeLogFile // @description: 关闭日志文件 // parameter: // // @receiver l: // // return: func (l *Logger) closeLogFile() { // 需要压缩文件,关闭已经打开的文件 for _, lf := range l.loggerMap { _ = lf.f.Close() } } // preCompress 确定是否要压缩 func (l *Logger) preCompress() bool { // 检查是否需要进行数据压缩 nowDate := timeUtil.GetDate(time.Now()).Unix() if nowDate == l.preCompressDate { return false } l.compressLock.Lock() defer l.compressLock.Unlock() // 上一次压缩的时间 if nowDate == l.preCompressDate { return false } l.closeLogFile() l.preCompressDate = nowDate return true } // 日志压缩 func (l *Logger) doCompress() { defer func() { if r := recover(); r != nil { // 将错误输出,而不是记录到文件,是因为可能导致死循环 fmt.Println(r) } }() // 获取昨天的日期,并获取昨天对应的文件夹 yesterday := time.Now().AddDate(0, 0, -1) dateString := timeUtil.Format(yesterday, "yyyy-MM-dd") fileAbsoluteDirectory := filepath.Join(l.logPath, strconv.Itoa(yesterday.Year()), strconv.Itoa(int(yesterday.Month()))) // 判断是否已经存在压缩文件 compressFileName := fmt.Sprintf("%s.tar.gz", dateString) compressAbsolutePath := filepath.Join(fileAbsoluteDirectory, compressFileName) if exists, err := fileUtil.IsFileExists(compressAbsolutePath); err == nil && exists { return } // 获取昨天的文件列表 fileList, err := fileUtil.GetFileList2(fileAbsoluteDirectory, dateString, con_FILE_SUFFIX) if err != nil { fmt.Printf("logUtil.compress.fileUtil.GetFileList2 err:%s\n", err) return } if len(fileList) == 0 { return } // 进行tar操作,得到yyyy-MM-dd.tar tarFileName := fmt.Sprintf("%s.tar", dateString) tarAbsolutePath := filepath.Join(fileAbsoluteDirectory, tarFileName) if err := fileUtil.Tar(fileList, tarAbsolutePath); err != nil { fmt.Printf("logUtil.compress.fileUtil.Tar err:%s\n", err) } // 进行gzip操作,得到yyyy-MM-dd.tar.gz if err := fileUtil.Gzip(tarAbsolutePath, ""); err != nil { fmt.Printf("logUtil.compress.fileUtil.Gzip err:%s\n", err) } // 删除原始文件 for _, item := range fileList { _ = fileUtil.DeleteFile(item) } // 删除tar文件 _ = fileUtil.DeleteFile(tarAbsolutePath) } // getLog // @description: 组装日志 // parameter: // // @format: // @args: // // return: // // @string: func getLog(format string, args ...interface{}) string { if len(args) == 0 { return format } else { return fmt.Sprintf(format, args...) } }