欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語(yǔ)言結(jié)構(gòu)化日志slog的用法解析

 更新時(shí)間:2023年10月09日 10:23:41   作者:Go技術(shù)干貨  
go?1.21.0?版本引入了一個(gè)新的包?log/slog,該包提供了結(jié)構(gòu)化日志的功能,本文小編就來(lái)和大家聊聊log/slog?包的使用,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

前言

go 1.21.0 版本引入了一個(gè)新的包 log/slog,該包提供了結(jié)構(gòu)化日志的功能。相比于普通的日志,結(jié)構(gòu)化日志更受歡迎,因?yàn)樗哂懈叩目勺x性,并且在處理、分析和搜索等方面具有顯著的優(yōu)勢(shì)。

接下來(lái)讓我們深入探討 log/slog 包的使用,準(zhǔn)備好了嗎?準(zhǔn)備一杯你最喜歡的咖啡或茶,隨著本文一探究竟吧。

slog 包

slog 包提供了結(jié)構(gòu)化日志,其中的日志記錄包含了 消息、嚴(yán)重級(jí)別 以及 各種其他屬性,這些屬性以 鍵值對(duì) 的形式表示。

slog 包的主要功能如下所示:

  • 結(jié)構(gòu)化日志
  • 日志嚴(yán)重級(jí)別
  • 日志自定義處理
  • 日志分組

初體驗(yàn)

// github.com/chenmingyong0423/blog/blob/master/tutorial-code/slog/demo1/main.go
package main
import (
    "context"
    "log/slog"
)
func main() {
    slog.Info("slog msg", "greeting", "hello slog")
    // 攜帶 context 上下文
    slog.InfoContext(context.Background(), "slog msg with context", "greeting", "hello slog")
}

在上述示例中,我們直接通過(guò)調(diào)用包函數(shù) slog.Info 去輸出一條 info 等級(jí)的日志。在該函數(shù)內(nèi)部,會(huì)使用默認(rèn)提供的一個(gè) Logger 實(shí)例去執(zhí)行日志輸出的操作。除此之外,我們還能使用 slog.InfoContext 攜帶上下文進(jìn)行日志輸出。

除了 Info() 和 InfoContext() 函數(shù),還有 Debug()、Warn() 和 Error() 等輸出不同級(jí)別日志的函數(shù)。

運(yùn)行上面這段程序,會(huì)得到以下輸出:

2023/10/08 21:08:08 INFO slog msg greeting="hello slog"
2023/10/08 21:08:08 INFO slog msg with context greeting="hello slog"

Logger 的創(chuàng)建

默認(rèn)情況下,使用 slog 包函數(shù)輸出日志,僅僅是普通的文本格式,若想實(shí)現(xiàn) JSON 或者 key=value 的格式輸出,需要使用 slog.New() 函數(shù)創(chuàng)建 Logger 實(shí)例,使用該函數(shù)時(shí)需要傳入一個(gè) slog.Handler 的實(shí)現(xiàn),slog 包提供兩個(gè)實(shí)現(xiàn):TextHandler 和 JsonHandler

TextHandler 處理器

TextHandler 是一個(gè)日志記錄處理器,它將記錄以一系列鍵值對(duì)的形式寫(xiě)入到一個(gè) io.Writer 中。每個(gè)鍵值對(duì)都以 key=value 的形式表示,并且它們之間用空格分隔。

// github.com/chenmingyong0423/blog/blob/master/tutorial-code/slog/demo2/main.go
package main  
import (  
    "context"
    "log/slog"
    "os"
)  
func main() {  
    textLogger := slog.New(slog.NewTextHandler(os.Stdout, nil))  
    textLogger.InfoContext(context.Background(), "TextHandler", "姓名", "陳明勇")  
}

在上述示例中,我們通過(guò) slog.NewTextHandler 函數(shù)創(chuàng)建一個(gè)日志處理器,第一個(gè)參數(shù) os.Stdout 表示將日志輸出到控制臺(tái),然后將處理器作為參數(shù),傳遞到 slog.New 函數(shù)里創(chuàng)建一個(gè) Logger 實(shí)例,通過(guò)該實(shí)例可以執(zhí)行日志輸出的相關(guān)操作。

程序運(yùn)行結(jié)果如下所示:

time=2023-10-08T21:09:03.912+08:00 level=INFO msg=TextHandler 姓名=陳明勇

JsonHandler 處理器

JsonHandler 是一個(gè)日志處理器, 它將記錄以 json 的形式寫(xiě)入到一個(gè) io.Writer 中。

// github.com/chenmingyong0423/blog/blob/master/tutorial-code/slog/demo3/main.go
package main
import (
    "context"
    "log/slog"
    "os"
)
func main() {
    jsonLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
    jsonLogger.InfoContext(context.Background(), "JsonHandler", "姓名", "陳明勇")
}

在上述示例中,我們通過(guò) slog.NewJsonHandler 函數(shù)創(chuàng)建一個(gè) json 日志處理器,第一個(gè)參數(shù) os.Stdout 表示將日志輸出到控制臺(tái),然后將處理器作為參數(shù)傳遞到 slog.New 函數(shù)里創(chuàng)建一個(gè) Logger 實(shí)例,通過(guò)該實(shí)例可以執(zhí)行日志輸出的相關(guān)操作。

程序運(yùn)行結(jié)果如下所示:

{"time":"2023-10-08T21:09:22.614686104+08:00","level":"INFO","msg":"JsonHandler","姓名":"陳明勇"}

全局的 Logger 實(shí)例

slog 有一個(gè)默認(rèn)的 Logger 實(shí)例,如果我們想要獲取默認(rèn)的 Logger 實(shí)例,可以參考以下代碼:

logger := slog.Default()

在前面的示例中,我們一直使用創(chuàng)建的一個(gè) Logger 實(shí)例去輸出日志。然而,如果我們不想每次都需要通過(guò)特定的 Logger 實(shí)例來(lái)記錄日志,而是希望能夠全局操作,我們可以使用 slog.SetDefault 函數(shù)來(lái)設(shè)置并替換默認(rèn)的 Logger 實(shí)例。這種方式可以使日志記錄更加方便和靈活。

// github.com/chenmingyong0423/blog/blob/master/tutorial-code/slog/demo4/main.go
package main
import (
    "context"
    "log/slog"
    "os"
)
func main() {
    jsonLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
    slog.SetDefault(jsonLogger)
    slog.InfoContext(context.Background(), "JsonHandler", "姓名", "陳明勇") //{"time":"2023-10-08T21:11:22.41760604+08:00","level":"INFO","msg":"JsonHandler","姓名":"陳明勇"}
}

Group 分組

分組指的給日志記錄相關(guān)聯(lián)的屬性(鍵值對(duì))進(jìn)行分組,通過(guò)示例感受一下:

// github.com/chenmingyong0423/blog/blob/master/tutorial-code/slog/demo5/main.go
package main  
import (  
    "context"
    "log/slog"
    "os"
)  
func main() {  
    jsonLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil)).WithGroup("information")  
    jsonLogger.InfoContext(context.Background(), "json-log", slog.String("name", "chenmingyong"), slog.Int("phone", 1234567890))  
    textLogger := slog.New(slog.NewTextHandler(os.Stdout, nil)).WithGroup("information")  
    textLogger.InfoContext(context.Background(), "json-log", slog.String("name", "chenmingyong"), slog.Int("phone", 1234567890))  
}

運(yùn)行這段程序的結(jié)果如下所示:

{"time":"2023-10-08T21:12:23.124255258+08:00","level":"INFO","msg":"json-log","information":{"name":"chenmingyong","phone":1234567890}}
time=2023-10-08T21:12:23.127+08:00 level=INFO msg=json-log information.name=chenmingyong information.phone=1234567890

根據(jù)運(yùn)行結(jié)果可知,如果是對(duì)具有 JsonHandler 處理器的 Logger 實(shí)例進(jìn)行分組操作,輸出日志時(shí),組名 group name 將作為 keyvalue 則是所有鍵值對(duì)組成的一個(gè) json 對(duì)象。

如果是對(duì)具有 TextHandler 處理器的 Logger 實(shí)例進(jìn)行分組操作,組名 group name 將與所有鍵值對(duì)的鍵進(jìn)行組合,最終以 groupName.key=value 的形式展示。

LogAttrs 高效輸出日志

如果需要頻繁輸出日志,相比之前的例子,我們使用 slog.LogAttrs 函數(shù)結(jié)合 slog.Attr 類(lèi)型的去輸出日志會(huì)更 高效,因?yàn)闇p少了類(lèi)型解析的過(guò)程。

// github.com/chenmingyong0423/blog/blob/master/tutorial-code/slog/demo6/main.go
package main
import (
    "context"
    "log/slog"
    "os"
)
func main() {
    jsonLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
    jsonLogger.LogAttrs(context.Background(), slog.LevelInfo, "高效輸出日志", slog.String("姓名", "陳明勇"), slog.Int("聯(lián)系方式", 12345678901))
}

在上面的示例中,我們使用了 LogAttrs 方法去輸出一條日志,該方法的簽名為:func (l *Logger) LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr)。

結(jié)合方法簽名我們可以知道,第一個(gè)參數(shù)為 context.Context  上下文類(lèi)型,第二個(gè)參數(shù)為 Level 類(lèi)型,即 slog 包里面的日志嚴(yán)重級(jí)別類(lèi)型,第三個(gè)參數(shù)為 Attr 鍵值對(duì)類(lèi)型。

在使用其他方法如 Info 輸出日志時(shí),內(nèi)部會(huì)將鍵值對(duì)轉(zhuǎn)成 Attr 類(lèi)型,而使用 LogAttrs 方法,我們直接指定了 Attr 類(lèi)型,減少了轉(zhuǎn)換的過(guò)程,因此會(huì)更 高效

With 設(shè)置統(tǒng)一的屬性

如果每條日志都包含相同的一個(gè)鍵值對(duì),我們可以考慮設(shè)置一個(gè)統(tǒng)一的屬性。

// github.com/chenmingyong0423/blog/blob/master/tutorial-code/slog/demo7/main.go
package main  
import (  
    "context"
    "log/slog"
    "os"
)  
func main() {  
    jsonLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))  
    logger := jsonLogger.With("systemID", "s1")  
    logger.LogAttrs(context.Background(), slog.LevelInfo, "json-log", slog.String("k1", "v1"))  
    logger.LogAttrs(context.Background(), slog.LevelInfo, "json-log", slog.String("k2", "v2"))
}

我們可以使用 With 方法添加一個(gè)或多個(gè)固定屬性,并返回一個(gè)新的 Logger 實(shí)例,后面通過(guò)新實(shí)例輸出的日志都會(huì)包含 被添加的固定屬性,從而 避免 每條輸出的日志語(yǔ)句添加 相同 的鍵值對(duì)。

運(yùn)行這段程序的結(jié)果如下所示:

{"time":"2023-10-08T21:19:51.338328238+08:00","level":"INFO","msg":"json-log","systemID":"s1","k1":"v1"}
{"time":"2023-10-08T21:19:51.338604943+08:00","level":"INFO","msg":"json-log","systemID":"s1","k2":"v2"}

HandlerOptions 日志處理器的配置選項(xiàng)

細(xì)心的讀者也許能發(fā)現(xiàn),在前面的示例中,無(wú)論是 NewJSONHandler,還是 NewTextHandler,第二個(gè)參數(shù)都被設(shè)置為 nil,這是為了使用默認(rèn)的配置。

這個(gè)參數(shù)的類(lèi)型為 *HandlerOptions,通過(guò)它,我們可以配置是否顯示日志語(yǔ)句的源代碼位置信息、最低的日志輸出級(jí)別以及鍵值對(duì)屬性的重寫(xiě)操作。

// github.com/chenmingyong0423/blog/blob/master/tutorial-code/slog/demo8/main.go
package main  
import (
    "context"
    "log/slog"
    "os"
    "time"
)
func main() {  
    jsonLogger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{  
        AddSource: true,  
        Level: slog.LevelError,  
        ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {  
            if a.Key == slog.TimeKey {  
                if t, ok := a.Value.Any().(time.Time); ok {  
                    a.Value = slog.StringValue(t.Format(time.DateTime))  
                }  
            }  
            return a  
        },  
    }))  
    jsonLogger.InfoContext(context.Background(), "json-log", slog.String("姓名", "陳明勇")) 
    jsonLogger.ErrorContext(context.Background(), "json-log", slog.String("姓名", "陳明勇")) 
}

在上述示例中,我們創(chuàng)建了一個(gè)具有 JsonHanlder 處理器的 Logger 實(shí)例。在創(chuàng)建 JsonHanlder 時(shí),通過(guò) HandlerOptions 參數(shù)指定了以下配置:

  • 輸出日志語(yǔ)句的源代碼配置 Source 信息
  • 設(shè)置最低日志等級(jí)為 Error
  • 將 key 為 "time" 的屬性值的格式重寫(xiě)為 "2006-01-02 15:04:05" 的形式。

運(yùn)行這段程序得到的結(jié)果如下所示:

{"time":"2023-10-08 21:21:31","level":"ERROR","source":{"function":"main.main","file":"D:/goproject/src/gocode/play/main.go","line":24},"msg":"json-log"
,"姓名":"陳明勇"}

輸出結(jié)果與預(yù)期相同,INFO 等級(jí)的日志沒(méi)有被輸出、輸出 Source 信息以及重寫(xiě) key 為 "time" 的屬性值。

自定義 key-value 對(duì)中 value 的值

在前面的一個(gè)案例中,我們有通過(guò) HandlerOptions 配置來(lái)修改 key-value 對(duì)中 value 的值,除此之外,slog 包還支持使用另一種方式進(jìn)行修改。

// github.com/chenmingyong0423/blog/blob/master/tutorial-code/slog/demo9/main.go
package main
import (
    "context"
    "log/slog"
)
type Password string
func (Password) LogValue() slog.Value {
    return slog.StringValue("REDACTED_PASSWORD")
}
func main() {
    slog.LogAttrs(context.Background(), slog.LevelInfo, "敏感數(shù)據(jù)", slog.Any("password", Password("1234567890")))
}

在上述案例中,我們通過(guò)實(shí)現(xiàn) slog.LogValuer 接口(為某個(gè)類(lèi)型添加 LogValue() slog.Value 方法),將 key-value 對(duì)中 value 的值進(jìn)行重寫(xiě)。日志輸出時(shí),value 的值將會(huì)被 LogValue 方法的返回值所覆蓋。

運(yùn)行這段程序輸出的結(jié)果如下所示:

2023/10/08 21:37:11 INFO 敏感數(shù)據(jù) password=REDACTED_PASSWORD

輸出結(jié)果與預(yù)期結(jié)果相同,password 的 value 已經(jīng)被修改。

到此這篇關(guān)于Go語(yǔ)言結(jié)構(gòu)化日志slog的用法解析的文章就介紹到這了,更多相關(guān)go slog內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Go如何優(yōu)雅的對(duì)時(shí)間進(jìn)行格式化

    詳解Go如何優(yōu)雅的對(duì)時(shí)間進(jìn)行格式化

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中是如何優(yōu)雅的對(duì)時(shí)間進(jìn)行格式化的,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-06-06
  • golang 通過(guò)ssh代理連接mysql的操作

    golang 通過(guò)ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過(guò)ssh代理連接mysql的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • go gin中間件關(guān)于 c.next()、c.abort()和return的使用小結(jié)

    go gin中間件關(guān)于 c.next()、c.abort()和return的使用小結(jié)

    中間件的執(zhí)行順序是按照注冊(cè)順序執(zhí)行的,中間件可以通過(guò) c.abort() + retrurn 來(lái)中止當(dāng)前中間件,后續(xù)中間件和處理器的處理流程,?這篇文章給大家介紹go gin中間件關(guān)于 c.next()、c.abort()和return的使用小結(jié),感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • go語(yǔ)言map字典刪除操作的方法

    go語(yǔ)言map字典刪除操作的方法

    這篇文章主要介紹了go語(yǔ)言map字典刪除操作的方法,實(shí)例分析了map字典操作的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • Golang二進(jìn)制反匯編問(wèn)題

    Golang二進(jìn)制反匯編問(wèn)題

    這篇文章主要介紹了Golang二進(jìn)制反匯編問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • golang解析域名的步驟全紀(jì)錄

    golang解析域名的步驟全紀(jì)錄

    這篇文章主要給大家介紹了利用golang如何解析域名的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • Go內(nèi)存分配之結(jié)構(gòu)體優(yōu)化技巧

    Go內(nèi)存分配之結(jié)構(gòu)體優(yōu)化技巧

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言內(nèi)存分配之結(jié)構(gòu)體優(yōu)化技巧的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11
  • Go語(yǔ)言開(kāi)發(fā)技巧必知的小細(xì)節(jié)提升效率

    Go語(yǔ)言開(kāi)發(fā)技巧必知的小細(xì)節(jié)提升效率

    這篇文章主要介紹了Go語(yǔ)言開(kāi)發(fā)技巧必知的小細(xì)節(jié)提升效率,分享幾個(gè)你可能不知道的Go語(yǔ)言小細(xì)節(jié),希望能幫助大家更好地學(xué)習(xí)這門(mén)語(yǔ)言
    2024-01-01
  • 使用Go語(yǔ)言實(shí)現(xiàn)接口繼承的方式

    使用Go語(yǔ)言實(shí)現(xiàn)接口繼承的方式

    在Go語(yǔ)言中,接口(interface)是一種定義方法集合的類(lèi)型,它并不包含方法的具體實(shí)現(xiàn),只是規(guī)定實(shí)現(xiàn)該接口的類(lèi)型必須提供這些方法的實(shí)現(xiàn),下面我將通過(guò)示例代碼來(lái)詳細(xì)解釋如何使用Go語(yǔ)言實(shí)現(xiàn)接口組合,以及為什么這種方式可以看作是實(shí)現(xiàn)接口繼承的一種方式
    2024-05-05
  • Go語(yǔ)言中的網(wǎng)絡(luò)編程實(shí)現(xiàn)方式

    Go語(yǔ)言中的網(wǎng)絡(luò)編程實(shí)現(xiàn)方式

    Go語(yǔ)言作為一種簡(jiǎn)潔而強(qiáng)大的編程語(yǔ)言,在網(wǎng)絡(luò)編程方面表現(xiàn)尤為出色,其內(nèi)置的net包提供了豐富的網(wǎng)絡(luò)I/O基礎(chǔ)設(shè)施,支持TCP、UDP協(xié)議,以及DNS解析等功能,本文將結(jié)合實(shí)際案例,詳細(xì)介紹Go語(yǔ)言在網(wǎng)絡(luò)編程中的詳細(xì)用法,需要的朋友可以參考下
    2024-10-10

最新評(píng)論