Go標(biāo)準(zhǔn)庫(kù)日志打印及同時(shí)輸出到控制臺(tái)與文件
打印
在使用go寫(xiě)一些小程序時(shí),我們沒(méi)必要引入額外的包,直接使用fmt標(biāo)準(zhǔn)包打印即可:
import "fmt" func main() { fmt.Println("line1") fmt.Print("line2") fmt.Printf("line%d \n", 3) str1 := fmt.Sprintln("hello", 3) str2 := fmt.Sprint("hello ", 1, " 2") str3 := fmt.Sprintf("hello %d", 1) fmt.Print(str1, str2, str3) }
line1
line2line3
hello 3
hello 1 2hello 1
那么,有些場(chǎng)景下,我們希望能同時(shí)打印到日志文件中要怎么辦呢?
log包
標(biāo)準(zhǔn)庫(kù)提供了log組件,用法和fmt一致,有3種方式:
import “l(fā)og" func main() { log.Println("line1") log.Print("line2") log.Printf("line%d \n", 3) }
和fmt的區(qū)別就是多了時(shí)間:
2021/08/25 17:23:47 line1
2021/08/25 17:23:47 line2
2021/08/25 17:23:47 line3
我們通過(guò)SetFlag函數(shù),可以設(shè)置打印的格式:
// For example, flags Ldate | Ltime (or LstdFlags) produce, // 2009/01/23 01:23:23 message // while flags Ldate | Ltime | Lmicroseconds | Llongfile produce, // 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message 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 )
比如,我們只需要時(shí)間和文件名:
import “l(fā)og" func main() { log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) log.Println("line1") log.Print("line2") log.Printf("line%d \n", 3) }
此時(shí),再次運(yùn)行,則會(huì)打印文件和行號(hào):
2021/08/25 17:27:56 mod_unread_redis.go:32: line1
2021/08/25 17:27:56 mod_unread_redis.go:33: line2
2021/08/25 17:27:56 mod_unread_redis.go:34: line3
如何輸出日志到文件?
log包使用非常簡(jiǎn)單,默認(rèn)情況下,只會(huì)輸出到控制臺(tái)。
我們可以使用SetOutput改變輸出流,比如輸出到文件。
先來(lái)看一下函數(shù)原型,其接收一個(gè)io.Writer接口:
// SetOutput sets the output destination for the standard logger. func SetOutput(w io.Writer) { // ... }
那么,我們就可以創(chuàng)建一個(gè)文件流設(shè)置一下就行了。
// 創(chuàng)建、追加、讀寫(xiě),777,所有權(quán)限 f, err := os.OpenFile("log.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm) if err != nil { return } defer func() { f.Close() }() log.SetOutput(f)
此時(shí),在運(yùn)行,我們發(fā)現(xiàn)日志會(huì)輸出到文件,但是控制臺(tái)沒(méi)有任何東西輸出了。
如何同時(shí)輸出到控制臺(tái)和文件?
標(biāo)準(zhǔn)庫(kù)io包中,有一個(gè)MultiWriter,可以把文件流和控制臺(tái)標(biāo)準(zhǔn)輸出流整合到一個(gè)io.Writer上,其實(shí)現(xiàn)上就是一個(gè)數(shù)組,在執(zhí)行寫(xiě)操作時(shí),遍歷數(shù)組:
// MultiWriter creates a writer that duplicates its writes to all the // provided writers, similar to the Unix tee(1) command. // // Each write is written to each listed writer, one at a time. // If a listed writer returns an error, that overall write operation // stops and returns the error; it does not continue down the list. func MultiWriter(writers ...Writer) Writer { allWriters := make([]Writer, 0, len(writers)) for _, w := range writers { if mw, ok := w.(*multiWriter); ok { allWriters = append(allWriters, mw.writers...) } else { allWriters = append(allWriters, w) } } return &multiWriter{allWriters} } // 重寫(xiě)io.Writer的Write函數(shù)函數(shù),本質(zhì)上就是遍歷數(shù)組,比較巧妙 func (t *multiWriter) Write(p []byte) (n int, err error) { for _, w := range t.writers { n, err = w.Write(p) if err != nil { return } if n != len(p) { err = ErrShortWrite return } } return len(p), nil }
使用方式如下:
func main() { f, err := os.OpenFile("log.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm) if err != nil { return } defer func() { f.Close() }() // 組合一下即可,os.Stdout代表標(biāo)準(zhǔn)輸出流 multiWriter := io.MultiWriter(os.Stdout, f) log.SetOutput(multiWriter) log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) log.Println("line1") log.Print("line2") log.Printf("line%d \n", 3) }
此時(shí),再運(yùn)行,則會(huì)同時(shí)輸出到控制臺(tái)和文件中。
2021/08/25 17:38:02 mod_unread_redis.go:42: line1
2021/08/25 17:38:02 mod_unread_redis.go:43: line2
2021/08/25 17:38:02 mod_unread_redis.go:44: line3
附:日志切割(按文件大小切割、按日期切割)
其實(shí)就是每次記錄文件的大小,超過(guò)了就重新寫(xiě)一個(gè)文件。
通過(guò)Stat()函數(shù)拿到文件的一些信息
open, _:= os.Open("文件名") stat, _, := open.Stat() stat.Size()//拿到文件大小
日期切割:
拿到文件的名稱(chēng)或者檢查下有沒(méi)有當(dāng)天的日志文件,沒(méi)有就創(chuàng)建新增。
總結(jié)
到此這篇關(guān)于Go標(biāo)準(zhǔn)庫(kù)日志打印及同時(shí)輸出到控制臺(tái)與文件的文章就介紹到這了,更多相關(guān)Go標(biāo)準(zhǔn)庫(kù)日志打印及輸出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go類(lèi)型斷言提取測(cè)試接口值動(dòng)態(tài)類(lèi)型及靜態(tài)轉(zhuǎn)換確保類(lèi)型接口編譯安全
這篇文章主要為大家介紹了Go類(lèi)型斷言提取測(cè)試接口值動(dòng)態(tài)類(lèi)型及靜態(tài)轉(zhuǎn)換確保類(lèi)型實(shí)現(xiàn)特定接口的編譯時(shí)安全性詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10GO接收GET/POST參數(shù)及發(fā)送GET/POST請(qǐng)求的實(shí)例詳解
這篇文章主要介紹了GO接收GET/POST參數(shù)及發(fā)送GET/POST請(qǐng)求,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12golang使用bcrypt包對(duì)密碼進(jìn)行加密的方法實(shí)現(xiàn)
本文主要介紹了golang使用bcrypt包對(duì)密碼進(jìn)行加密的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07vscode中安裝Go插件和配置Go環(huán)境詳細(xì)步驟
要在VSCode中配置Go語(yǔ)言插件,首先需要確保你的電腦已經(jīng)安裝了Go環(huán)境和最新版本的VSCode,這篇文章主要給大家介紹了關(guān)于vscode中安裝Go插件和配置Go環(huán)境的相關(guān)資料,需要的朋友可以參考下2024-01-01Golang利用compress/flate包來(lái)壓縮和解壓數(shù)據(jù)
在處理需要高效存儲(chǔ)和快速傳輸?shù)臄?shù)據(jù)時(shí),數(shù)據(jù)壓縮成為了一項(xiàng)不可或缺的技術(shù),Go語(yǔ)言的compress/flate包為我們提供了對(duì)DEFLATE壓縮格式的原生支持,本文將深入探討compress/flate包的使用方法,揭示如何利用它來(lái)壓縮和解壓數(shù)據(jù),并提供實(shí)際的代碼示例,需要的朋友可以參考下2024-08-08go寫(xiě)文件后出現(xiàn)大量NUL字符問(wèn)題解決
本文主要介紹了go寫(xiě)文件后出現(xiàn)大量NUL字符問(wèn)題解決,由于每次寫(xiě)的時(shí)候設(shè)置的長(zhǎng)度都是64,在某次不足64時(shí),byte切片空余位置被填充為空字符,下面就來(lái)介紹一下如何解決2023-12-12