一文搞懂 Go 語言標準庫,log

Go 語言的標準庫中提供了一個簡單的 log 日誌包,它不僅提供了很多函數,還定義了一個包含很多方法的類型 Logger。Logger 會打印每條日誌信息的日期、時間,默認輸出到標準錯誤。Fatal 系列函數會在寫入日誌信息後調用 os.Exit(1)。Panic 系列函數會在寫入日誌信息後 panic。下面詳細介紹下標準庫 log 的基本使用。

函數

Golang 的 log 包主要提供了以下幾個具備輸出功能的函數:

func Fatal(v ...interface{})
func Fatalf(format string, v ...interface{})
func Fatalln(v ...interface{})
func Panic(v ...interface{})
func Panicf(format string, v ...interface{})
func Panicln(v ...interface{})
func Print(v ...interface{})
func Printf(format string, v ...interface{})
func Println(v ...interface{})

示例

//l.Output(2, fmt.Sprintf(format, v...))
 v := "普通"
 log.Printf("一條%s日誌。\n", v)
 
 //l.Output(2, fmt.Sprintln(v...))
 log.Println("一條一條普通日誌。")
 
 //l.Output(2, fmt.Sprintln(v...))
 //os.Exit(1)
 log.Fatalln("一條觸發fatal的日誌。")
 
 //s := fmt.Sprintln(v...)
 //l.Output(2, s)
 //panic(s)
 log.Panicln("一條觸發panic的日誌。")

運行結果

021/12/22 15:01:01 一條普通日誌。
2021/12/22 15:01:01 一條普通日誌。
2021/12/22 15:01:01 一條觸發fatal的日誌。

以上這些函數的使用方法和 fmt 包完全相同,具體 fmt 包的介紹上一篇已經介紹過了,>> 傳送門。通過查看源碼可以發現:

函數 Output() 的源碼:

func (l *Logger) Output(calldepth int, s string) error {
 now := time.Now() // get this early.
 var file string
 var line int
 l.mu.Lock()
 defer l.mu.Unlock()
 if l.flag&(Lshortfile|Llongfile) != 0 {
  // Release lock while getting caller info - it's expensive.
  l.mu.Unlock()
  var ok bool
  _, file, line, ok = runtime.Caller(calldepth)
  if !ok {
   file = "???"
   line = 0
  }
  l.mu.Lock()
 }
 l.buf = l.buf[:0]
 l.formatHeader(&l.buf, now, file, line)
 l.buf = append(l.buf, s...)
 if len(s) == 0 || s[len(s)-1] != '\n' {
  l.buf = append(l.buf, '\n')
 }
 _, err := l.out.Write(l.buf)
 return err
}

可以發現:

  1. 函數使用互斥鎖來保證多個 goroutine 寫日誌的安全,且在調用 runtime.Caller() 之前,先釋放了互斥鎖,等獲取到信息後再加鎖來保證安全。

  2. 使用 formatHeader() 函數來格式化日誌的信息,然後保存到 buf 中,然後再把日誌信息追加到 buf 的末尾,然後再通過判斷,查看日誌是否爲空或末尾不是 \n,如果是就再把 \n 追加到 buf 的末尾,最後將日誌信息輸出。

配置 logger

默認情況下的 logger 只提供了日誌的時間信息,log 標準庫還提供了一些定製的方法。可以得到更多信息,例如記錄該日誌的文件名和行號等。

Flags

log 標準庫中的 Flags 函數會返回標準 logger 的輸出配置,而 SetFlags 函數用來設置標準 logger 的輸出配置。

func Flags() int
func SetFlags(flag int)

log 標準庫提供瞭如下的 flag 選項,它們是一系列定義好的常量。

const (
    // 控制輸出日誌信息的細節,不能控制輸出的順序和格式。
    // 輸出的日誌在每一項後會有一個冒號分隔:例如2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
    Ldate         = 1 << iota     // 日期:2009/01/23
    Ltime                         // 時間:01:23:23
    Lmicroseconds                 // 微秒級別的時間:01:23:23.123123(用於增強Ltime位)
    Llongfile                     // 文件全路徑名+行號: /a/b/c/d.go:23
    Lshortfile                    // 文件名+行號:d.go:23(會覆蓋掉Llongfile)
    LUTC                          // 使用UTC時間
    LstdFlags     = Ldate | Ltime // 標準logger的初始值
)

示例

func main() {
    log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
    log.Println("一條很普通的日誌。")
}

//輸出
//2021/12/22 15:09:08.290930 /box/main.go:7: 一條很普通的日誌。

日誌前綴 Prefix

Prefix 函數查看標準 logger 的輸出前綴,SetPrefix 函數用來設置輸出前綴。

func Prefix() string
func SetPrefix(prefix string)

示例

func main() {
 log.SetPrefix("[info]")
 log.Println("一條普通的日誌")
 fmt.Println(log.Prefix())
}

//輸出
//[info]2021/12/22 15:15:28 一條普通的日誌
//[info]

輸出位置 Output

SetOutput 函數用來設置標準 logger 的輸出目的地,默認是標準錯誤輸出。

func SetOutput(w io.Writer)

示例

func main() {
 logFile, err := os.OpenFile("./test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
 if err != nil {
  fmt.Println("open log file failed, err:", err)
  return
 }
 log.SetOutput(logFile)
 log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate)
 log.SetPrefix("[info]")
 log.Println("一條很普通的日誌")
}

自定義 logger

lo g 標準庫中還提供了一個創建新 logger 對象的構造函數 New,支持我們創建自己的 logger。

func New(out io.Writer, prefix string, flag int) *Logger {
 return &Logger{out: out, prefix: prefix, flag: flag}
}

示例

func main() {
 logger := log.New(os.Stdout, "<info>", log.Lshortfile|log.Lmicroseconds|log.Ldate)
 logger.Println("自定義的 logger 日誌")
}

//輸出
//<info>2021/12/22 23:30:16.283401 main.go:10: 自定義的 logger 日誌

由於 G o 內置的 log 庫功能有限,在實際的項目中可以根據自己的需要選擇使用第三方的日誌庫,如 logrus、zap 等。

參考資料:

https://www.jianshu.com/p/66c75589d6b5

https://www.cnblogs.com/flippedxyy/p/15558771.html

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/B5l1luPkipR0x6pLaIUoFg