最近2018中文字幕在日韩欧美国产成人片_国产日韩精品一区二区在线_在线观看成年美女黄网色视频_国产精品一区三区五区_国产精彩刺激乱对白_看黄色黄大色黄片免费_人人超碰自拍cao_国产高清av在线_亚洲精品电影av_日韩美女尤物视频网站

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯網營銷解決方案
go語言日志輸出,go 日志打印

Golang將日志同時輸出到控制臺和文件

日常開發(fā)當中需要將golang的log包打印的日志同時輸出到控制臺和文件,應該如何解決這個問題?

創(chuàng)新互聯建站專注于劍河網站建設服務及定制,我們擁有豐富的企業(yè)做網站經驗。 熱誠為您提供劍河營銷型網站建設,劍河網站制作、劍河網頁設計、劍河網站官網定制、重慶小程序開發(fā)公司服務,打造劍河網絡公司原創(chuàng)品牌,更為您提供劍河網站排名全網營銷落地服務。

log包可以通過SetOutput()方法指定日志輸出的方式(Writer),但是只能指定一個輸出的方式(Writer)。我們利用io.MultiWriter()將多個Writer拼成一個Writer使用的特性,把log.Println()輸出的內容分流到控制臺和文件當中。

原文地址

golang logger輸出格式怎么修改

1.Logger結構

首先來看下類型Logger的定義:

type Logger struct {

mu sync.Mutex // ensures atomic writes; protects the following fields

prefix string // prefix to write at beginning of each line

flag int // properties

out io.Writer // destination for output

buf []byte // for accumulating text to write

}

主要有5個成員,其中3個我們比較熟悉,分別是表示Log前綴的 "prefix",表示Log頭標簽的 "flag" ,以及Log的輸出目的地out。 buf是一個字節(jié)數組,主要用來存放即將刷入out的內容,相當于一個臨時緩存,在對輸出內容進行序列化時作為存儲目的地。 mu是一個mutex主要用來作線程安全的實習,當有多個goroutine同時往一個目的刷內容的時候,通過mutex保證每次寫入是一條完整的信息。

2.std及整體結構

在前一篇文章中我們提到了log模塊提供了一套包級別的簡單接口,使用該接口可以直接將日志內容打印到標準錯誤。那么該過程是怎么實現的呢?其實就是通過一個內置的Logger類型的變量 "std" 來實現的。該變量使用:

var std = New(os.Stderr, "", LstdFlags)

進行初始化,默認輸出到系統(tǒng)的標準輸出 "os.Stderr" ,前綴為空,使用日期加時間作為Log抬頭。

當我們調用 log.Print的時候是怎么執(zhí)行的呢?我們看其代碼:

func Print(v ...interface{}) {

std.Output(2, fmt.Sprint(v...))

}

這里實際就是調用了Logger對象的 Output方法,將日志內容按照fmt包中約定的格式轉義后傳給Output。Output定義如下 :

func (l *Logger) Output(calldepth int, s string) error

其中s為日志沒有加前綴和Log抬頭的具體內容,xxxxx 。該函數執(zhí)行具體的將日志刷入到對應的位置。

3.核心函數的實現

Logger.Output是執(zhí)行具體的將日志刷入到對應位置的方法。

該方法首先根據需要獲得當前時間和調用該方法的文件及行號信息。然后調用formatHeader方法將Log的前綴和Log抬頭先格式化好 放入Logger.buf中,然后再將Log的內容存入到Logger.buf中,最后調用Logger.out.Write方法將完整的日志寫入到輸出目的地中。

由于寫入文件以及拼接buf的過程是線程非安全的,因此使用mutex保證每次寫入的原子性。

l.mu.Lock()

defer l.mu.Unlock()

將buf的拼接和文件的寫入放入這個后面,使得在多個goroutine使用同一個Logger對象是,不會弄亂buf,也不會雜糅的寫入。

該方法的第一個參數最終會傳遞給runtime.Caller的skip,指的是跳過的棧的深度。這里我記住給2就可以了。這樣就會得到我們調用log 是所處的位置。

在golang的注釋中說鎖住 runtime.Caller的過程比較重,這點我還是不很了解,只是從代碼中看到其在這里把鎖打開了。

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()

}

在formatHeader里面首先將前綴直接復制到Logger.buf中,然后根據flag選擇Log抬頭的內容,這里用到了一個log模塊實現的 itoa的方法,作用類似c的itoa,將一個整數轉換成一個字符串。只是其轉換后將結果直接追加到了buf的尾部。

縱觀整個實現,最值得學習的就是線程安全的部分。在什么位置合適做怎樣的同步操作。

4.對外接口的實現

在了解了核心格式化和輸出結構后,在看其封裝就非常簡單了,幾乎都是首先用Output進行日志的記錄,然后在必要的時候 做os.exit或者panic的操作,這里看下Fatal的實現。

func (l *Logger) Fatal(v ...interface{}) {

l.Output(2, fmt.Sprint(v...))

os.Exit(1)

}

// Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1).

func (l *Logger) Fatalf(format string, v ...interface{}) {

l.Output(2, fmt.Sprintf(format, v...))

os.Exit(1)

}

// Fatalln is equivalent to l.Println() followed by a call to os.Exit(1).

func (l *Logger) Fatalln(v ...interface{}) {

l.Output(2, fmt.Sprintln(v...))

os.Exit(1)

}

這里也驗證了我們之前做的Panic的結果,先做輸出日志操作。再進行panic。

Go語言基礎語法(一)

本文介紹一些Go語言的基礎語法。

先來看一個簡單的go語言代碼:

go語言的注釋方法:

代碼執(zhí)行結果:

下面來進一步介紹go的基礎語法。

go語言中格式化輸出可以使用 fmt 和 log 這兩個標準庫,

常用方法:

示例代碼:

執(zhí)行結果:

更多格式化方法可以訪問中的fmt包。

log包實現了簡單的日志服務,也提供了一些格式化輸出的方法。

執(zhí)行結果:

下面來介紹一下go的數據類型

下表列出了go語言的數據類型:

int、float、bool、string、數組和struct屬于值類型,這些類型的變量直接指向存在內存中的值;slice、map、chan、pointer等是引用類型,存儲的是一個地址,這個地址存儲最終的值。

常量是在程序編譯時就確定下來的值,程序運行時無法改變。

執(zhí)行結果:

執(zhí)行結果:

Go 語言的運算符主要包括算術運算符、關系運算符、邏輯運算符、位運算符、賦值運算符以及指針相關運算符。

算術運算符:

關系運算符:

邏輯運算符:

位運算符:

賦值運算符:

指針相關運算符:

下面介紹一下go語言中的if語句和switch語句。另外還有一種控制語句叫select語句,通常與通道聯用,這里不做介紹。

if語法格式如下:

if ... else :

else if:

示例代碼:

語法格式:

另外,添加 fallthrough 會強制執(zhí)行后面的 case 語句,不管下一條case語句是否為true。

示例代碼:

執(zhí)行結果:

下面介紹幾種循環(huán)語句:

執(zhí)行結果:

執(zhí)行結果:

也可以通過標記退出循環(huán):

--THE END--


標題名稱:go語言日志輸出,go 日志打印
文章分享:http://fisionsoft.com.cn/article/dsipeic.html