|
@@ -0,0 +1,278 @@
|
|
|
+package tools
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "os"
|
|
|
+ "runtime"
|
|
|
+ "strconv"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+// 异步写日志
|
|
|
+
|
|
|
+var MyLog *FileLog
|
|
|
+
|
|
|
+const (
|
|
|
+ LogSplitTypeHour = iota
|
|
|
+ LogSplitTypeSize
|
|
|
+ logPath = "myLog"
|
|
|
+ logName = "myLog"
|
|
|
+ chanSize = 5000
|
|
|
+)
|
|
|
+
|
|
|
+type FileLog struct {
|
|
|
+ logPath string
|
|
|
+ logName string
|
|
|
+ file *os.File //普通日志
|
|
|
+ warnFile *os.File //错误日志 级别低
|
|
|
+ logDataChan chan *LogData
|
|
|
+ logSplitType int //分割类型
|
|
|
+ logSplitSize int64 //分割体积
|
|
|
+ lastSplitHour int //分割时间
|
|
|
+}
|
|
|
+
|
|
|
+type LogData struct {
|
|
|
+ Message string
|
|
|
+ TimeStr string
|
|
|
+ LevelStr string
|
|
|
+ IsWarn bool
|
|
|
+ File string
|
|
|
+}
|
|
|
+
|
|
|
+func InitLog() (log *FileLog) {
|
|
|
+ config := make(map[string]string, 8)
|
|
|
+ config["log_path"] = "."
|
|
|
+ config["log_name"] = "server"
|
|
|
+ config["log_chan_size"] = "50000" //chan size 可以不用
|
|
|
+ config["log_split_type"] = "size"
|
|
|
+ config["log_split_size"] = strconv.Itoa(100 * 1024 * 1024) // 100MB
|
|
|
+ log, err := NewFileLog(config)
|
|
|
+ if err != nil {
|
|
|
+ panic("init log err")
|
|
|
+ }
|
|
|
+ MyLog = log
|
|
|
+ return log
|
|
|
+}
|
|
|
+
|
|
|
+func NewFileLog(config map[string]string) (logFile *FileLog, err error) {
|
|
|
+
|
|
|
+ var logSplitType = LogSplitTypeSize
|
|
|
+ var logSplitSize int64
|
|
|
+
|
|
|
+ splitType, ok := config["log_split_type"]
|
|
|
+ if !ok {
|
|
|
+ splitType = "hour"
|
|
|
+ } else {
|
|
|
+ if splitType == "size" {
|
|
|
+ splitSize, ok := config["log_split_size"]
|
|
|
+ if !ok {
|
|
|
+ splitSize = "104857600" //100M 以文字来讲很多了
|
|
|
+ }
|
|
|
+
|
|
|
+ logSplitSize, err = strconv.ParseInt(splitSize, 10, 64)
|
|
|
+ if err != nil {
|
|
|
+ logSplitSize = 104857600
|
|
|
+ }
|
|
|
+
|
|
|
+ logSplitType = LogSplitTypeSize
|
|
|
+ } else {
|
|
|
+ logSplitType = LogSplitTypeHour
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //打开日志文件
|
|
|
+ exist, err := PathIsExists(logPath)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Printf("get dir error![%v]\n", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if !exist {
|
|
|
+ err = os.Mkdir(logPath, os.ModePerm)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Printf("mkdir failed![%v]\n", err)
|
|
|
+ return
|
|
|
+ } else {
|
|
|
+ fmt.Printf("mkdir success!\n")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //正常日志
|
|
|
+ fileName := fmt.Sprintf("%s/%s.log", logPath, logName)
|
|
|
+ file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
|
|
|
+ //错误日志
|
|
|
+ fileNameWarn := fmt.Sprintf("%s/%s.log.err", logPath, logName)
|
|
|
+ fileWarn, err := os.OpenFile(fileNameWarn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ logFile = &FileLog{
|
|
|
+ logPath: logPath,
|
|
|
+ logName: logName,
|
|
|
+ logDataChan: make(chan *LogData, chanSize),
|
|
|
+ file: file,
|
|
|
+ warnFile: fileWarn,
|
|
|
+ logSplitType: logSplitType,
|
|
|
+ logSplitSize: logSplitSize,
|
|
|
+ lastSplitHour: time.Now().Hour(),
|
|
|
+ }
|
|
|
+ go logFile.writeLogBackGround()
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// 判断文件夹是否存在
|
|
|
+func PathIsExists(path string) (bool, error) {
|
|
|
+ _, err := os.Stat(path)
|
|
|
+ if err == nil {
|
|
|
+ return true, nil
|
|
|
+ }
|
|
|
+ if os.IsNotExist(err) {
|
|
|
+ return false, nil
|
|
|
+ }
|
|
|
+ return false, err
|
|
|
+}
|
|
|
+
|
|
|
+func (f *FileLog) Info(message string) {
|
|
|
+ _, file, line, _ := runtime.Caller(1)
|
|
|
+ fi := file + ":" + strconv.Itoa(line)
|
|
|
+ f.print(message, "info", fi)
|
|
|
+}
|
|
|
+func (f *FileLog) Debug(message string) {
|
|
|
+ _, file, line, _ := runtime.Caller(1)
|
|
|
+ fi := file + ":" + strconv.Itoa(line)
|
|
|
+ f.print(message, "debug", fi)
|
|
|
+}
|
|
|
+func (f *FileLog) Warn(message string) {
|
|
|
+ _, file, line, _ := runtime.Caller(1)
|
|
|
+ fi := file + ":" + strconv.Itoa(line)
|
|
|
+ f.print(message, "warn", fi)
|
|
|
+}
|
|
|
+func (f *FileLog) Error(message string) {
|
|
|
+ _, file, line, _ := runtime.Caller(1)
|
|
|
+ fi := file + ":" + strconv.Itoa(line)
|
|
|
+ f.print(message, "error", fi)
|
|
|
+}
|
|
|
+
|
|
|
+func (f *FileLog) print(message, Type string, file string) {
|
|
|
+ isWarn := false
|
|
|
+ if Type == "error" {
|
|
|
+ isWarn = true
|
|
|
+ }
|
|
|
+ msg := &LogData{
|
|
|
+ Message: message,
|
|
|
+ TimeStr: time.Now().Format("2006-01-02 15:04:05"),
|
|
|
+ LevelStr: Type,
|
|
|
+ IsWarn: isWarn,
|
|
|
+ File: file,
|
|
|
+ }
|
|
|
+ // 怕chan满了插不进去
|
|
|
+ select {
|
|
|
+ case f.logDataChan <- msg:
|
|
|
+ default:
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (f *FileLog) writeLogBackGround() {
|
|
|
+ for logData := range f.logDataChan {
|
|
|
+ var file = f.file
|
|
|
+ if logData.IsWarn {
|
|
|
+ file = f.warnFile
|
|
|
+ }
|
|
|
+
|
|
|
+ f.checkSplitFile(logData.IsWarn) // 检查文件分割类型
|
|
|
+ fmt.Fprintf(file, "%s %s %s %s\n", logData.TimeStr, logData.LevelStr, logData.Message, logData.File)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (f *FileLog) checkSplitFile(isWarn bool) {
|
|
|
+ if f.logSplitType == LogSplitTypeHour {
|
|
|
+ f.splitHour(isWarn)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ f.splitSize(isWarn)
|
|
|
+}
|
|
|
+
|
|
|
+// 根据时间切割
|
|
|
+func (f *FileLog) splitHour(isWarn bool) {
|
|
|
+
|
|
|
+ now := time.Now()
|
|
|
+ hour := now.Hour()
|
|
|
+
|
|
|
+ if hour == f.lastSplitHour {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ f.lastSplitHour = hour
|
|
|
+
|
|
|
+ var backupFileName string
|
|
|
+ var fileName string
|
|
|
+
|
|
|
+ if isWarn {
|
|
|
+ backupFileName = fmt.Sprintf("%s/%s.log.err_%s", f.logPath, f.logName, now.Format("20060102150405"))
|
|
|
+ fileName = fmt.Sprintf("%s/%s.log.err", f.logPath, f.logName)
|
|
|
+ } else {
|
|
|
+ backupFileName = fmt.Sprintf("%s/%s.log_%s", f.logPath, f.logName, now.Format("20060102150405"))
|
|
|
+ fileName = fmt.Sprintf("%s/%s.log", f.logPath, f.logName)
|
|
|
+ }
|
|
|
+
|
|
|
+ file := f.file
|
|
|
+ if isWarn {
|
|
|
+ file = f.warnFile
|
|
|
+ }
|
|
|
+ file.Close()
|
|
|
+ os.Rename(fileName, backupFileName)
|
|
|
+
|
|
|
+ file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if isWarn {
|
|
|
+ f.warnFile = file
|
|
|
+ } else {
|
|
|
+ f.file = file
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// 根据文件大小来分割
|
|
|
+func (f *FileLog) splitSize(isWarn bool) {
|
|
|
+ file := f.file
|
|
|
+ if isWarn {
|
|
|
+ file = f.warnFile
|
|
|
+ }
|
|
|
+ fileInfo, err := file.Stat() // 可以得到文件的参数
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ fileSize := fileInfo.Size()
|
|
|
+ if fileSize <= f.logSplitSize {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ var backupFileName string
|
|
|
+ var fileName string
|
|
|
+
|
|
|
+ now := time.Now()
|
|
|
+
|
|
|
+ if isWarn {
|
|
|
+ backupFileName = fmt.Sprintf("%s/%s.log_%s", f.logPath, f.logName, now.Format("20060102150405"))
|
|
|
+ fileName = fmt.Sprintf("%s/%s.log", f.logPath, f.logName)
|
|
|
+ } else {
|
|
|
+ backupFileName = fmt.Sprintf("%s/%s.log.err_%s", f.logPath, f.logName, now.Format("20060102150405"))
|
|
|
+ fileName = fmt.Sprintf("%s/%s.log.err", f.logPath, f.logName)
|
|
|
+ }
|
|
|
+
|
|
|
+ file.Close()
|
|
|
+ os.Rename(fileName, backupFileName)
|
|
|
+
|
|
|
+ file, err = os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if isWarn {
|
|
|
+ f.warnFile = file
|
|
|
+ } else {
|
|
|
+ f.file = file
|
|
|
+ }
|
|
|
+}
|