聊聊golang的log

本文主要研究一下golang的log

log

flags

const (
    Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
    Ltime                         // the time in the local time zone: 01:23:23
    Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
    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
    LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
    Lmsgprefix                    // move the "prefix" from the beginning of the line to before the message
    LstdFlags     = Ldate | Ltime // initial values for the standard logger
)

這幾個(gè)flags可以用來設(shè)置log的pattern

logger

type Logger struct {
    mu     sync.Mutex // ensures atomic writes; protects the following fields
    prefix string     // prefix on each line to identify the logger (but see Lmsgprefix)
    flag   int        // properties
    out    io.Writer  // destination for output
    buf    []byte     // for accumulating text to write
}

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

func (l *Logger) SetOutput(w io.Writer) {
    l.mu.Lock()
    defer l.mu.Unlock()
    l.out = w
}

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
}

func (l *Logger) Printf(format string, v ...interface{}) {
    l.Output(2, fmt.Sprintf(format, v...))
}

func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }

func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }

func (l *Logger) Fatal(v ...interface{}) {
    l.Output(2, fmt.Sprint(v...))
    os.Exit(1)
}

func (l *Logger) Fatalf(format string, v ...interface{}) {
    l.Output(2, fmt.Sprintf(format, v...))
    os.Exit(1)
}

func (l *Logger) Fatalln(v ...interface{}) {
    l.Output(2, fmt.Sprintln(v...))
    os.Exit(1)
}

func (l *Logger) Panic(v ...interface{}) {
    s := fmt.Sprint(v...)
    l.Output(2, s)
    panic(s)
}

func (l *Logger) Panicf(format string, v ...interface{}) {
    s := fmt.Sprintf(format, v...)
    l.Output(2, s)
    panic(s)
}

func (l *Logger) Panicln(v ...interface{}) {
    s := fmt.Sprintln(v...)
    l.Output(2, s)
    panic(s)
}

func (l *Logger) SetFlags(flag int) {
    l.mu.Lock()
    defer l.mu.Unlock()
    l.flag = flag
}

func (l *Logger) SetPrefix(prefix string) {
    l.mu.Lock()
    defer l.mu.Unlock()
    l.prefix = prefix
}

func (l *Logger) Writer() io.Writer {
    l.mu.Lock()
    defer l.mu.Unlock()
    return l.out
}
  • log包默認(rèn)提供的Print、Fatal、Panic方法使用的是std標(biāo)準(zhǔn)輸出流,它也提供了New方法可以自定義輸出
  • Fatal相關(guān)方法會(huì)執(zhí)行os.Exit(1),Panic相關(guān)方法會(huì)執(zhí)行panic,而panic執(zhí)行的是os.Exit(1)
  • f結(jié)尾的方法執(zhí)行的是fmt.Sprintf,可以使用format,ln結(jié)尾的方法執(zhí)行的是fmt.Sprintln,會(huì)增加換行

實(shí)例

package main

import (
    "encoding/json"
    "errors"
    "io"
    "log"
    "os"
    "time"
)

var logFile *os.File

func init() {
    log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
    log.SetPrefix("demo-app ")
    var err error
    logFile, err = os.OpenFile("/tmp/demo.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    if err != nil {
        log.Fatalln("Failed to open log file")
    }
    mw := io.MultiWriter(os.Stdout, logFile)
    log.SetOutput(mw)
}

type Cart struct {
    UserId int `json:"userId"`
    SkuId  int `json:"skuId"`
}

func closeLogFile() {
    if logFile != nil {
        log.Println("closing log file")
        logFile.Close()
    }
}

func main() {
    defer closeLogFile()
    // log.Panicln("print and then exit with status 2")
    // log.Fatalln("print and then exit with status 1")
    log.Println("hello")
    log.Printf("hello %s", "abc")

    //print with var
    str1 := "abc"
    str2 := "cdf"
    log.Println("print with auto space:", str1, "append", str2)

    //print error
    err1 := errors.New("demo error")
    log.Println("error:", err1)

    //print time
    now1 := time.Now()
    log.Println("print time:", now1)
    log.Println("print time with format:", now1.Format(time.RFC3339))

    //print struct
    cart := Cart{
        UserId: 1,
        SkuId:  123,
    }
    log.Println("print struct:", cart)

    //print json
    jsonByte, err := json.Marshal(cart)
    if err != nil {
        log.Fatalln("error:", err)
    }
    log.Println("print cart json:", string(jsonByte))

    //log to file
}
  • 這里給log設(shè)置了MultiWriter,可以同時(shí)往std和文件輸出

輸出實(shí)例

demo-app 2020/12/03 23:54:27.245848 main.go:42: hello
demo-app 2020/12/03 23:54:27.245974 main.go:43: hello abc
demo-app 2020/12/03 23:54:27.245981 main.go:48: print with auto space: abc append cdf
demo-app 2020/12/03 23:54:27.245996 main.go:52: error: demo error
demo-app 2020/12/03 23:54:27.246015 main.go:56: print time: 2020-12-03 23:54:27.246001 +0800 CST m=+0.000260928
demo-app 2020/12/03 23:54:27.246022 main.go:57: print time with format: 2020-12-03T23:54:27+08:00
demo-app 2020/12/03 23:54:27.246047 main.go:64: print struct: {1 123}
demo-app 2020/12/03 23:54:27.246109 main.go:71: print cart json: {"userId":1,"skuId":123}
demo-app 2020/12/03 23:54:27.246116 main.go:33: closing log file

小結(jié)

  • log包默認(rèn)提供的Print、Fatal、Panic方法使用的是std標(biāo)準(zhǔn)輸出流,它也提供了New方法可以自定義輸出
  • Fatal相關(guān)方法會(huì)執(zhí)行os.Exit(1),Panic相關(guān)方法會(huì)執(zhí)行panic,而panic執(zhí)行的是os.Exit(1)
  • f結(jié)尾的方法執(zhí)行的是fmt.Sprintf,可以使用format,ln結(jié)尾的方法執(zhí)行的是fmt.Sprintln,會(huì)增加換行

doc

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 14,259評(píng)論 0 38
  • 目錄 1.go 各種代碼運(yùn)行 2.go 在線編輯代碼運(yùn)行 3.通過 Gob 包序列化二進(jìn)制數(shù)據(jù) 4.使用 ...
    楊言錫閱讀 1,214評(píng)論 0 1
  • 一、log日志包 log支持并發(fā)操作。其結(jié)構(gòu)定義如下: log基本日志格式 (1)Golang's log模塊主要...
    學(xué)生黃哲閱讀 10,751評(píng)論 3 35
  • 一、錯(cuò)誤異常 《快學(xué) Go 語言》第 10 課 —— 錯(cuò)誤與異常Go 語言的異常處理語法絕對(duì)是獨(dú)樹一幟,在我見過的...
    合肥黑閱讀 1,172評(píng)論 0 3
  • 在我們開發(fā)程序后,如果有一些問題需要對(duì)程序進(jìn)行調(diào)試的時(shí)候,日志是必不可少的,這是我們分析程序問題常用的手段。 日志...
    豆瓣奶茶閱讀 18,480評(píng)論 0 22

友情鏈接更多精彩內(nèi)容