go開發屬於本身的日誌庫-日誌切分

在文件日誌中,還存在一個問題,就是在日誌寫文件時間長了之後,日誌文件確定會很是大,內容很是多,這個時候若是咱們須要去定位一個錯誤,會耗費很長的時間。因此咱們須要將日誌文件進行分割,分割文件咱們能夠採用一天分割一次,或者文件大小達到一個體積進行分割。 log_const.gogit

const (
	LogSplitTypeHour = iota
	LogSplitTypeSize
)
複製代碼

file.gogithub

type FileLog struct {
	logPath       string
	logName       string
	file          *os.File
	warnFile      *os.File
	logDataChan   chan *LogData
	logSplitType  int  //分割類型
	logSplitSize  int64 //分割體積
	lastSplitHour int //分割時間
}


func NewFileLog(config map[string]string) (logFile Log, 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
		}
	}

	logFile = &FileLog{
		logPath:       logPath,
		logName:       logName,
		logDataChan:   make(chan *LogData, chanSize),
		logSplitType:  logSplitType,
		logSplitSize:  logSplitSize,
		lastSplitHour: time.Now().Hour(),
	}

	logFile.Init()
	return
}

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:%d] %s\n", logData.TimeStr, logData.LevelStr,
			logData.FileName, logData.FuncName, logData.LineNo, logData.Message)
	}
}

func (f *FileLog) checkSplitFile(isWarn bool) {
	if f.logSplitType == LogSplitTypeHour {
		f.splitHour(isWarn)
		return
	}
	f.splitSize(isWarn)
}

// 根據文件大小來分割
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.wf_%s", f.logPath, f.logName, now.Format("20060102150405"))
		fileName = fmt.Sprintf("%s/%s.log.wf", 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.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) 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.wf_%s", f.logPath, f.logName, now.Format("20060102150405"))
		fileName = fmt.Sprintf("%s/%s.log.wf", 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 initLog(logPath, logName string) {
   //log := hm_log.NewFileLog(logPath, logName)
	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"] = "104857600" // 100MB
   err := InitLog("file", config)
	 if err != nil {
		 return
	 }
	 
	 for {
		log.Warn("%s", "123")
	}
}
複製代碼

等一段時間看看是否進行分割了。 這裏是源文件hm_logui

咱們日誌庫就已經開發完成了,固然,和目前主流的日誌庫比還顯得簡漏。不過咱們的目的不在於寫的多好,而在於寫的過程。也歡迎各位真正裏面的錯誤,謝謝。spa

相關文章
相關標籤/搜索