最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言編程實(shí)現(xiàn)支持六種級(jí)別的日志庫?

 更新時(shí)間:2022年07月04日 09:28:37   作者:波斯馬  
這篇文章主要為大家介紹了使用Golang編寫一個(gè)支持六種級(jí)別的日志庫示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

Golang標(biāo)準(zhǔn)日志庫提供的日志輸出方法有Print、Fatal、Panic等,沒有常見的Debug、Info、Error等日志級(jí)別,用起來不太順手。這篇文章就來手?jǐn)]一個(gè)自己的日志庫,可以記錄不同級(jí)別的日志。

其實(shí)對(duì)于追求簡(jiǎn)單來說,Golang標(biāo)準(zhǔn)日志庫的三個(gè)輸出方法也夠用了,理解起來也很容易:

  • Print用于記錄一個(gè)普通的程序日志,開發(fā)者想記點(diǎn)什么都可以。
  • Fatal用于記錄一個(gè)導(dǎo)致程序崩潰的日志,并會(huì)退出程序。
  • Panic用于記錄一個(gè)異常日志,并觸發(fā)panic。

不過對(duì)于用慣了Debug、Info、Error的人來說,還是有點(diǎn)不習(xí)慣;對(duì)于想更細(xì)致的區(qū)分日志級(jí)別的需求,標(biāo)準(zhǔn)日志庫還提供了一個(gè)通用的Output方法,開發(fā)者在要輸出的字符串中加入級(jí)別也是可以的,但總是有點(diǎn)別扭,不夠直接。

目前市面上也已經(jīng)有很多優(yōu)秀的三方日志庫,比如uber開源的zap,常見的還有zerolog、logrus等。不過我這里還是想自己手?jǐn)]一個(gè),因?yàn)榇蠖鄶?shù)開源產(chǎn)品都不會(huì)完全貼合自己的需求,有很多自己用不上的功能,這會(huì)增加系統(tǒng)的復(fù)雜性,有沒有隱藏的坑也很難說,當(dāng)然自己入坑的可能性也很大;再者看了官方日志庫的實(shí)現(xiàn)之后,感覺可以簡(jiǎn)單封裝下即可實(shí)現(xiàn)自己想要的功能,能夠hold住。

初始需求

我這里的初始需求是:

  • 將日志寫入磁盤文件,每個(gè)月一個(gè)文件夾,每個(gè)小時(shí)一個(gè)文件。
  • 支持常見日志級(jí)別:Trace、Debug、Info、Warn、Error、Fatal,并且程序能夠設(shè)置日志級(jí)別。

我給這個(gè)日志庫取名為ylog,預(yù)期的使用方法如下:

ylog.SetLevel(LevelInfo)
ylog.Debug("I am a debug log.")
ylog.Info("I am a Info log.")

技術(shù)實(shí)現(xiàn)

類型定義

需要定義一個(gè)結(jié)構(gòu)體,保存日志級(jí)別、要寫入的文件等信息。

type FileLogger struct {
	lastHour int64
	file     *os.File
	Level    LogLevel
	mu       sync.Mutex
	iLogger  *log.Logger
	Path     string
}

來看一下這幾個(gè)參數(shù):

lastHour 用來記錄創(chuàng)建日志文件時(shí)的小時(shí)數(shù),如果小時(shí)變了,就要?jiǎng)?chuàng)建新的日志文件。

file 當(dāng)前使用的日志文件。

Level 當(dāng)前使用的日志級(jí)別。

mu 因?yàn)榭赡茉诓煌膅o routine中寫日志,需要一個(gè)互斥體保證日志文件不會(huì)重復(fù)創(chuàng)建。

iLogger 標(biāo)準(zhǔn)日志庫實(shí)例,因?yàn)檫@里是封裝了標(biāo)準(zhǔn)日志庫。

Path 日志輸出的最上層目錄,比如程序根目錄下的logs目錄,這里就保存一個(gè)字符串:logs。

日志級(jí)別

先把日志級(jí)別定義出來,這里日志級(jí)別其實(shí)是int類型,從0到5,級(jí)別不斷升高。

如果設(shè)置為ToInfo,則Info級(jí)別及比Info級(jí)別高的日志都能輸出。

type LogLevel int
const (
	LevelTrace LogLevel = iota
	LevelDebug
	LevelInfo
	LevelWarn
	LevelError
	LevelFatal
)

上文提到可以在Output方法的參數(shù)中加入日志級(jí)別,這里就通過封裝Output方法來實(shí)現(xiàn)不同級(jí)別的日志記錄方法。這里貼出其中一個(gè)方法,封裝的方式都一樣,就不全都貼出來了:

func (l *FileLogger) CanInfo() bool {
	return l.Level <= LevelInfo 
}
func (l *FileLogger) Info(v ...any) {
	if l.CanInfo() {
		l.ensureFile()
		v = append([]any{"Info "}, v...)
		l.iLogger.Output(2, fmt.Sprintln(v...))
	}
}

輸出日志前做了三件事:

  • 判斷日志級(jí)別,如果設(shè)置的日志級(jí)別小于等于當(dāng)前輸出級(jí)別,則可以輸出。
  • 確保日志文件已經(jīng)創(chuàng)建好,后邊會(huì)講如何確保。
  • 將日志級(jí)別前插到日志字符串中。

然后調(diào)用標(biāo)準(zhǔn)庫的Output函數(shù)輸出日志,這里第一個(gè)參數(shù)是為了獲取到當(dāng)前正在寫日志的程序文件名,傳入的是在程序調(diào)用棧中進(jìn)行查找的深度值,這里用2就正好。

寫到文件

標(biāo)準(zhǔn)庫的log是支持輸出到多種目標(biāo)的,只要實(shí)現(xiàn)了io.Write接口:

type Writer interface {
	Write(p []byte) (n int, err error)
}

因?yàn)槲募?duì)象也實(shí)現(xiàn)了這個(gè)接口,所以這里可以創(chuàng)建os.File的實(shí)例,并把它設(shè)置到內(nèi)嵌的標(biāo)準(zhǔn)日志庫實(shí)例,也就是設(shè)置到前邊創(chuàng)建的FileLogger中的iLogger中。這個(gè)操作在ensureFile方法中,看一下這個(gè)文件的實(shí)現(xiàn):

func (l *FileLogger) ensureFile() (err error) {
	currentTime := time.Now()
	if l.file == nil {
		l.mu.Lock()
		defer l.mu.Unlock()
		if l.file == nil {
			l.file, err = createFile(&l.Path, &currentTime)
			l.iLogger.SetOutput(l.file)
			l.iLogger.SetFlags(log.Lshortfile | log.Ldate | log.Ltime | log.Lmicroseconds)
			l.lastHour = getTimeHour(&currentTime)
		}
		return
	}
	currentHour := getTimeHour(&currentTime)
	if l.lastHour != currentHour {
		l.mu.Lock()
		defer l.mu.Unlock()
		if l.lastHour != currentHour {
			_ = l.file.Close()
			l.file, err = createFile(&l.Path, &currentTime)
			l.iLogger.SetOutput(l.file)
			l.iLogger.SetFlags(log.Llongfile | log.Ldate | log.Ltime)
			l.lastHour = getTimeHour(&currentTime)
		}
	}
	return
}

這里稍微有點(diǎn)復(fù)雜,基本邏輯是:如果文件實(shí)例不存在,則創(chuàng)建;如果需要?jiǎng)?chuàng)建新的文件,則先關(guān)閉舊的文件再創(chuàng)建新的文件。

更改文件實(shí)例時(shí)需要加鎖,否則可能多次操作,出現(xiàn)預(yù)期之外的情況。

設(shè)置輸出到文件后,標(biāo)準(zhǔn)log庫的Output方法就會(huì)將日志輸出到這個(gè)文件了。

默認(rèn)實(shí)現(xiàn)

經(jīng)過上邊一系列操作,這個(gè)FileLogger就可以使用了:

var logger = NewFileLogger(LevelInfo, "logs")
logger.Info("This is a info.")

不過和最初設(shè)想的用法有點(diǎn)差別:ylog.Info("xxxx")

這需要在ylog包中再定義一個(gè)名為Info的公開函數(shù),可以在這個(gè)公開函數(shù)中調(diào)用一個(gè)默認(rèn)創(chuàng)建的FileLogger實(shí)例,代碼是這樣的:

var stdPath = "logs"
var std = NewFileLogger(LevelInfo, stdPath)
func Trace(v ...any) {
	if std.CanTrace() {
		std.ensureFile()
		v = append([]any{"Trace"}, v...)
		std.iLogger.Output(2, fmt.Sprintln(v...))
	}
}

注意這里沒有調(diào)用std的Trace方法,這是因?yàn)镺utput中的第一個(gè)參數(shù),如果嵌套調(diào)用std.Trace,則多了一層,這個(gè)參數(shù)就得設(shè)置為3,但是自己創(chuàng)建實(shí)例調(diào)用Trace時(shí)這個(gè)參數(shù)需要為2,這就產(chǎn)生沖突了。

經(jīng)過以上這些操作,就可以實(shí)現(xiàn)預(yù)期的日志操作了:

ylog.SetLevel(LevelInfo)
ylog.Debug("I am a debug log.")
ylog.Info("I am a Info log.")

完整的程序代碼:https://github.com/bosima/ylog/tree/v1.0.1

下篇文章將繼續(xù)改造這個(gè)日志庫,支持輸出Json格式的日志,以及輸出日志到Kafka,更多關(guān)于Golang日志庫的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go編譯so庫讓python引用編譯后沒有.h文件的問題

    go編譯so庫讓python引用編譯后沒有.h文件的問題

    有時(shí)python需要引用go的一些開源庫,這時(shí)就需要go編譯成python可調(diào)用的庫,本文給大家介紹了go編譯so庫讓python引用,編譯后沒有.h文件的問題,需要的朋友可以參考下
    2024-02-02
  • golang gin框架獲取參數(shù)的操作

    golang gin框架獲取參數(shù)的操作

    這篇文章主要介紹了golang gin框架獲取參數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言中的通道channel詳情

    Go語言中的通道channel詳情

    這篇文章主要介紹了Go語言中的通道channel,在Go語言中管道類似于一個(gè)數(shù)據(jù)流,每次放入或者取出一部分?jǐn)?shù)據(jù),數(shù)據(jù)取出后原通道內(nèi)的數(shù)據(jù)就刪除掉,在linux操作系統(tǒng)中管道會(huì)將函數(shù)的返回結(jié)果作為下一個(gè)函數(shù)的參數(shù),下文詳細(xì)內(nèi)容需要的朋友可以參考下
    2022-02-02
  • go中空接口的具體使用

    go中空接口的具體使用

    空接口是一種特殊的接口類型,它不包含任何方法,本文主要介紹了go中空接口的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-04-04
  • go zero微服務(wù)高在請(qǐng)求量下如何優(yōu)化

    go zero微服務(wù)高在請(qǐng)求量下如何優(yōu)化

    這篇文章主要為大家介紹了go zero微服務(wù)高在請(qǐng)求量下的優(yōu)化處理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Go語言中io.Reader和io.Writer的詳解與實(shí)現(xiàn)

    Go語言中io.Reader和io.Writer的詳解與實(shí)現(xiàn)

    在Go語言的實(shí)際編程中,幾乎所有的數(shù)據(jù)結(jié)構(gòu)都圍繞接口展開,接口是Go語言中所有數(shù)據(jù)結(jié)構(gòu)的核心。在使用Go語言的過程中,無論你是實(shí)現(xiàn)web應(yīng)用程序,還是控制臺(tái)輸入輸出,又或者是網(wǎng)絡(luò)操作,不可避免的會(huì)遇到IO操作,使用到io.Reader和io.Writer接口。下面來詳細(xì)看看。
    2016-09-09
  • Golang unsafe包中的類型和函數(shù)詳解

    Golang unsafe包中的類型和函數(shù)詳解

    Golang中的unsafe包用于在運(yùn)行時(shí)進(jìn)行低級(jí)別的操作,這些操作通常是不安全的,因?yàn)榭梢源蚱艷olang的類型安全性和內(nèi)存安全性,使用 unsafe包的程序可能會(huì)影響可移植性和兼容性,接下來看下unsafe包中的類型和函數(shù)
    2023-08-08
  • Go sync WaitGroup使用深入理解

    Go sync WaitGroup使用深入理解

    這篇文章主要為大家介紹了Go sync WaitGroup使用深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Go實(shí)現(xiàn)凱撒密碼加密解密

    Go實(shí)現(xiàn)凱撒密碼加密解密

    這篇文章主要為大家介紹了Go實(shí)現(xiàn)凱撒密碼加密解密示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 手把手帶你走進(jìn)Go語言之條件表達(dá)式

    手把手帶你走進(jìn)Go語言之條件表達(dá)式

    條件表達(dá)式由條件運(yùn)算符構(gòu)成,并常用條件表達(dá)式構(gòu)成一個(gè)賦值語句,本文給大家介紹了在Go語言中條件表達(dá)式的具體用法,講述的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值
    2021-09-09

最新評(píng)論

卢湾区| 长泰县| 宜良县| 台中市| 洪雅县| 错那县| 哈尔滨市| 凭祥市| 三门峡市| 壤塘县| 海南省| 彰武县| 宜宾市| 讷河市| 普兰县| 湖州市| 吐鲁番市| 华亭县| 米脂县| 班戈县| 香港 | 凤翔县| 阿拉尔市| 商水县| 化隆| 远安县| 于都县| 阿勒泰市| 乌苏市| 晴隆县| 托克逊县| 登封市| 炉霍县| 民勤县| 龙井市| 盐源县| 呼图壁县| 杭锦后旗| 田林县| 三穗县| 陆良县|