go第三方日誌系統-seelog-Basic sections

https://github.com/cihub/seeloggit

文檔學習:https://github.com/cihub/seelog/wikigithub

1.安裝:golang

go get github.com/cihub/seelog

 

2.快速啓動json

Seelog的設計很是方便。它的默認配置和包級別的日誌記錄器是現成的,因此開始你只須要兩行代碼:後端

package main

import log "github.com/cihub/seelog"

func main() {
    defer log.Flush()
    log.Info("Hello from Seelog!")
}

Info只是Seelog支持的日誌級別之一。你還可使用Trace, Debug, Info, Warn, Error, Critical級別。安全

運行返回:服務器

bogon:~ user$ go run testGo.go 
1551577771885754000 [Info] Hello from Seelog!

 

基本配置網絡

這是seelog config的一個例子,它使用默認格式選項、約束等將輸出重定向到控制檯,命名爲seelog.xml。併發

<seelog>
    <outputs>
        <console />
    </outputs>
</seelog>

大多數wiki部分介紹使用configs進行的Seelog調優。app

 

下載配置
在Seelog包中有幾個函數能夠幫你加載configs。

logger, err := log.LoggerFromConfigAsFile("seelog.xml")
    
if err != nil {
    return err
}
    
log.ReplaceLogger(logger)

這裏還有'LoggerFromConfigAsBytes',和'LoggerFromConfigAsString'兩種類型的下載函數

你能夠在任什麼時候候運行log.ReplaceLogger。配置轉換可見Changing config on the fly

 

defer塊和刷新

在許多狀況下,沒法在主goroutine中處理生成的日誌信息。

在這些狀況下,咱們建議異步日誌記錄器在非阻塞模式下依次從隊列中接收緩衝消息。在這種狀況下,確保在應用程序遭受緊急崩潰時不會丟失日誌數據是相當重要的。咱們在main函數的defer中使用log. Flush()函數解決了這個問題,它保證日誌消息隊列中剩下的全部消息都將正常地獨立於應用程序無論panic是否進行處理。

注意:在使用Seelog構造以前,defer塊必須放在可執行文件的main函數中。在編寫包時,不要擔憂延遲刷新,詳情可見Writing libraries with Seelog

 

ReplaceLogger 和 UseLogger

這兩個函數都更改了負責當前日誌記錄器的包級別變量。此變量用於包級函數「Trace」、「Debug」等。可是,請注意區別。

前者正確地關閉前一個日誌記錄器(使用刷新日誌數據),而後用一個新的日誌記錄器替換它。當你更改日誌配置時,這是最推薦的方法。

後者只刷新前一個日誌記錄器(不關閉它),而後用一個新的日誌記錄器替換它。當你更改日誌記錄器而且對關閉舊日誌記錄器不聞不問時,應該使用此方法。

 

演示配置的全部功能

有一個演示配置,它在一個地方演示了大多數功能,可見下面的 9.Example config

你能夠在深刻研究全部特性以前檢查它。

 

3.日誌級別

這一節展現了咱們對Seelog級別層次、它們的含義和使用範圍的見解。當咱們根據本身的概念對Seelog代碼進行調優時,建議遵循如下規則。

支持的日誌級別有:

  • Trace -查找關於全部基本構造的狀態的廣泛信息。使用「Trace」進行深度調試,查找函數的問題部分,檢查臨時變量的值,等等。
  • Debug——用於詳細的系統行爲報告和診斷消息,以幫助定位開發過程當中的問題。
  • Info-關於應用程序工做的通常信息。在代碼中使用「Info」級別,這樣即便在生產環境中也能夠啓用它。因此這是一個「生產日誌級別」。
  • Warn-用於指示以安全方式自動處理的小錯誤、奇怪狀況和故障。
  • Error-嚴重故障影響應用程序的工做流程,但不是致命的(不強迫應用程序關閉)。
  • Critical——在應用程序死亡以前生成最後的消息。注意:Critical消息強制當即刷新,由於Critical狀況下,若是應用程序崩潰,避免日誌消息丟失是很重要的。
  • Off—用於關閉日誌記錄的特殊日誌級別

配置文件的日誌級別標識符

  • "trace"——低級別
  • "debug"
  • "info"
  • "warn"
  • "error"
  • "critical"——高級別

日誌消息示例

  • Trace
    • "Entered parse function validation block"
    • "Validation: entered second 'if'"
    • "Dictionary 'Dict' is empty. Using default value"
  • Debug
    • "Web page requested: http://somesite.com Params='...'"
    • "Response generated. Response size: 10000. Sending."
    • "New file received. Type:PNG Size:20000"
  • Info
    • "Web server restarted"
    • "Hourly statistics: Requested pages: 12345 Errors: 123 ..."
    • "Service paused. Waiting for 'resume' call"
  • Warn
    • "Cache corrupted for file='test.file'. Reading from back-end"
    • "Database 192.168.0.7/DB not responding. Using backup 192.168.0.8/DB"
    • "No response from statistics server. Statistics not sent"
  • Error
    • "Internal error. Cannot process request #12345 Error:...."
    • "Cannot perform login: credentials DB not responding"
  • Critical
    • "Critical panic received: .... Shutting down"
    • "Fatal error: ... App is shutting down to prevent data corruption or loss"

例子:

下面的示例演示了Seelog級別的概念用法。

注1:這個例子實際上在計算方面沒有任何意義。它只是突出了日誌級別使用上下文中的差別。

注2:有時人們會將Info與Debug甚至Trace混淆。咱們試圖找出最引人注目的案例。請注意「Info」用例:它是一個生產日誌級別,咱們讓它在不影響性能(即便在生產中)的狀況下運行。

package main

import (
    log "github.com/cihub/seelog"
    "time"
    "errors"
)

type inputData struct {
    x, y int
}

type outputData struct {
    result int
    error bool
}

var inputs chan inputData
var outputs chan outputData
var criticalChan chan int

func internalCalculationFunc(x, y int) (result int, err error) {
    log.Debugf("calculating z. x:%d y:%d", x, y) //報告系統行爲,定位開發過程
    z := y
    switch {
    case x == 3 :
        log.Trace("x == 3")//進行深度調試:查找函數的問題部分,檢查臨時變量的值等
        panic("Failure.")
    case y == 1 :
        log.Trace("y == 1")
        return 0, errors.New("Error!")
    case y == 2 :
        log.Trace("y == 2")
        z = x
    default :
        log.Trace("default")
        z += x
    }
    log.Tracef("z:%d",z)
    retVal := z-3
    log.Debugf("Returning %d", retVal)
    
    return retVal, nil
}

func generateInputs(dest chan inputData) {
    time.Sleep(1e9)
    log.Debug("Sending 2 3")
    dest <- inputData{x : 2, y : 3}
    
    time.Sleep(1e9)
    log.Debug("Sending 2 1")
    dest <- inputData{x : 2, y : 1}
    
    time.Sleep(1e9)
    log.Debug("Sending 3 4")
    dest <- inputData{x : 3, y : 4}
    
    time.Sleep(1e9)
    log.Debug("Sending critical")
    criticalChan <- 1
}

func consumeResults(res chan outputData) {
    for {
        select {
            case <- outputs:
            //在這一點上,咱們獲得並輸出結果值
        }
    }
}

func processInput(input inputData) {
    defer func() {
        if r := recover(); r != nil {//獲取panic中的錯誤信息
            log.Errorf("Unexpected error occurred: %v", r) //記錄錯誤信息
            outputs <- outputData{result : 0, error : true}
        }
    }()
    log.Infof("Received input signal. x:%d y:%d", input.x, input.y)    //關於應用程序工做的通常信息
    
    res, err := internalCalculationFunc(input.x, input.y)    
    if err != nil {
        log.Warnf("Error in calculation: %s", err.Error())//用於指示以安全方式自動處理的小錯誤、奇怪狀況和故障
    }
    
    log.Infof("Returning result: %d error: %t", res, err != nil)        
    outputs <- outputData{result : res, error : err != nil}    
}

func main() {
    inputs = make(chan inputData)
    outputs = make(chan outputData)
    criticalChan = make(chan int)
    log.Info("App started.")
    
    go consumeResults(outputs) //outputs通道等待結果,並將結果輸出
    log.Info("Started receiving results.")
    
    go generateInputs(inputs)
    log.Info("Started sending signals.")//三次將值發送到inputs通道中,並輸入1給criticalChan
    
    for {
        select {
            case input := <- inputs: //generateInputs每次值輸入到inputs時就併發在此輸出
                processInput(input) //進行內部計算並將結果輸入通道outputs
            case <- criticalChan:  //直到generateInputs的最後輸入1給criticalChan
                log.Critical("Caught value from criticalChan: Go shut down.") //在應用程序死亡以前生成最後的消息
                panic("Shut down due to critical fault.")
        }    
    }
}

返回:

bogon:~ user$ go run testGo.go 
1551581657401394000 [Info] App started.
1551581657401416000 [Info] Started receiving results.
1551581657401419000 [Info] Started sending signals.
1551581658406575000 [Debug] Sending 2 3
1551581658406686000 [Info] Received input signal. x:2 y:3
1551581658406827000 [Debug] calculating z. x:2 y:3
1551581658406850000 [Trace] default
1551581658406860000 [Trace] z:5
1551581658406870000 [Debug] Returning 2
1551581658407009000 [Info] Returning result: 2 error: false
1551581659412207000 [Debug] Sending 2 1
1551581659412273000 [Info] Received input signal. x:2 y:1
1551581659412357000 [Debug] calculating z. x:2 y:1
1551581659412368000 [Trace] y == 1
1551581659412499000 [Warn] Error in calculation: Error!
1551581659412528000 [Info] Returning result: 0 error: true
1551581660414490000 [Debug] Sending 3 4
1551581660414708000 [Info] Received input signal. x:3 y:4
1551581660414760000 [Debug] calculating z. x:3 y:4
1551581660414774000 [Trace] x == 3
1551581660414787000 [Error] Unexpected error occurred: Failure.
1551581661420124000 [Debug] Sending critical
1551581661420188000 [Critical] Caught value from criticalChan: Go shut down.
panic: Shut down due to critical fault.

goroutine 1 [running]:
main.main()
    /Users/user/testGo.go:109 +0x3bc
exit status 2

 

4.約束和例外

限制

約束限制了規範日誌級別的規則。若是沒有指定約束,則容許全部日誌級別。

  • Min/max約束容許包含最小值和最大值之間的級別(例如,info thru error)。min和max都不須要在場。所以,你能夠容許全部日誌級別高於或低於最小級別1。可以使用關鍵字「minlevel」和「maxlevel」設置這些約束。
  • 約束列表只容許在列表中指定級別。例如,你能夠輸入字符串「debug, info, critical」來表示logger須要這三個級別。使用關鍵字「levels」來設置這種約束。

有兩種類型的約束:全局約束和例外約束

 

全局約束

全局約束用於整個應用程序,它們使用的是「按期應用的」規則(而不是「例外」)。這些約束是在seelog根元素屬性中設置的。

舉例說明

若要只容許日誌級別「info」及以上,請使用如下命令啓動配置:

<seelog minlevel="info">

容許級別從 info到error(即 info, warn, error),使用:

<seelog minlevel="info" maxlevel="error">

要只容許特定的級別集(例如trace, info, and critical級別),請使用如下命令啓動配置:

<seelog levels="trace,info,critical">

 

例外約束

例外,與通常規則相反,被認爲是打破(放鬆或增強)常規規則(通常約束)的特殊狀況。例如,你可能但願限制特定文件或文件組的日誌記錄。反之亦然:你確實有限制全局約束,而且你但願容許特定的文件或函數在更深的層次上進行日誌記錄。

例外包括「filepattern」、「funcpattern」和約束(「minlevel」/「maxlevel」或「levels」)。所以,若是你但願使用特定的名稱模式覆蓋函數或文件(或二者)的通常規則,那麼能夠在「filepattern」/「funcpattern」字段中指定模式,並使用覆蓋約束。

 

例外如何使用

當你在運行時爲每一個日誌執行日誌記錄時。在底層調用調用方函數以獲取當前上下文。而後咱們發現匹配模式file/func名的第一個例外。若是發現這樣的例外,則其約束將覆蓋常規約束

 

建議

根據上面所說的,有一些簡單的建議:

  • 例外要適度。當咱們在每次記錄某樣東西時都運行例外列表時,用規則填充它不是一個好主意,只有少數能夠這麼作。咱們稱它們爲例外是有緣由的!
  • 避免生產配置中容許「trace」或「debug」級別的約束。若是這樣作,你將告訴分析器「容許在某些地方進行traces/debugs」,而且全部Trace/Debug調用不會當即返回,而是強制約束檢查器在每次運行時運行。而後調用者將進入例外列表等。然而,對於性能並不重要的開發或生產系統,這些限制是能夠接受的。(參見下面的例子)
  • 首先使用更具體的規則。這只是由於咱們剛好使用知足file/func名稱模式的第一個例外。所以,若是你的文件名符合例外的「filepattern」—例外子系統將當即使用此例外的約束,而不會查看隨後出現的例外。因此首先使用更具體的規則,最後使用不那麼具體的規則(參見下面的例子)

舉例說明:

讓咱們從「test」開始,爲全部文件建立更多的限制規則。

<seelog minlevel="info">
    <exceptions>
        <exception filepattern="test*" minlevel="error"/>
    </exceptions>

經過這種方式,你將得到全部文件的「info」、「warn」、「error」、「critical」消息,但以「test」開頭的文件除外。對於以「test」開頭的文件,你只會獲得「error」和「critical」消息。

另外一個例子。如今讓咱們建立一個相反的狀況:讓咱們只容許「critical」消息做爲通常規則,但容許「main.testFunc」函數爲「warn, error, critical」級別(package 'main', func 'testFunc'):

<seelog levels="critical">
    <exceptions>
        <exception funcpattern="main.testFunc" minlevel="warn"/>
    </exceptions>

讓咱們建立一個生產就緒配置:

<seelog minlevel="info">
    <exceptions>
        <exception funcpattern="main.testFunc" minlevel="warn"/>
                <exception funcpattern="main.testFunc2" minlevel="error"/>
                <exception funcpattern="*test*" filepattern="tests.go" levels="off"/>
                <exception funcpattern="*perfCritical" minlevel="critical"/>
    </exceptions>
...

這個配置徹底能夠用於生產,由於它沒有任何容許級別「trace」或「debug」的例外
讓咱們先測試一下「更常見的例外狀況」規則:

<seelog minlevel="info">
    <exceptions>
                <exception funcpattern="main.testFunc" levels="critical"/>
                <exception funcpattern="main.test*" minlevel="error"/>
        <exception funcpattern="main.*" minlevel="warn"/>
    </exceptions>
...

這個配置將像它看起來的那樣工做。但若是你以另外一種順序寫這些例外,它就不同了。例如,若是你將「main.*」放在例外的前面,那麼其餘兩個例外將被忽略。

 

「off」日誌級別

「off」是一個特殊的日誌級別,它意味着禁用日誌記錄。它能夠在minlevel和level約束中使用,所以你能夠在全局約束或例外約束中寫入'minlevel= 「off」'和'levels= 「off」'來禁用日誌。

 

示例

package main

import (
    "fmt"
    log "github.com/cihub/seelog"
)

func main() {
    defer log.Flush()
    testMinMax()
    testMin()
    testMax()
    testList()
    testFuncException()
    testFileException()
}


func testMinMax() { //只會輸出日誌級別在info和error之間的日誌的內容,即info\warn\error
    fmt.Println("testMinMax")
    testConfig := `
<seelog type="sync" minlevel="info" maxlevel="error">
    <outputs><console/></outputs>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("NOT Printed")
    log.Debug("NOT Printed")
    log.Info("Printed")
    log.Warn("Printed")
    log.Error("Printed")
    log.Critical("NOT Printed")
}

func testMin() { //會輸出大於info日誌級別的日誌內容,即info\warn\error\critical
    fmt.Println("testMin")
    testConfig := `
<seelog type="sync" minlevel="info">
    <outputs><console/></outputs>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("NOT Printed")
    log.Debug("NOT Printed")
    log.Info("Printed")
    log.Warn("Printed")
    log.Error("Printed")
    log.Critical("Printed")
}

func testMax() {//會輸出級別不大於error的日誌文件的信息,即trace、debug、info、warn和error
    fmt.Println("testMax")
    testConfig := `
<seelog type="sync" maxlevel="error">
    <outputs><console/></outputs>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("Printed")
    log.Debug("Printed")
    log.Info("Printed")
    log.Warn("Printed")
    log.Error("Printed")
    log.Critical("NOT Printed")
}

func testList() {//只輸出日誌級別爲info, trace, critical的日誌
    fmt.Println("testList")
    testConfig := `
<seelog type="sync" levels="info, trace, critical">
    <outputs><console/></outputs>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("Printed")
    log.Debug("NOT Printed")
    log.Info("Printed")
    log.Warn("NOT Printed")
    log.Error("NOT Printed")
    log.Critical("Printed")
}

//主限制是輸出大於info日誌級別的日誌內容,
//可是這裏有個例外,要求知足函數名爲"*main.test*Except*"的函數中的日誌輸出的是日誌級別大於error的日誌信息
//因此這裏最後輸出的是error、critical日誌
func testFuncException() { 
    fmt.Println("testFuncException")
    testConfig := `
<seelog type="sync" minlevel="info">
    <exceptions>
        <exception funcpattern="*main.test*Except*" minlevel="error"/>
    </exceptions>
    <outputs>
        <console/>
    </outputs>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("NOT Printed")
    log.Debug("NOT Printed")
    log.Info("NOT Printed")
    log.Warn("NOT Printed")
    log.Error("Printed")
    log.Critical("Printed")

    log.Current.Trace("NOT Printed")
    log.Current.Debug("NOT Printed")
    log.Current.Info("NOT Printed")
    log.Current.Warn("NOT Printed")
    log.Current.Error("Printed")
    log.Current.Critical("Printed")
}

//這裏由於testFileException名不知足例外中的"*main.go",因此返回的內容爲大於info日誌級別的日誌內容,即info\warn\error\critical
func testFileException() {
    fmt.Println("testFileException")
    testConfig := `
<seelog type="sync" minlevel="info">
    <exceptions>
        <exception filepattern="*main.go" minlevel="error"/>
    </exceptions>
    <outputs>
        <console/>
    </outputs>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("NOT Printed")
    log.Debug("NOT Printed")
    log.Info("NOT Printed")
    log.Warn("NOT Printed")
    log.Error("Printed")
    log.Critical("Printed")
}

返回:

userdeMBP:go-learning user$ go run test.go 
testMinMax
1551696134714593000 [Info] Printed
1551696134714624000 [Warn] Printed
1551696134714643000 [Error] Printed
testMin
1551696134714668000 [Info] Printed
1551696134714674000 [Warn] Printed
1551696134714679000 [Error] Printed
1551696134714684000 [Critical] Printed
testMax
1551696134714700000 [Trace] Printed
1551696134714708000 [Debug] Printed
1551696134714714000 [Info] Printed
1551696134714718000 [Warn] Printed
1551696134714723000 [Error] Printed
testList
1551696134714745000 [Trace] Printed
1551696134714751000 [Info] Printed
1551696134714758000 [Critical] Printed
testFuncException
1551696134714822000 [Error] Printed
1551696134714837000 [Critical] Printed
1551696134714847000 [Error] Printed
1551696134714852000 [Critical] Printed
testFileException
1551696134714888000 [Info] NOT Printed
1551696134714895000 [Warn] NOT Printed
1551696134714904000 [Error] Printed
1551696134714909000 [Critical] Printed

 

 

5.Dispatchers and receivers分配器和接收器

1)

接收器Receivers

咱們對後端字節接收器使用「receiver」術語,如日誌文件、網絡通道等。

分配器Dispatchers

咱們使用「dispatcher」術語表示向多個底層 接收者receivers/分配器dispatchers發送消息的中間元素。

舉例說明:

進行dispatcher/receiver配置的主要目標是使用公共格式選項或容許的日誌級別建立不一樣的組。例如,讓咱們建立一個示例配置:

<seelog>
    <outputs>
        <splitter formatid="common">
            <console/>
            <file path="file.log"/>
            <conn addr="192.168.0.2:8123"/>
        </splitter>
        <filter levels="critical">
            <file path="critical.log" formatid="critical"/>
            <smtp formatid="criticalemail" senderaddress="noreply-notification-service@none.org" sendername="Automatic notification service" hostname="mail.none.org" hostport="587" username="nns" password="123">
                <recipient address="john-smith@none.com"/>
                <recipient address="hans-meier@none.com"/>
            </smtp>
        </filter>
    </outputs>
    <formats>
        <format id="common" format="[%LEV] %Msg"/>
        <format id="critical" format="%Time %Date %RelFile %Func %Msg"/>
        <format id="criticalemail" format="Critical error on our server!\n    %Time %Date %RelFile %Func %Msg \nSent by Seelog"/>
    </formats>
</seelog>

所以,在這裏咱們使用一個「splitter」元素來按格式(「common」)將三個接收器分組,其餘兩個接收器使用「filter」按容許的日誌級別分組。注意,頂部的元素「output」自己就是一個拆分器splitter,所以咱們能夠簡化配置:

<seelog>
    <outputs formatid="common">
        <console/>
        <file path="file.log"/>
        <conn addr="192.168.0.2:8123"/>
        <filter levels="critical">
            <file path="critical.log" formatid="critical"/>
            <smtp formatid="criticalemail" senderaddress="noreply-notification-service@none.org" sendername="Automatic notification service" hostname="mail.none.org" hostport="587" username="nns" password="123">
                <recipient address="john-smith@none.com"/>
                <recipient address="hans-meier@none.com"/>
            </smtp>
        </filter>
    </outputs>
    <formats>
        <format id="common" format="[%LEV] %Msg"/>
        <format id="critical" format="%Time %Date %RelFile %Func %Msg"/>
        <format id="criticalemail" format="Critical error on our server!\n    %Time %Date %RelFile %Func %Msg \nSent by Seelog"/>
    </formats>
</seelog>

 

Formatting格式化

格式僅在寫入字節接收器時應用。若是沒有設置「formatid」,Dispatchers將繼承格式標識符。若是設置了「formatid」,分配器和字節接收器將覆蓋任何繼承的格式。

讓咱們使用上面例子中的配置:

<seelog>
    <outputs formatid="common">
        <console/>
        <file path="file.log"/>
        <network address="192.168.0.2" port="8123"/>
        <filter levels="critical">
            <file path="critical.log" formatid="critical"/>
            <smtp formatid="criticalemail" senderaddress="noreply-notification-service@none.org" sendername="Automatic notification service" hostname="mail.none.org" hostport="587" username="nns" password="123">
                <recipient address="john-smith@none.com"/>
                <recipient address="hans-meier@none.com"/>
            </smtp>
        </filter>
    </outputs>
    <formats>
        <format id="common" format="[%LEV] %Msg"/>
        <format id="critical" format="%Time %Date %RelFile %Func %Msg"/>
        <format id="criticalemail" format="Critical error on our server!\n    %Time %Date %RelFile %Func %Msg \nSent by Seelog"/>
    </formats>
</seelog>

它演示了繼承/覆蓋(inheritance/overriding)特性。最上面的splitter有formatid=「common」,所以它的全部子組件都繼承它:console, file, network,和filter。filter中的file和smtp接收器不會繼承它,由於它們用本身的格式文件覆蓋它。若是smtp沒有一個「formatid」屬性集,那麼它將從其父組件「filter」分配器中繼承formatid=「common」。

 

示例

 

package main

import (
    "fmt"
    log "github.com/cihub/seelog"
    "time"
)

func main() {
    defer log.Flush()
    runExample(consoleWriter)
    runExample(fileWriter)
    runExample(rollingFileWriter)
    runExample(rollingFileWriterManyRolls)
    runExample(bufferedWriter)
    runExample(bufferedWriterWithFlushPeriod)
    runExample(bufferedWriterWithOverflow)
    runExample(splitDispatcher)
    runExample(filterDispatcher)
    //runExample(smtpWriter)
}

func runExample(exampleFunc func()) {
    exampleFunc()
    fmt.Println()
}

//在終端標準輸出中輸出"Console writer"
//並在終端輸出5個trace日誌信息
func consoleWriter() {
    testConfig := `
<seelog>
    <outputs>
        <console />
    </outputs>
</seelog>
`
    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    fmt.Println("Console writer")
    
    doLog()
}

//將5個trace日誌信息寫到文件./log/log.log中
func fileWriter() {
    
    testConfig := `
<seelog>
    <outputs>
        <file path="./log/log.log"/>
    </outputs>
</seelog>
`
    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    fmt.Println("File writer")
    
    doLog()
}

//將日誌信息寫到回滾文件./log/roll.log中
//以大小size存儲,文件最大爲100個字節,文件個數最多爲5
func rollingFileWriter() {
    testConfig := `
<seelog>
    <outputs>
        <rollingfile type="size" filename="./log/roll.log" maxsize="100" maxrolls="5" />
    </outputs>
</seelog>
`
    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    fmt.Println("Rolling file writer")
    
    doLog()
}


func rollingFileWriterManyRolls() {
    testConfig := `
<seelog>
    <outputs>
        <rollingfile type="size" filename="./log/manyrolls.log" maxsize="100" maxrolls="4" />
    </outputs>
</seelog>
`
    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    fmt.Println("Rolling file writer. Many rolls")
    
    doLogBig()
}

func bufferedWriter() {
    testConfig := `
<seelog>
    <outputs>
        <buffered size="10000">
            <file path="./log/bufFile.log"/>
        </buffered>
    </outputs>
</seelog>
`
    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    fmt.Println("Buffered file writer. NOTE: file modification time not changed until next test (buffered)")
    time.Sleep(3e9)
    for i := 0; i < 3; i++ {
        doLog() 
        time.Sleep(5e9)
    }
    
    time.Sleep(2e9)
}

func bufferedWriterWithFlushPeriod() {
    testConfig := `
<seelog>
    <outputs>
        <buffered size="10000" flushperiod="1000">
            <file path="./log/bufFileFlush.log"/>
        </buffered>
    </outputs>
</seelog>
`
    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    fmt.Println("Buffered file writer with flush period. NOTE: file modification time changed after each 'doLog' because of small flush period.")
    time.Sleep(3e9)
    for i := 0; i < 3; i++ {
        doLog() 
        time.Sleep(5e9)
    }
    
    time.Sleep(2e9)
}

//雖然溢出,可是日誌信息仍所有存儲
func bufferedWriterWithOverflow() {
    testConfig := `
<seelog>
    <outputs>
        <buffered size="20">
            <file path="./log/bufOverflow.log"/>
        </buffered>
    </outputs>
</seelog>
`
    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    fmt.Println("Buffered file writer with overflow. NOTE: file modification time changes after each 'doLog' because of overflow")
    time.Sleep(3e9)
    for i := 0; i < 3; i++ {
        doLog() 
        time.Sleep(5e9)
    }
    
    time.Sleep(1e9)
}

//日誌信息在輸入日誌文件split.log同時也輸出到標準輸出中
func splitDispatcher() {
    testConfig := `
<seelog>
    <outputs>
        <file path="./log/split.log"/>
        <console />
    </outputs>
</seelog>
`
    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    fmt.Println("Split dispatcher")
    
    doLog() 
}

//只有trace日誌級別的信息存儲到filter.log文件中,可是trace和debug的日誌信息都會輸出到標準輸出中
func filterDispatcher() {
    testConfig := `
<seelog>
    <outputs>
        <filter levels="trace">
            <file path="./log/filter.log"/>
        </filter>
        <console />
    </outputs>
</seelog>
`
    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    fmt.Println("Filter dispatcher")
    
    for i:=0; i < 5; i++ {
        log.Trace("This message on console and in file")
        log.Debug("This message only on console")
    }
}

func smtpWriter() {
 testConfig := `
 <seelog>
  <outputs>
   <smtp senderaddress="noreply-notification-service@none.org" sendername="Automatic notification service" hostname="mail.none.org" hostport="587" username="nns" password="123">
    <recipient address="john-smith@none.com"/>
   </smtp>
  </outputs>
 </seelog>
 `
 logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
 log.ReplaceLogger(logger)
 fmt.Println("SMTP writer is now sending emails to the specified recipients")
 doLog()
}

func doLog() {
    for i:=0; i < 5; i++ {
        log.Tracef("%d", i)
    }
}

func doLogBig() {
    for i:=0; i < 50; i++ {
        log.Tracef("%d", i)
    }
}
View Code

返回:

userdeMBP:go-learning user$ go run test.go 
Console writer

1551697317265791000 [Trace] 0
1551697317265815000 [Trace] 1
1551697317265818000 [Trace] 2
1551697317265819000 [Trace] 3
1551697317265820000 [Trace] 4
File writer

Rolling file writer

Rolling file writer. Many rolls

Buffered file writer. NOTE: file modification time not changed until next test (buffered)

Buffered file writer with flush period. NOTE: file modification time changed after each 'doLog' because of small flush period.

Buffered file writer with overflow. NOTE: file modification time changes after each 'doLog' because of overflow

Split dispatcher

1551697376322223000 [Trace] 0
1551697376322243000 [Trace] 1
1551697376322250000 [Trace] 2
1551697376322256000 [Trace] 3
1551697376322262000 [Trace] 4
Filter dispatcher
1551697376322864000 [Trace] This message on console and in file
1551697376322876000 [Debug] This message only on console
1551697376322891000 [Trace] This message on console and in file
1551697376322897000 [Debug] This message only on console
1551697376322900000 [Trace] This message on console and in file
1551697376322903000 [Debug] This message only on console
1551697376322906000 [Trace] This message on console and in file

1551697376322910000 [Debug] This message only on console
1551697376323322000 [Trace] This message on console and in file
1551697376323329000 [Debug] This message only on console

一個文件中最多有100個字節,所以這裏一個文件中只寫入了4行日誌信息,其餘的日誌信息將另起一個文件存儲,以前的文件將被重命名爲roll.log.1,後來的日誌內容仍會存在roll.log中,若是再超出,目前roll.log中的內容將存在名爲roll.log.2的文件中,新內容仍存儲在roll.log

好比函數rollingFileWriter運行第一次的日誌文件有兩個,其內容爲:

userdeMBP:go-learning user$ cat ./log/roll.log
1551698497839015000 [Trace] 4

userdeMBP:go-learning user$ cat ./log/roll.log.1 
1551698497838979000 [Trace] 0
1551698497839007000 [Trace] 1
1551698497839010000 [Trace] 2
1551698497839013000 [Trace] 3

再運行一次函數rollingFileWriter,可見日誌文件變成了三個,內容分別爲:

userdeMBP:go-learning user$ cat ./log/roll.log.1
1551698497838979000 [Trace] 0
1551698497839007000 [Trace] 1
1551698497839010000 [Trace] 2
1551698497839013000 [Trace] 3

userdeMBP:go-learning user$ cat ./log/roll.log.2
1551698497839015000 [Trace] 4
1551698882929867000 [Trace] 0
1551698882929892000 [Trace] 1
1551698882929894000 [Trace] 2

userdeMBP:go-learning user$ cat ./log/roll.log
1551698882929896000 [Trace] 3
1551698882929897000 [Trace] 4

 

運行函數rollingFileWriterManyRolls後,日誌文件爲:

可見該日誌文件一直保持5個的數量,後面的日誌將前面的日誌覆蓋

userdeMBP:go-learning user$ cat ./log/manyrolls.log.9
1551697317268125000 [Trace] 32
1551697317268127000 [Trace] 33
1551697317268128000 [Trace] 34
1551697317269659000 [Trace] 35
userdeMBP:go-learning user$ cat ./log/manyrolls.log.12
1551697317271189000 [Trace] 44
1551697317271192000 [Trace] 45
1551697317271194000 [Trace] 46
1551697317271196000 [Trace] 47
userdeMBP:go-learning user$ cat ./log/manyrolls.log
1551697317271197000 [Trace] 48
1551697317271198000 [Trace] 49

 

2)分配器(dispatchers)列表:Reference

下面不一樣的dispatcher是用於指明發送消息的方式

1》Splitter dispatcher

功能:將接收到的消息發送到全部子節點。用於細分<outputs>日誌格式,內部支持:file(文件), rollingfile(滾動文件,自動清除過時)

元素名:Splitter

容許屬性:

  • formatid—不覆蓋它的全部子節點將繼承的格式

舉例說明:

<seelog>
    <outputs>
        <splitter formatid="format1">
            <file path="log.log"/>
            <file path="log2.log"/>
        </splitter>
        <splitter formatid="format2">
            <file path="log3.log"/>
            <file path="log4.log"/>
        </splitter>
    </outputs>
    <formats>
        ...
    </formats>
</seelog>

注:「output」元素也是一個Splitter,這只是頂部Splitter的一個特殊別名,所以,能夠寫成:

<seelog>
    <outputs>
        <file path="split.log"/>
        <console />
    </outputs>
</seelog>

上面的例子等價於:

<seelog>
    <splitter>
        <file path="split.log"/>
        <console />
    </splitter>
</seelog>

但後者在句法上並不正確。

2》Filter dispatcher

功能:僅當接收到的消息的日誌級別在「allowed」列表中時,才向全部子節點發送接收到的消息。用於單獨處理某個或某些級別日誌

元素名:Filter

容許屬性:

formatid—不覆蓋它的全部子節點將繼承的格式
levels—「allowed」列表中的逗號分隔的日誌級別標識符(日誌級別)列表

舉例說明:

<seelog>
    <outputs>
        <filter levels="trace,debug">
          <file path="filter.log"/>
       </filter>
        <console />
    </outputs>
</seelog>

 

3)接收器(receivers)列表:Reference

下面的不一樣種類的writer的目的其實就是將接收到的信息寫入不一樣的地方

1》File writer

功能:將收到的消息寫到一個文件中

元素名:file

容許屬性:

  • formatid—此接收器將使用的格式
  • path——日誌文件的路徑
<seelog>
    <outputs>
        <file path="log.log"/>
    </outputs>
</seelog>

注意:

  • 不要使用文件名中不容許的任何特殊符號。
  • 不要在多進程環境中使用相同的文件,以免日誌不一致。

2》Console writer

功能:將收到的消息寫到標準輸出中

元素名:Console

容許屬性:

  • formatid—此接收器將使用的格式
<seelog>
    <outputs>
        <console/>
    </outputs>
</seelog>

3》Rolling file writer (or "Rotation file writer")

功能:將接收到的消息寫入文件,直到日期更改或文件超過指定的限制。在此以後,將重命名當前日誌文件並開始將日誌寫到新文件中。若是按大小滾動,能夠設置重命名文件計數的限制(若是須要的話),而後當文件計數超過指定的限制時,滾動寫入器將刪除舊的文件。

這樣作的好處就是可以控制日誌的大小,對於一個高流量的Web應用來講,日誌的增加是十分可怕的。這樣就可以保證日誌文件不會由於不斷變大而致使咱們的磁盤空間不夠引發問題

元素名:rollingfile

容許屬性:

  • formatid—此接收器將使用的格式
  • filename-到日誌文件的路徑。在建立時,該路徑被分爲文件夾路徑和實際文件名。後者將做爲全部文件的公共部分,在滾動中起做用:
  1. 在按「date」滾動的狀況下,文件名將以這種方式造成:filename.DATE_PATTERN。例如(若是未設置全名標誌,請參見下面):app.log, app.log.11.Aug.14, app.log.11.Aug.15
  2. 在按'size'滾動的狀況下,文件名將以這種方式造成:"filename.#"。例如app.log, app.log.1, app.log.2, app.log.3
  • type-旋轉類型:"date"或 "size"
  • namemode-滾動文件的命名模式。可能的值:"postfix"(後綴), "prefix"(前綴)。若是設置爲「postfix」,滾動的文件看起來像'file.log.1', 'file.log.02.01.2006';若是設置爲"prefix",則看起來像是'1.file.log', '02.01.2006.file.log'。默認爲"postfix"
  • maxrolls -重命名文件的最大計數。當超過此限制時,將刪除舊卷。值應該是>= 0。注意:在2.3版本以前,此屬性不適用於「date」滾動寫入器。
  • archivetype—一個用於指定存儲舊卷而不是刪除舊卷的存檔的類型的屬性。可能的值:「none」、「zip」、「gzip」。若是設置爲「none」,則不執行存檔(只刪除舊卷)。
  • archiveexploded——一個用於指定日誌是應該被分解仍是分組到同一個歸檔文件中的屬性。
  • archivepath——當archivetype未設置爲「none」時使用的屬性。指定存儲舊卷的存檔的路徑。

當容許'size'類型時的屬性:

  • maxsize——這是致使滾動的超出大小限制(以字節爲單位)。

當容許'date'類型時的屬性:

  • datepattern—這是使用在「time.LocalTime().Format」去造成一個文件名的模式。當'time. localtime (). format (rollFileWriter.datePattern)'返回與當前文件名不一樣的內容時,將發生「date」(實際上,這意味着日期和時間)滾動。這意味着你可使用帶有日期標識符(如「02.01.2006」)的格式建立日滾動。或者你可使用帶有小時標識符(如「02.01.2006.15」)的格式建立小時滾動。
  • fullname — 一個影響當前文件名的布爾屬性。若是設置爲「true」,則當前文件名將使用與卷名相同的命名約定。例如,日誌文件列表將相似於app.log.11.Aug.13, app.log.11.Aug.14, app.log.11.Aug.15, ...,而不是app.log, app.log.11.Aug.14, app.log.11.Aug.15, ....。默認設置爲false

⚠️

  • 不要使用文件名中不容許的任何特殊符號。
  • 不要在多進程環境中使用相同的文件,以免日誌不一致。

舉例說明:

<seelog>
    <outputs>
        <rollingfile type="size" filename="logs/roll.log" maxsize="1000" maxrolls="5" />
    </outputs>
</seelog>

 

<seelog>
    <outputs>
        <rollingfile type="date" filename="logs/roll.log" datepattern="02.01.2006" maxrolls="7" />
    </outputs>
</seelog>

4》Buffered writer

功能:充當緩衝區包裝其餘寫入器。緩衝寫入器將數據存儲在內存中,並在每次刷新週期或緩衝區滿時刷新數據。將日誌先存在內存中,按期寫入文件,適合日誌併發量較大或 IO 比較緊張的場合

元素名:buffered

容許的屬性:

  • formatid—此接收器將使用的格式
  • size-緩衝區大小(以字節爲單位)
  • flushperiod——緩衝區刷新之間的間隔(單位爲毫秒)

舉例說明:

<seelog>
    <outputs>
        <buffered size="10000" flushperiod="1000">
            <file path="bufFile.log"/>
        </buffered>
    </outputs>
</seelog>

 

<seelog>
    <outputs>
        <buffered size="10000" flushperiod="1000" formatid="someFormat">
            <rollingfile type="date" filename="logs/roll.log" datepattern="02.01.2006" />
        </buffered>
    </outputs>
    <formats>
        ...
    </formats>
</seelog>

注意:該寫入器使用特定格式累計寫入的數據,而後將其刷新到內部寫入器中。所以,內部寫入器不能有本身的格式:僅爲緩衝元素設置「formatid」,如上一個示例中所示。

5》SMTP writer

功能:在給定的post服務器上使用密碼保護(但一般不安全)的電子郵件賬戶向指定的收件人發送電子郵件。經過郵件smtp方式將日誌文件發送出去(通常會發給相應的運維人員)

元素名:smtp

容許使用的屬性:

  • senderaddress-發件人的電子郵件地址
  • sendername—發送方的名稱
  • hostname——post服務器的主機名(一般是mail.XXX.YYY)
  • hostport - post服務器的TCP端口(一般爲587)
  • username——用於登陸到post服務器的用戶名
  • password——post服務器的密碼
  • subject-電子郵件的主題

子元素名:recipient

容許使用的屬性:

  • address-收件人的電子郵件地址(接收來自通知者的消息)

子元素名:cacertdirpath

  • path-到帶有PEM證書文件的目錄的路徑。

舉例說明:

<seelog>
  <outputs>
   <smtp senderaddress="noreply-notification-service@none.org" sendername="Automatic notification service" hostname="mail.none.org" hostport="587" username="nns" password="123">
    <recipient address="john-smith@none.com"/>
    <recipient address="hans-meier@none.com"/>
   </smtp>
  </outputs>
 </seelog>

 

<seelog>
  <outputs>
   <filter levels="error,critical">
    <smtp senderaddress="nns@none.org" sendername="ANS" hostname="mail.none.org" hostport="587" username="nns" password="123" subject="test">
     <cacertdirpath path="cacdp1"/>
     <recipient address="hans-meier@none.com"/>
     <header name="Priority" value="Urgent" />
     <header name="Importance" value="high" />
     <header name="Sensitivity" value="Company-Confidential" />
     <header name="Auto-Submitted" value="auto-generated" />
    </smtp>
   </filter>
  </outputs>
 </seelog>

注意:

查看上面的第一個示例,瞭解如何使用SMTP writer。請記住,電子郵件noreply-notific-service@none.org不能被認爲是安全可靠的。因爲配置中顯式的發送密碼,它可能會受到黑客攻擊,咱們強烈建議你不要爲SMTP writer使用我的或公司的post賬戶。最好的作法是專門設置一個獨立的郵政賬戶,特別是電子郵件通知服務。

第二個示例演示了使用這個編寫器的最合理的方法——在(罕見的)特殊狀況下使用應用程序的通知。從技術上講,你能夠設置其餘過濾級別,但也要作好被診斷郵件淹沒的準備。

能夠設置當發生了錯誤的時候咱們就可以將錯誤信息發送給運維,這樣就就可以在遇到問題時及時處理

6》Conn writer

功能:將接收到的消息寫入網絡鏈接。

元素名:conn

容許使用的屬性:

  • formatid— 此接收器將使用的格式
  • net— 使用的網絡(「tcp」, 「udp」,「tcp4」、「udp4」……)
  • addr -網絡地址(":1000","127.0.0.1:8888",…)
  • reconnectonmsg -若是爲true,鏈接將在每次寫入時打開,不然在第一次寫入時打開。默認爲false。
  • usetls -若是爲true,將使用TLS。
  • insecureskipverify — 設置tls.Config的InsecureSkipVerify標誌。若是設置了useTLS就使用它

舉例說明:

<seelog type="sync">
    <outputs>
        <conn net="tcp" addr=":8888" />
    </outputs>
</seelog>

 

<outputs>
  <conn formatid="syslog" net="tcp4" addr="server.address:5514" tls="true" insecureskipverify="true" />
</outputs>
<formats>
  <format id="syslog" format="%CustomSyslogHeader(20) %Msg%n"/>
</formats>

%CustomSyslogHeader的示例代碼能夠查看下面的 4)Custom formatters自定義格式器 - 2》

 

6.Formatting格式化

1)

Seelog提供了更改發送到字節接收器的消息格式的功能。格式設置在「formats」配置部分,以下:

<formats>
    <format id="common" format="[%LEV] %Msg"/>
    <format id="critical" format="%Time %Date %RelFile %Func %Msg"/>
    <format id="criticalemail" format="Critical error on our server!\n    %Time %Date %RelFile %Func %Msg \nSent by Seelog"/>
</formats>

每一個「format」節點都有一個「id」和「format」屬性。Id是用於將格式連接到dispatchers/receiver的格式的惟一標識符。「format」屬性用於用特殊的格式化對象指定格式字符串,以「%」符號開頭。當將消息寫入字節接收器時,這些特殊符號將被上下文值或特殊字符串替換。

要查看格式是如何連接到dispatchers/receiver的,查看上面 Dispatchers and receivers分配器和接收器 的「Formatting」部分

2)formatters列表

1》Message context消息上下文

  • %Level - 日誌級別 (Trace, Debug, Info, Warn, Error, Critical)
  • %Lev - 短日誌級別 (Trc, Dbg, Inf, Wrn, Err, Crt)
  • %LEVEL - 大寫的日誌級別 (TRACE, DEBUG, INFO, WARN, ERROR, CRITICAL)
  • %LEV - 縮寫版大寫日誌級別 (TRC, DBG, INF, WRN, ERR, CRT)
  • %l - 超簡寫版日誌級別(t, d, i, w, e, c)
  • %Msg - 消息文本 (string)
  • %FullPath - 完整的調用者文件路徑
  • %File - 只調用文件名
  • %RelFile - 相對於應用程序運行目錄的調用者路徑
  • %Func - 調用函數名
  • %FuncShort - 調用函數名的最後一個點後面的部分
  • %Line - 日誌記錄器被調用時的行號

2》日期和時間

  • %Ns - time.Now().UnixNano()
  • %Date - 指明日期格式爲‘2006-01-02’的快捷方式
  • %Time - 指明時間格式爲‘15:04:05’的快捷方式
  • %Date(...) - 日期的格式,指定在括號中。使用標準time.Format,所以請檢查http://golang.org/src/pkg/time/format.go中的標識符列表。能夠這樣使用:「%Date(2006-01-02)」(或任何其餘格式)
  • %UTCNs - time.Now().UTC().UnixNano()
  • %UTCDate - 指明日期格式爲‘2006-01-02’ (UTC)的快捷方式
  • %UTCTime - 指明時間格式爲‘15:04:05’ (UTC)的快捷方式
  • %UTCDate(...) - UTC日期的格式,指定在括號中。使用標準時間。格式,所以請檢查http://golang.org/src/pkg/time/format.go中的標識符列表。能夠這樣使用:「%UTCDate(2006-01-02)」(或任何其餘格式)

3》特殊符號

  • %EscN - terminal ANSI CSI n [;k] m escape. 檢查彩色輸出的詳細信息
  • %n - 換行符
  • %t - 製表符

3)Predefined formats預約義格式

Seelog配置解析器識別一組特殊的格式標識符,稱爲預約義格式。引入這些標識符是爲了不每次在配置文件中顯式建立「xml」或「json」等公共格式。

1》使用

使用任何輸出節點的「formatid」屬性中的預約義格式標識符之一。

格式標識符的全名由前綴std:和下面列出的標識符之一組成。如下是完整的id-format對的列表:

  • xml-debug: <time>%Ns</time><lev>%Lev</lev><msg>%Msg</msg><path>%RelFile</path><func>%Func</func>
  • xml-debug-short: <t>%Ns</t><l>%l</l><m>%Msg</m><p>%RelFile</p><f>%Func</f>
  • xml: <time>%Ns</time><lev>%Lev</lev><msg>%Msg</msg>
  • xml-short: <t>%Ns</t><l>%l</l><m>%Msg</m>
  • json-debug: {"time":%Ns,"lev":"%Lev","msg":"%Msg","path":"%RelFile","func":"%Func"}
  • json-debug-short: {"t":%Ns,"l":"%Lev","m":"%Msg","p":"%RelFile","f":"%Func"}
  • json: {"time":%Ns,"lev":"%Lev","msg":"%Msg"}
  • json-short: {"t":%Ns,"l":"%Lev","m":"%Msg"}
  • debug: [%LEVEL] %RelFile:%Func %Date %Time %Msg%n
  • debug-short: [%LEVEL] %Date %Time %Msg%n
  • fast: %Ns %l %Msg%n

注意:

使用你本身的格式覆蓋預約義的格式並使用以std:開頭的標識符建立你本身的格式是徹底合法的,可是不建議使用這兩種作法。

舉例說明:

<seelog>
    <outputs formatid="std:json">
        <console/>
    </outputs>
</seelog>

seelog.Info("Hello world!")輸出爲:

{"time":1341218159882230900,"lev":"Inf","msg":"Hello world!"}

將以json的格式輸出信息到標準輸出中

 

4)Custom formatters自定義格式器

若是你以爲上面2)formatters列表 中的標準格式化集還不夠,你能夠指定本身的自定義格式化程序。


要作到這一點,你必須使用seelog。使用RegisterCustomFormatter函數去爲你要使用的新格式別名註冊工廠。在此以後(若是返回的錯誤爲nil),你能夠在隨後建立的任何日誌記錄器中使用指定的格式別名。

自定義格式化器能夠參數化。參數字符串(括號內)若是存在,則傳遞給你註冊的工廠func。

讓咱們看幾個例子。

1》Alternative log level names可選日誌級別名稱

註冊你的新格式器:

var myLevelToString = map[log.LogLevel]string{ //這是我自定義的格式,重命名對應的日誌級別
    log.TraceLvl:    "MyTrace",
    log.DebugLvl:    "MyDebug",
    log.InfoLvl:     "MyInfo",
    log.WarnLvl:     "MyWarn",
    log.ErrorLvl:    "MyError",
    log.CriticalLvl: "MyCritical",
    log.Off:         "MyOff",
}

func createMyLevelFormatter(params string) log.FormatterFunc {
    return func(message string, level log.LogLevel, context log.LogContextInterface) interface{} {
        levelStr, ok := myLevelToString[level]
        if !ok {
            return "Broken level!"
        }
        return levelStr
    }
}

func init() {
    err := log.RegisterCustomFormatter("MyLevel", createMyLevelFormatter) //註冊
    if err != nil {
         ...
    }
}

如今你能夠在你的配置中使用註冊的「MyLevel」:

<seelog type="sync">
    <outputs formatid="main">
        <console/>
    </outputs>
    <formats>
        <format id="main" format="%MyLevel %Msg%n"/>
    </formats>
</seelog>

使用這個配置後一個日誌記錄器將建立:

log.Trace("Test message!")

輸出爲:

MyTrace Test message!

 

2》用於TLS鏈接並寫入syslog的格式器

註冊你的格式器:

var hostName string
var appName = "test"
var pid int

var levelToSyslogSeverity = map[log.LogLevel]int{
    // Mapping to RFC 5424 where possible
    log.TraceLvl:    7,
    log.DebugLvl:    7,
    log.InfoLvl:     6,
    log.WarnLvl:     4,
    log.ErrorLvl:    3,
    log.CriticalLvl: 2,
    log.Off:         7,
}

func createSyslogHeaderFormatter(params string) log.FormatterFunc {
    facility := 20
    i, err := strconv.Atoi(params)
    if err == nil && i >= 0 && i <= 23 {
        facility = i
    }

    return func(message string, level log.LogLevel, context log.LogContextInterface) interface{} {
        return fmt.Sprintf("<%d>1 %s %s %s %d - -", facility*8+levelToSyslogSeverity[level],
            time.Now().Format("2006-01-02T15:04:05Z07:00"),
            hostName, appName, pid)
    }
}

func init() {
    hostName, _ = os.Hostname()
    pid = os.Getpid()

    err := log.RegisterCustomFormatter("CustomSyslogHeader", createSyslogHeaderFormatter)
    if err != nil {
        ...
    }
}

如今你能夠在你的配置中使用註冊的「CustomSyslogHeader」:

<outputs>
  <conn formatid="syslog" net="tcp4" addr="server.address:5514" tls="true" insecureskipverify="true" />
</outputs>
<formats>
  <format id="syslog" format="%CustomSyslogHeader(20) %Msg%n"/>
</formats>

使用這個配置後一個日誌記錄器將被建立:

log.Info("Test message!")

輸出爲:

<167>1 2014-05-14T21:39:00+04:00 imp-pcl test 7624 - - Test message!

 

示例:

package main

import (
    log "github.com/cihub/seelog"
    "fmt"
)

func main() {
    defer log.Flush()
    defaultFormat()
    stdFormat()
    dateTimeFormat()
    dateTimeCustomFormat()
    logLevelTypesFormat()
    fileTypesFormat()
    funcFormat()
    xmlFormat()
}

//測試的是默認的格式
func defaultFormat() {
    fmt.Println("Default format")
    
    testConfig := `
<seelog type="sync" />`

    logger, err := log.LoggerFromConfigAsBytes([]byte(testConfig))
    if err != nil {
        fmt.Println(err)
    }
    log.ReplaceLogger(logger)
    
    log.Trace("Test message!")
}

//標準格式
func stdFormat() {
    fmt.Println("Standard fast format")
    
    testConfig := `
<seelog type="sync">
    <outputs formatid="main">
        <console/>
    </outputs>
    <formats>
        <format id="main" format="%Ns [%Level] %Msg%n"/>
    </formats>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("Test message!")
}

//日期和時間的格式默認
func dateTimeFormat() {
    fmt.Println("Date time format")
    
    testConfig := `
<seelog type="sync">
    <outputs formatid="main">
        <console/>
    </outputs>
    <formats>
        <format id="main" format="%Date/%Time [%LEV] %Msg%n"/>
    </formats>
</seelog>`

    logger, err := log.LoggerFromConfigAsBytes([]byte(testConfig))
    
    if err != nil {
        fmt.Println(err)
    }
    
    loggerErr := log.ReplaceLogger(logger)
    
    if loggerErr != nil {
        fmt.Println(loggerErr)
    }
    
    log.Trace("Test message!")
}

//自定義的日期和時間格式
func dateTimeCustomFormat() {
    fmt.Println("Date time custom format")
    
    testConfig := `
<seelog type="sync">
    <outputs formatid="main">
        <console/>
    </outputs>
    <formats>
        <format id="main" format="%Date(2006 Jan 02/3:04:05.000000000 PM MST) [%Level] %Msg%n"/>
    </formats>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("Test message!")
}

//日誌級別類型格式
func logLevelTypesFormat() {
    fmt.Println("Log level types format")
    
    testConfig := `
<seelog type="sync">
    <outputs formatid="main">
        <console/>
    </outputs>
    <formats>
        <format id="main" format="%Level %Lev %LEVEL %LEV %l %Msg%n"/>
    </formats>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("Test message!")
}

//文件類型格式
func fileTypesFormat() {
    fmt.Println("File types format")
    
    testConfig := `
<seelog type="sync">
    <outputs formatid="main">
        <console/>
    </outputs>
    <formats>
        <format id="main" format="%File %FullPath %RelFile %Msg%n"/>
    </formats>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("Test message!")
}

//函數格式
func funcFormat() {
    fmt.Println("Func format")
    
    testConfig := `
<seelog type="sync">
    <outputs formatid="main">
        <console/>
    </outputs>
    <formats>
        <format id="main" format="%Func %Msg%n"/>
    </formats>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.ReplaceLogger(logger)
    
    log.Trace("Test message!")
}

//xml格式
func xmlFormat() {
    fmt.Println("Xml format")

    //等價於<time>%Ns</time><lev>%Lev</lev><msg>%Msg</msg><path>%RelFile</path><func>%Func</func>
    testConfig := `
<seelog type="sync">
    <outputs formatid="main">
        <console/>
    </outputs>
    <formats>
        <format id="main" format="` +
        `&lt;log&gt;` +
             `&lt;time&gt;%Ns&lt;/time&gt;` +
             `&lt;lev&gt;%l&lt;/lev&gt;` +
             `&lt;msg&gt;%Msg&lt;/msg&gt;` +
         `&lt;/log&gt;"/>
    </formats>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))

    log.ReplaceLogger(logger)
    
    log.Trace("Test message!")
}
View Code

返回:

userdeMBP:go-learning user$ go run test.go 
Default format
1551702181896235000 [Trace] Test message!
Standard fast format
1551702181896299000 [Trace] Test message!
Date time format
2019-03-04/20:23:01 [TRC] Test message!
Date time custom format
2019 Mar 04/8:23:01.896487000 PM CST [Trace] Test message!
Log level types format
Trace Trc TRACE TRC t Test message!
File types format
test.go /Users/user/go-learning/test.go test.go Test message!
Func format
main.funcFormat Test message!
Xml format
<log><time>1551702181896732000</time><lev>t</lev><msg>Test message!</msg></log>

 

7.Colorizing output着色輸出

有時你可能想要對終端輸出進行着色。這一般使用CSI n [;k] m序列來完成。

Seelog格式使用XML設置,所以沒法在格式標識符中使用這些序列。可是有一種特殊格式的動詞叫作「EscM」,它以「n[;k]」部分做爲參數。你可使用它來爲終端輸出執行圖形化選項定製。

舉例說明:

<seelog>
    <outputs>
        <console formatid="colored"/>
    </outputs>
    <formats>
        <format id="colored"  format="%EscM(46)%Level%EscM(49) %Msg%n%EscM(0)"/>
    </formats>
</seelog>

使用上面的配置,而後記錄任何消息,日誌級別將有青色背景。46設置背景,49將其重置。

建議

在消息末尾使用%EscM(0)(以及%n)重置全部圖形更改

8.Migration from standard log package從標準日誌包遷移

對於那些但願在已經經過標準pkg使用日誌功能的應用程序中開始使用seelog的人來講,從日誌包遷移到seelog是一項常見的任務。

1)不兼容性

Seelog概念與標準日誌概念不一樣,所以它們不兼容。

例1 : log.Printf。在seelog中沒有相似的函數,由於Printf不攜帶任何日誌級別的信息,因此若是要遷移,不清楚應該怎麼替換log.Printf。多是seelog.Infof或seelog.Debugf 或其餘。

例2 : log.Panicf。它根據格式和panic建立消息,使用格式化的消息做爲panic文本。在seelog中,對任何日誌函數的一次調用均可能產生具備不一樣格式(取決於配置)的多個消息,所以不清楚應該使用什麼做爲panic文本。

例3 : log.SetPrefix。Seelog沒有相似的函數,由於對任何日誌函數(例如Debug)的一次調用均可能產生具備不一樣格式的多個消息,所以使用一個這樣的全局函數是沒有意義的。此外,seelog的核心原則之一是避免經過代碼進行配置。全部配置都是經過配置文件進行的。這樣的函數會打破seelog的概念。

2)結論

目前(Go1.X), seelog不兼容標準日誌包,不能有任何「標準日誌pkg兼容性」的功能。

3)遷移注意點

儘管實際上你不能用seelog替換日誌,而且具備相同的行爲(如前所述,它們只是不兼容),可是你可能但願自動化從日誌到seelog的遷移。咱們建議爲你的項目建立一個替代腳本

遷移腳本示例:

下面是一個Python腳本,它在多個文件中對多個日誌包函數執行一些替換。它能夠做爲存根來知足你本身的替換需求。

import os, sys,shutil,re

changeDir= './test'
openFlags = 'rb'
writeFlags = 'r+b'
encoding = 'utf-8'
backupPostfix = '.backup'

goFilesRx = r'.+\.go$'

patterns = [

(re.compile(ur'''(?P<before>import[\s\S]*?)"log"''', re.U | re.M), 
            ur'''\g<before>log "github.com/cihub/seelog"'''), # change import

(re.compile(ur'''log.Print(?P<after>.*?)''', re.U), 
            ur'''log.Info\g<after>'''), # Print -> Info

(re.compile(ur'''log.Println(?P<after>.*?)''', re.U),
            ur'''log.Info\g<after>'''), # Println -> Info

(re.compile(ur'''log.Printf(?P<after>.*?)''', re.U),
            ur'''log.Infof\g<after>'''), # Printf -> Infof

(re.compile(ur'''(?P<ws>[\t ]*)log.Panic\((?P<values>.*?)\)''', re.U),
            ur'''\g<ws>log.Info(\g<values>)\n\g<ws>panic(fmt.Sprint(\g<values>))'''), # Panic -> Info + panic(...)

(re.compile(ur'''(?P<ws>[\t ]*)log.Panicf\((?P<values>.*?)\)''', re.U),
            ur'''\g<ws>log.Infof(\g<values>)\n\g<ws>panic(fmt.Sprint(\g<values>))'''), # Panicf -> Info + panic(...)

# ... and so on

]

def rewriteFile(fl, text):
   fl.read() # To preserve file creation date
   fl.seek(0)
   fl.write(text.encode(encoding))
   fl.truncate()

def replacePatterns(filePath, backup):
   # Open file and get its contents
   input = open(filePath, openFlags)
   fileText = unicode(input.read(), encoding)
   input.close()

   found = False
   # Make replacements for all patterns
   for pc in patterns:
      origRx = pc[0]
      replRx = pc[1]
      replacedText = re.sub(origRx, replRx, fileText)
      if fileText != replacedText:
         found = True
      fileText = replacedText

   # If any replacements were made, write the changed file
   if found:
      if backup:
         bckName = filePath + backupPostfix
         shutil.copy2(filePath, bckName)

      outF = open(filePath,writeFlags)
      rewriteFile(outF, fileText)
      outF.close()

def replaceFunc(a, dir, files):
   for f in files:
      fPath = dir + '/' + f
      if re.search(goFilesRx, f, re.U) and os.path.isfile(fPath):
         replacePatterns(fPath, True)

os.path.walk(changeDir, replaceFunc, 3)

9.Example config

這個配置沒有任何實際價值,它只是在一個地方演示了大多數功能。有關詳細信息,請查看wiki,它包含每一個seelog特性的描述。要快速參考,請查看參考reference部分。

<seelog type="asynctimer" asyncinterval="5000000" minlevel="debug" maxlevel="error">
    <exceptions>
        <exception funcpattern="*main.test*Something*" minlevel="info"/>
        <exception filepattern="*main.go" minlevel="error"/>
    </exceptions>
    <outputs formatid="main"> //指明其將使用在<formats>中的<format id="main" 處指明的格式來輸出信息,若是裏面的子元素中有定義本身的formatid,將會將其覆蓋
        <console/> //指明將outputs中的日誌內容在輸入到文件、內存、SMTP等的同時還輸出到標準輸出,即終端中

        <splitter formatid="format1"> //指明將輸出以<format id="format1"格式寫到log.log和log2.log文件中
            <file path="log.log"/> 
            <file path="log2.log"/>
        </splitter>
        <splitter formatid="format2"> //splitter用於細分<outputs>日誌格式
            <file path="log3.log"/>
            <file path="log4.log"/>
        </splitter>

        <rollingfile formatid="someformat" type="size" filename="./log/roll.log" maxsize="100" maxrolls="5" /> //指明將輸出以<format id="someformat"格式寫到./log/roll.log 回滾文件中

        <buffered formatid="testlevels" size="10000" flushperiod="1000"> //指明將輸出以<format id="testlevels"格式寫到緩衝區(即內存)中,而後再存儲到./log/bufFileFlush.log文件中
            <file path="./log/bufFileFlush.log"/>
        </buffered>

        <filter levels="error"> //只顯示error日誌級別
            <file path="./log/error.log"/> //寫到該文件中
            <smtp senderaddress="noreply-notification-service@none.org"  //並將日誌內容發送給下面<recipient指定的接收者
                  sendername="Automatic notification service" 
                  hostname="mail.none.org" 
                  hostport="587" 
                  username="nns" 
                  password="123">
                <recipient address="john-smith@none.com"/>
                <recipient address="hans-meier@none.com"/>
            </smtp>
            <conn net="tcp4" addr="server.address:5514" tls="true" insecureskipverify="true" /> //同時也將這個日誌內容經過網絡傳輸到地址server.address:5514上
        </filter>

    </outputs>
    <formats> //這裏就是指定上面對應的日誌內容輸出應該分別使用什麼樣的格式
        <format id="main" format="%Date(2006 Jan 02/3:04:05.000000000 PM MST) [%Level] %Msg%n"/>
        <format id="someformat" format="%Ns [%Level] %Msg%n"/>
        <format id="testlevels" format="%Level %Lev %LEVEL %LEV %l %Msg%n"/>
        <format id="usetags" format="&lt;msg&gt;%Msg&lt;/time&gt;"/>
        <format id="format1" format="%Date/%Time [%LEV] %Msg%n"/>
        <format id="format2" format="%File %FullPath %RelFile %Msg%n"/>
    </formats>
</seelog>

 

10.Logger types reference類型

日誌記錄器類型設置在頂部的「seelog」元素中。屬性名是「type」。

1)Synchronous同步

功能:在調用log func的相同goroutine中處理日誌消息

類型屬性值:Sync

額外屬性:None

舉例說明:

<seelog type="sync">
    ...
</seelog>

 

2)Asynchronous loop異步循環

功能:在單獨的goroutine中處理日誌消息。從「for」循環中的消息隊列獲取消息。

類型屬性值:asyncloop(這是默認類型,因此你能夠忽略「type」屬性)

額外屬性:none

舉例說明,下面的兩種寫法是等價的:

<seelog type="asyncloop">
    ...
</seelog>

等價於:

<seelog>
    ...
</seelog>

3)Asynchronous timer異步計時器

功能:在單獨的goroutine中處理日誌消息。獲取具備指定時間間隔的消息隊列中的消息

類型屬性值:asynctimer

額外屬性:

  • asyncinterval——計時器時間間隔(以納秒爲單位)

舉例說明:

<seelog type="asynctimer" asyncinterval="5000">
    ...
</seelog>

示例:

package main

import (
    "fmt"
    log "github.com/cihub/seelog"
    "strings"
    "time"
)

var longMessage = strings.Repeat("A", 1024*100)

func main() {
    defer log.Flush()
    syncLogger()
    fmt.Println()
    asyncLoopLogger()
    fmt.Println()
    asyncTimerLogger()
}

func syncLogger() {
    fmt.Println("Sync test")

    testConfig := `
<seelog type="sync">
    <outputs>
        <filter levels="trace">
            <file path="log.log"/>
        </filter>
        <filter levels="debug">
            <console />
        </filter>
    </outputs>
</seelog>
`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.UseLogger(logger)

    doTest()
}

func asyncLoopLogger() {
    fmt.Println("Async loop test")

    testConfig := `
<seelog>
    <outputs>
        <filter levels="trace">
            <file path="log.log"/>
        </filter>
        <filter levels="debug">
            <console />
        </filter>
    </outputs>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.UseLogger(logger)

    doTest()

    time.Sleep(1e9)
}

func asyncTimerLogger() {
    fmt.Println("Async timer test")

    testConfig := `
<seelog type="asynctimer" asyncinterval="5000000">
    <outputs>
        <filter levels="trace">
            <file path="log.log"/>
        </filter>
        <filter levels="debug">
            <console />
        </filter>
    </outputs>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
    log.UseLogger(logger)

    doTest()

    time.Sleep(1e9)
}

func doTest() {
    start := time.Now()
    for i := 0; i < 50; i += 2 {
        fmt.Printf("%d\n", i)
        log.Trace(longMessage)
        log.Debugf("%d", i+1)
    }
    end := time.Now()
    dur := end.Sub(start)
    fmt.Printf("Test took %d ns\n", dur)
}
View Code

返回

userdeMBP:go-learning user$ go run test.go 
Sync test //同步進行 0
1551702598965060000 [Debug] 1
2
1551702598965356000 [Debug] 3
4
1551702598965630000 [Debug] 5
6
1551702598965883000 [Debug] 7
8
1551702598966119000 [Debug] 9
10
1551702598966379000 [Debug] 11
12
1551702598966609000 [Debug] 13
14
1551702598966909000 [Debug] 15
16
1551702598967173000 [Debug] 17
18
1551702598967419000 [Debug] 19
20
1551702598968144000 [Debug] 21
22
1551702598968266000 [Debug] 23
24
1551702598968362000 [Debug] 25
26
1551702598968473000 [Debug] 27
28
1551702598968555000 [Debug] 29
30
1551702598968641000 [Debug] 31
32
1551702598968725000 [Debug] 33
34
1551702598968810000 [Debug] 35
36
1551702598968901000 [Debug] 37
38
1551702598968985000 [Debug] 39
40
1551702598969240000 [Debug] 41
42
1551702598969625000 [Debug] 43
44
1551702598969757000 [Debug] 45
46
1551702598969858000 [Debug] 47
48
1551702598969947000 [Debug] 49
Test took 5368269 ns

Async loop test //循環同時獲取日誌消息 0
2
4
1551702598970071000 [Debug] 1
1551702598970077000 [Debug] 3
6
8
10
1551702598970084000 [Debug] 5
1551702598970504000 [Debug] 7
1551702598970511000 [Debug] 9
12
14
16
18
20
1551702598970742000 [Debug] 11
1551702598970755000 [Debug] 13
1551702598970761000 [Debug] 15
1551702598970766000 [Debug] 17
1551702598970772000 [Debug] 19
22
24
1551702598972970000 [Debug] 21
1551702598973067000 [Debug] 23
26
28
1551702598973221000 [Debug] 25
1551702598973232000 [Debug] 27
30
1551702598973481000 [Debug] 29
32
1551702598973598000 [Debug] 31
34
1551702598973706000 [Debug] 33
36
38
1551702598973967000 [Debug] 35
1551702598973974000 [Debug] 37
40
1551702598974162000 [Debug] 39
42
44
1551702598974171000 [Debug] 41
1551702598974376000 [Debug] 43
46
48
1551702598974470000 [Debug] 45
1551702598974476000 [Debug] 47
Test took 4692732 ns
1551702598974482000 [Debug] 49

Async timer test
0
2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
36
38
40
42
44
46
48
Test took 989547 ns //async Timer設置是5000000ns後纔開始讀取日誌消息 1551702599976687000 [Debug] 1
1551702599976713000 [Debug] 3
1551702599976736000 [Debug] 5
1551702599977358000 [Debug] 7
1551702599977372000 [Debug] 9
1551702599977386000 [Debug] 11
1551702599977404000 [Debug] 13
1551702599977418000 [Debug] 15
1551702599977431000 [Debug] 17
1551702599977444000 [Debug] 19
1551702599977458000 [Debug] 21
1551702599977471000 [Debug] 23
1551702599977484000 [Debug] 25
1551702599977497000 [Debug] 27
1551702599977510000 [Debug] 29
1551702599977523000 [Debug] 31
1551702599977537000 [Debug] 33
1551702599977550000 [Debug] 35
1551702599977563000 [Debug] 37
1551702599977576000 [Debug] 39
1551702599977589000 [Debug] 41
1551702599977602000 [Debug] 43
1551702599977615000 [Debug] 45
1551702599977628000 [Debug] 47
1551702599977641000 [Debug] 49

 

4)Asynchronous adaptive異步適應性

功能:相似於異步計時器日誌記錄器,但其間隔取決於隊列中剩下的消息數量。建立這種類型的日誌記錄器是爲了不日誌消息隊列溢出:隊列中的消息越多,獲取它們的速度就越快。在seelogg -example:adaptive_main.go中進行了演示:

package main

import (
    "time"
    log "github.com/cihub/seelog"
)

func main() {
    defer log.Flush()
    loadAdaptiveConfig()
    testMsgIntensity(1)
    testMsgIntensity(5)
    testMsgIntensity(10)
}

func testMsgIntensity(intensity int) {
    log.Default.Infof("Intensity test: %d", intensity)
    
    for j := 0; j < 4; j++ {
        for i := 0; i < intensity; i++ {
            log.Tracef("trace %d", i)
            <-time.After(time.Second / time.Duration(intensity)) //time.Second / time.Duration(5)表示1秒除以5的時間進行一次循環
        }
    }
    
    log.Default.Info("Messages sent")
    
    <-time.After(time.Second * time.Duration(intensity))
}

func loadAdaptiveConfig() {
    testConfig := `<seelog type="adaptive" mininterval="200000000" maxinterval="1000000000" critmsgcount="5">
    <outputs formatid="msg">
        <console/>
    </outputs>
    <formats>
        <format id="msg" format="%Time: %Msg%n"/>
    </formats>
</seelog>`

    logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))

    log.ReplaceLogger(logger)
}

返回:

userdeMBP:go-learning user$ go run test.go 
1551693376581324000 [Info] Intensity test: 1
17:56:16: trace 0
17:56:17: trace 0
17:56:18: trace 0
17:56:19: trace 0
1551693380594712000 [Info] Messages sent
1551693381595019000 [Info] Intensity test: 5
17:56:21: trace 0
17:56:21: trace 1
17:56:21: trace 2
17:56:22: trace 3
17:56:22: trace 4
17:56:22: trace 0
17:56:22: trace 1
17:56:23: trace 2
17:56:23: trace 3
17:56:23: trace 4
17:56:23: trace 0
17:56:23: trace 1
17:56:24: trace 2
17:56:24: trace 3
1551693385632063000 [Info] Messages sent
17:56:24: trace 4
17:56:24: trace 0
17:56:24: trace 1
17:56:25: trace 2
17:56:25: trace 3
17:56:25: trace 4
17:56:30: trace 0
1551693390634801000 [Info] Intensity test: 10
17:56:30: trace 1
17:56:30: trace 2
17:56:30: trace 3
17:56:31: trace 4
17:56:31: trace 5
17:56:31: trace 6
17:56:31: trace 7
17:56:31: trace 8
17:56:31: trace 9
17:56:31: trace 0
17:56:31: trace 1
17:56:31: trace 2
17:56:31: trace 3
17:56:32: trace 4
17:56:32: trace 5
1551693394732474000 [Info] Messages sent
17:56:32: trace 6
17:56:32: trace 7
17:56:32: trace 8
17:56:32: trace 9
17:56:32: trace 0
17:56:32: trace 1
17:56:32: trace 2
17:56:33: trace 3
17:56:33: trace 4
17:56:33: trace 5
17:56:33: trace 6
17:56:33: trace 7
17:56:33: trace 8
17:56:33: trace 9
17:56:33: trace 0
17:56:33: trace 1
17:56:33: trace 2
17:56:34: trace 3
17:56:34: trace 4
17:56:34: trace 5
17:56:34: trace 6
17:56:34: trace 7
17:56:34: trace 8
17:56:34: trace 9

 

若是咱們使用下面的概念:

  • I - 獲取下一項以前的間隔
  • m - 最小間隔
  • M - 極大區間
  • c - 當前消息計數
  • C - 關鍵信息計數

計算間隔的公式爲:

I = m + (C - Min(c, C)) / C * (M - m)

 

類型屬性值:adaptive

額外屬性:

  • mininterval-最小間隔(以納秒爲單位)
  • maxinterval -最大間隔(以納秒爲單位)
  • critmsgcount -關鍵消息計數

舉例說明:

<seelog type="adaptive" mininterval="2000000" maxinterval="1000000000" critmsgcount="500">
    <outputs formatid="msg">
        <console/>
    </outputs>
    <formats>
        <format id="msg" format="%Time: %Msg%n"/>
    </formats>
</seelog>

 

11.簡單舉例:

1)僅將日誌輸出到終端

配置文件seelog.xml爲,參考https://blog.csdn.net/luckytanggu/article/details/80345134:

<seelog type="asynctimer" asyncinterval="1000000" minlevel="debug" maxlevel="error">
    <outputs formatid="main">
        <!-- 僅實現將日誌內容輸出到終端 -->
        <console/>
    </outputs>
    <formats>
        <!-- 設置格式,輸出UTC日期 UTC時間 - 縮寫版大寫日誌級別 - 相對於應用程序運行目錄的調用者路徑 - 日誌記錄器被調用時的行號 - 消息文本(最後換行) -->
        <format id="main" format="%UTCDate %UTCTime - [%LEV] - %RelFile - l%Line - %Msg%n"/>
    </formats>
</seelog>

而後應用爲:

package main

import (
    log "github.com/cihub/seelog"
    "fmt"
)

func main() {
    logger, err := log.LoggerFromConfigAsFile("seelog.xml")
        
    if err != nil {
        fmt.Println("parse seelog.xml error")
    }
        
    log.ReplaceLogger(logger)

    defer log.Flush()
    log.Info("Hello from Seelog!")

}

輸出爲:

userdeMBP:go-learning user$ go run test.go 
2019-03-04 09:19:11 - [INF] - test.go - l20 - Hello from Seelog!

 

2)將日誌輸出到終端和文件中

<seelog type="asynctimer" asyncinterval="1000000" minlevel="debug" maxlevel="error">
    <outputs formatid="main">
        <!-- 僅實現將日誌內容輸出到終端 -->
        <console/>
        <!-- 該文件將使用"format1"格式來覆蓋"main"格式,並將文件信息寫到log.log文件中-->
        <splitter formatid="format1"> 
            <file path="log.log"/>
        </splitter>
    </outputs>
    <formats>
        <!-- 設置格式,輸出UTC日期 UTC時間 - 縮寫版大寫日誌級別 - 相對於應用程序運行目錄的調用者路徑 - 日誌記錄器被調用時的行號 - 消息文本(最後換行) -->
        <format id="main" format="%UTCDate %UTCTime - [%LEV] - %RelFile - l%Line - %Msg%n"/>
        <!-- 格式爲以2006 Jan 02/3:04:05.000000000 PM MST格式輸出日期 正常的日誌級別 消息文本(最後換行)-->
        <format id="format1" format="%Date(2006 Jan 02/3:04:05.000000000 PM MST) [%Level] %Msg%n"/>
    </formats>
</seelog>

而後返回:

userdeMBP:go-learning user$ go run test.go 
2019-03-04 09:28:35 - [INF] - test.go - l20 - Hello from Seelog!

日誌文件中的輸出爲:

userdeMBP:go-learning user$ cat log.log 
2019 Mar 04/5:28:35.215823000 PM CST [Info] Hello from Seelog!
相關文章
相關標籤/搜索