go開發屬於自己的日誌庫-檔案日誌庫實現

兒兒菜發表於2018-11-09

上一篇中我們已經把日誌寫入檔案中了,但是還有一些問題,可以看到我們日誌內容沒有記錄時間,也沒有日誌級別。錯誤日誌,沒有錯誤的檔案和行號,也不知道在哪個函式出錯的,這些我們也是需要加入進去的。

所以,我們的日誌列印的內容應該是這樣的:

2018-11-08 18:18:18.888 DEBUG [logDebug.go/logDebug.Debug:20]  this is a debug log
複製程式碼

我們現在file.go的Debug方法中將時間加入進去:

func (f *FileLog) Debug(format string, args ...interface{}) {
    now := time.Now()
    nowStr := now.Format("2006-01-02 15:04:05.999")// 這個數字格式是固定的不能改變的,但是-和:可以更換
    

    fmt.Fprintf(f.file, nowStr)
    fmt.Fprintf(f.file, format, args...)
    fmt.Fprintln(f.file)
}
複製程式碼

然後我們再講日誌級別加進去,我們之前定義了日誌級別常量,但是因為使用的iota,所以使用常量的時候,常量的值都是012,這種基本是沒人看的懂的,所以我們需要將日誌級別已字串的形式列印。我們在log_const.go中新增一個方法:

func LogLevelString(level int) (levelStr string) {
	switch level {
	case DebugLevel:
		levelStr = "DEBUG"
	case TraceLevel:
		levelStr = "TRACE"
	case InfoLevel:
		levelStr = "INFO"
	case WarnLevel:
		levelStr = "WARN"
	case ErrorLevel:
		levelStr = "ERROR"
	case FatalLevel:
		levelStr = "FATAL"
	}
	return
}
複製程式碼

可以看到我們制定制定的日誌格式裡面還有一個行號,檔名,所以我們還需要獲取錯誤日誌所在的行號的檔名,新建util.go

package hm_log

import(
    "runtime"
)

func GetLineInfo() (fileName, funcName string, lineNo int) {
   //pc 計數器, file 檔名, line 行號, ok 是否
   // runtime.Caller(4)這裡的4是一個層級關係,可以嘗試使用0 1 2 3來看看
   // 4 在其他專案中使用的時候,如果在log的test中,使用3
	pc, file, line, ok := runtime.Caller(4)
	if ok {
		fileName = file
		funcName = runtime.FuncForPC(pc).Name() // 獲取當前的方法
		lineNo = line
	}
	return
}
複製程式碼

繼續完善Debug方法:

func (f *FileLog) Debug(format string, args ...interface{}) {
    now := time.Now()
    nowStr := now.Format("2006-01-02 15:04:05.999")
    // 這個數字格式是固定的不能改變的,但是-和:可以更換
    levelStr := LogLevelString(DebugLevel)
    fileName, funcName, lineNo := GetLineInfo()
    //由於這裡返回的是全路徑的,但是我們不需要,所以我們只需要檔名以及相關的即可
    fileName = path.Base(fileName)
    funcName = path.Base(funcName)
    msg := fmt.Sprintf(format, args...)
    fmt.Fprintf(f.file, "%s %s [%s/%s:%d] %s\n", nowStr, levelStr, fileName, funcName, lineNo, msg)
}
複製程式碼

然後再執行go.test,檢視我們的日誌檔案,可以看到日誌內容和之前定義的格式相同了。然後就其他方法修改為Debug方法相同的程式碼即可。但是這樣太麻煩了,我們提取一個公共函式來回省點我們很多時間。

func (f *FileLog) writeLog(file *os.File, level int, format string, args... interface{} {
    now := time.Now()
    nowStr := now.Format("2006-01-02 15:04:05.999")
    // 這個數字格式是固定的不能改變的,但是-和:可以更換
    levelStr := LogLevelString(level)
    fileName, funcName, lineNo := GetLineInfo()
    //由於這裡返回的是全路徑的,但是我們不需要,所以我們只需要檔名以及相關的即可
    fileName = path.Base(fileName)
    funcName = path.Base(funcName)
    msg := fmt.Sprintf(format, args...)
    fmt.Fprintf(file, "%s %s [%s/%s:%d] %s\n", nowStr, levelStr, fileName, funcName, lineNo, msg)
}

func (f *FileLog) Debug(format string, args ...interface{}) {
    f.writeLog(f.file, DebugLevel, format, args...)
}

...

func (f *FileLog) Warn(format string, args ...interface{}) {
    f.writeLog(f.warnFile, WarnLevel, format, args...)
}

...

複製程式碼

基本上這個檔案日誌庫就寫的差不多了,也基本實現了檔案日誌庫的功能。下一篇我們繼續將console日誌庫也實現了。

相關文章