Go標(biāo)準(zhǔn)庫日志打印及同時輸出到控制臺與文件
打印
在使用go寫一些小程序時,我們沒必要引入額外的包,直接使用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
那么,有些場景下,我們希望能同時打印到日志文件中要怎么辦呢?
log包
標(biāo)準(zhǔn)庫提供了log組件,用法和fmt一致,有3種方式:
import “l(fā)og"
func main() {
log.Println("line1")
log.Print("line2")
log.Printf("line%d \n", 3)
}
和fmt的區(qū)別就是多了時間:
2021/08/25 17:23:47 line1
2021/08/25 17:23:47 line2
2021/08/25 17:23:47 line3
我們通過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 )
比如,我們只需要時間和文件名:
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)
}
此時,再次運(yùn)行,則會打印文件和行號:
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包使用非常簡單,默認(rèn)情況下,只會輸出到控制臺。
我們可以使用SetOutput改變輸出流,比如輸出到文件。
先來看一下函數(shù)原型,其接收一個io.Writer接口:
// SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) {
// ...
}
那么,我們就可以創(chuàng)建一個文件流設(shè)置一下就行了。
// 創(chuàng)建、追加、讀寫,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)
此時,在運(yùn)行,我們發(fā)現(xiàn)日志會輸出到文件,但是控制臺沒有任何東西輸出了。
如何同時輸出到控制臺和文件?
標(biāo)準(zhǔn)庫io包中,有一個MultiWriter,可以把文件流和控制臺標(biāo)準(zhǔn)輸出流整合到一個io.Writer上,其實(shí)現(xiàn)上就是一個數(shù)組,在執(zhí)行寫操作時,遍歷數(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}
}
// 重寫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)
}
此時,再運(yùn)行,則會同時輸出到控制臺和文件中。
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í)就是每次記錄文件的大小,超過了就重新寫一個文件。
通過Stat()函數(shù)拿到文件的一些信息
open, _:= os.Open("文件名")
stat, _, := open.Stat()
stat.Size()//拿到文件大小
日期切割:
拿到文件的名稱或者檢查下有沒有當(dāng)天的日志文件,沒有就創(chuàng)建新增。
總結(jié)
到此這篇關(guān)于Go標(biāo)準(zhǔn)庫日志打印及同時輸出到控制臺與文件的文章就介紹到這了,更多相關(guān)Go標(biāo)準(zhǔn)庫日志打印及輸出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang中sync.Mutex的實(shí)現(xiàn)方法
本文主要介紹了golang中sync.Mutex的實(shí)現(xiàn)方法,mutex?主要有兩個?method:?Lock()?和?Unlock(),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
GO語言實(shí)現(xiàn)TCP服務(wù)器的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何通過GO語言實(shí)現(xiàn)TCP服務(wù)器,文中的示例代碼講解詳細(xì),對我們深入了解Go語言有一定的幫助,需要的可以參考一下2023-03-03
Golang實(shí)現(xiàn)WebSocket服務(wù)的項(xiàng)目實(shí)踐
本文介紹如何使用Golang實(shí)現(xiàn)實(shí)時后端WebSocket服務(wù),首先使用Gin框架搭建http服務(wù),然后使用gorilla/websocket庫實(shí)現(xiàn)簡單后端WebSocket服務(wù),具有一定的參考價值,感興趣的可以了解一下2023-05-05
go語言單元測試基準(zhǔn)測試及表驅(qū)動測試示例詳解
這篇文章主要為大家介紹了go語言單元測試基準(zhǔn)測試及表驅(qū)動測試示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08

