Golang學習筆記--log模組(一)
Golang的標準庫提供了log的機制,但是該模組的功能較為簡單(看似簡單,其實他有他的設計思路)。不過比手寫fmt. Printxxx還是強很多的。至少在輸出的位置做了執行緒安全的保護。其官方手冊見Golang log。這裡給出一個簡單使用的例子:
package main
import (
"log"
)
func main(){
log.Fatal("Come with fatal,exit with 1 \n")
}
編譯執行後,會看到程式列印了 Come with fatal,exit with 1
然後就退出了,如果用 echo $?
檢視退出碼,會發現是 “1”。
一般介面
Golang's log模組主要提供了3類介面。分別是 “Print 、Panic 、Fatal ”。當然是用前先包含log包。
import(
"log"
)
為了方便是用,Golang和Python一樣,在提供介面時,提供一個簡單的包級別的使用介面。不同於Python,其輸出預設定位到標準錯誤可以通過SetOutput
進行修改。
對每一類介面其提供了3中呼叫方式,分別是 "Xxxx 、 Xxxxln 、Xxxxf" 比如對於Print就有:
log.Print
log.Printf
log.Println
-
log.Print :表示其引數的呼叫方式和
fmt.Print
-
log.Printf : 表示其引數的呼叫方式和
fmt.Printf
是類似的,即可以用C系列的格式化標誌表示輸出物件的型別,具體型別表示 可以參考fmt.Printf的文件 -
log.Println: 表示其呼叫方式和
fmt.Println
類似,其和log.Print基本一致,僅僅是在輸出的時候多輸出一個換行
這裡是以 “Print”來具體說明的,對於“Panic”和“Fatal”也是一樣的。下面再以"Print"為例,看下呼叫方式:
package main import ( "log" ) func main(){ arr := []int {2,3} log.Print("Print array ",arr,"\n") log.Println("Println array",arr) log.Printf("Printf array with item [%d,%d]\n",arr[0],arr[1]) }
會得到如下結果:
2014/05/02 12:27:19 Print array [2 3]
2014/05/02 12:27:19 Println array [2 3]
2014/05/02 12:27:19 Printf array with item [2,3]
輸出中的日期和時間是預設的格式,如果直接呼叫簡單介面,其格式是固定的,可以通過 SetFlags
方法進行修改,同時這裡輸出內容的(傳個log.Print的內容)前面和時間的後面是空的,這也是預設的行為,我們可以通過新增字首來表示其是一條"Warnning" 或者是一條"Debug"日誌。通過使用 SetPrefix
可以設定該字首。
SetOutput,
SetFlags,
SetPrefix
這裡關係不大,先不解釋,留到後面介紹Logger型別中一併解釋。
看完了 log.PrintXxx
介面,我們再來看下 log.FatalXxx
介面,我們以 log.Fatal
為例介紹其功能。如最開始看到的例子, 在呼叫 log.Fatal
介面後,會先將日誌內容列印到標準輸出,接著呼叫系統的 os.exit(1)
介面,退出程式返回狀態為 “1”
比較複雜的是 log.PanicXxx
,看該函式的說明,其相當於再把日誌內容刷到標準錯誤後呼叫 panic
函式(不清楚Golang的defer-recover-panic機制可以去Golang教程第32節--panic 和 recover學習一下)。這裡舉個常用的例子:
package main
import (
"log"
"fmt"
)
func main(){
defer func(){
if e:= recover();e!= nil {
fmt.Println("Just comming recover")
fmt.Println("e from recover is :",e)
fmt.Println("After recover")
}
}()
arr := []int {2,3}
log.Panic("Print array ",arr,"\n")
}
結果為:
2014/05/03 13:52:42 Print array [2 3]
Just comming recover
e from recover is : Print array [2 3]
After recover
從結果我們可以看出,是先將日誌刷入標準輸出,然後通過defer裡面的recover進行捕獲panic的內容。
自定義Logger型別
理清了“Print 、Panic 、Fatal ”後我們就好介紹 log.Logger
型別了。該型別提供了一個New方法用來建立物件。
func New(out io.Writer, prefix string, flag int) *Logger
其初始化條件分別是日誌寫入的位置 out ,日誌的字首內容 prefix ,以及日誌的內容flag。可以通過上面介紹的 SetOutput,
SetFlags,
SetPrefix
依次對其進行設定。
-
輸出位置out,是一個io.Writer物件,該物件可以是一個檔案也可以是實現了該介面的物件。通常我們可以用這個來指定其輸出到哪個檔案
-
prefix 我們在前面已經看到,就是在日誌內容前面的內容。我們可以將其置為 "[Info]" 、 "[Warning]"等來幫助區分日誌 級別。
-
flags 較為迷惑,其實際上就是一個選項,可選的值有:
Ldate = 1 << iota // the date: 2009/01/23 形如 2009/01/23 的日期
Ltime // the time: 01:23:23 形如 01:23:23 的時間
Lmicroseconds // microsecond resolution: 01:23:23.123123. 形如01:23:23.123123 的時間
Llongfile // full file name and line number: /a/b/c/d.go:23 全路徑檔名和行號
Lshortfile // final file name element and line number: d.go:23. overrides Llongfile 檔名和行號
LstdFlags = Ldate | Ltime // 日期和時間
表示在日誌內容開頭,我們暫且稱之為日誌擡頭,打印出相關內容。對於上面的預設格式就是 LstdFlags 打印出日期和時間。
該方法還定義瞭如上一些同名方法。
func (l *Logger) Print(v ...interface{})
func (l *Logger) Printf(format string, v ...interface{})
func (l *Logger) Println(v ...interface{})
func (l *Logger) Fatal(v ...interface{})
func (l *Logger) Fatalf(format string, v ...interface{})
func (l *Logger) Fatalln(v ...interface{})
func (l *Logger) Panic(v ...interface{})
func (l *Logger) Panicf(format string, v ...interface{})
func (l *Logger) Panicln(v ...interface{})
func (l *Logger) Flags() int
func (l *Logger) Prefix() string
func (l *Logger) SetFlags(flag int)
func (l *Logger) SetPrefix(prefix string)
其中 “Print 、Panic 、Fatal ” 系列函式和之前介紹的一樣,Flags和Prefix分別可以獲得log.Logger當前的日誌擡頭和字首。 SetFlags ,SetPrefix 則可以用來設定日誌擡頭和字首。
使用例項
最後我看有log模組將debug日誌列印到檔案的例項。
package main
import (
"log"
"os"
)
func main(){
fileName := "xxx_debug.log"
logFile,err := os.Create(fileName)
defer logFile.Close()
if err != nil {
log.Fatalln("open file error !")
}
debugLog := log.New(logFile,"[Debug]",log.Llongfile)
debugLog.Println("A debug message here")
debugLog.SetPrefix("[Info]")
debugLog.Println("A Info Message here ")
debugLog.SetFlags(debugLog.Flags() | log.LstdFlags)
debugLog.Println("A different prefix")
}
執行後開啟日誌檔案我們可以看到相應的日誌內容