了解如何登入 Go

已完成

記錄在程式中扮演重要的角色,因為它們會成為資訊來源,以便您在發生問題時加以檢查。 通常,發生錯誤時,終端使用者只會看到指出程式有問題的訊息。 從開發人員的觀點來看,我們需要的不只是簡單的錯誤訊息而已。 這主要是因為我們想要重現問題,以撰寫適當的修正程式。 在本課程模組中,您將了解記錄在 Go 中的運作方式。 您也會學到幾個應該一律採行的做法。

log 套件

針對初學者,Go 提供簡單的標準套件來處理記錄。 您可透過使用 fmt 套件的相同方式來使用該套件。 標準套件不提供記錄層級,也無法讓您為每個套件設定個別的記錄器。 如果您需要撰寫更複雜的記錄設定,可以使用紀錄架構來進行。 我們稍後會討論紀錄架構。

以下是使用記錄的最簡單方式:

import (
    "log"
)

func main() {
    log.Print("Hey, I'm a log!")
}

當您執行上述程式碼時,會取得此輸出:

2020/12/19 13:39:17 Hey, I'm a log!

根據預設,log.Print() 函式會包含日期和時間做為記錄訊息的前置詞。 您可以使用 fmt.Print() 來取得相同的行為,但您可以使用 log 套件來進行其他作業,例如將記錄傳送至檔案。 稍後我們將探討更多 log 套件功能。

您可以使用 log.Fatal() 函式以記錄錯誤並結束程式,就像您使用的 os.Exit(1) 一樣。 若要試試看,請使用下列程式碼片段:

package main

import (
    "fmt"
    "log"
)

func main() {
    log.Fatal("Hey, I'm an error log!")
    fmt.Print("Can you see me?")
}

當您執行上述程式碼時,會取得此輸出:

2020/12/19 13:53:19  Hey, I'm an error log!
exit status 1

請注意,最後一行 fmt.Print("Can you see me?") 未執行。 這是因為 log.Fatal() 函式呼叫會停止程式。 當您使用 log.Panic() 函式時,會取得類似的行為,該函式也會呼叫 panic() 函式,如下所示:

package main

import (
    "fmt"
    "log"
)

func main() {
    log.Panic("Hey, I'm an error log!")
    fmt.Print("Can you see me?")
}

當您執行上述程式碼時,會取得此輸出:

2020/12/19 13:53:19  Hey, I'm an error log!
panic: Hey, I'm an error log!

goroutine 1 [running]:
log.Panic(0xc000060f58, 0x1, 0x1)
        /usr/local/Cellar/go/1.15.5/libexec/src/log/log.go:351 +0xae
main.main()
        /Users/christian/go/src/helloworld/logs.go:9 +0x65
exit status 2

您仍會取得記錄訊息,但現在也會取得錯誤堆疊追蹤。

另一個重要函式是 log.SetPrefix()。 您可以使用該函式,將前置詞新增至程式的記錄訊息。 例如,您可以使用下列程式碼片段:

package main

import (
    "log"
)

func main() {
    log.SetPrefix("main(): ")
    log.Print("Hey, I'm a log!")
    log.Fatal("Hey, I'm an error log!")
}

當您執行上述程式碼時,會取得此輸出:

main(): 2021/01/05 13:59:58 Hey, I'm a log!
main(): 2021/01/05 13:59:58 Hey, I'm an error log!
exit status 1

您只需要設定一次前置詞,您的記錄會包含記錄所使用的函式名稱等資訊。

您可以探索 Go 網站上的其他函式

記錄至檔案

除了將記錄列印至主控台,您也可以將記錄傳送至檔案,以便稍後或即時進行處理。

為什麼要將記錄傳送至檔案? 首先,您可能會想向終端使用者隱藏特定資訊。 因為他們可能對這些資訊不感興趣,或您可能會公開機密資訊。 當您將記錄存放在檔案中時,便可以將所有記錄集中到單一位置,並將其與其他事件相互關聯。 這種模式很常見,例如容器這類暫時性的分散式應用程式。

讓我們使用下列程式碼來測試將記錄傳送至檔案:

package main

import (
    "log"
    "os"
)

func main() {
    file, err := os.OpenFile("info.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }

    defer file.Close()

    log.SetOutput(file)
    log.Print("Hey, I'm a log!")
}

當您執行上述程式碼時,不會在主控台看到任何內容。 在您的目錄中,您應該會看到名為 info.log 的新檔案,其中包含您使用 log.Print() 函式傳送的記錄。 請注意,您必須先建立或開啟檔案,然後設定 log 套件將所有輸出傳送至檔案。 然後您就可以照常繼續使用 log.Print() 函式。

記錄架構

最後,log 套件的函式有時候可能不夠用。 您可能會發現,與其撰寫自己的程式庫,還不如使用紀錄架構。 Go 的幾個紀錄架構包括 Logruszerologzap 以及 Apex 等。

讓我們來探索可使用 zerolog 進行的作業。

首先,您需要安裝套件。 如果您一直在進行此系列,則可能已經在使用 Go 模組,因此不需要執行任何動作。 為了以防萬一,您可以在工作站上執行此命令,以安裝 zerolog 程式庫:

go get -u github.com/rs/zerolog/log

現在,請使用此程式碼片段試試看:

package main

import (
    "github.com/rs/zerolog"
    "github.com/rs/zerolog/log"
)

func main() {
    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
    log.Print("Hey! I'm a log message!")
}

當您執行上述程式碼時,會取得此輸出:

{"level":"debug","time":1609855453,"message":"Hey! I'm a log message!"}

請注意,您只需要包含正確的匯入名稱,然後就可照常繼續使用 log.Print() 函式。 此外,請注意輸出內容如何變更為 JSON 格式。 當您在集中式位置執行搜尋時,JSON 是有用的記錄格式。

另一個有用的功能是,您可以快速地加入內容資料,如下所示:

package main

import (
    "github.com/rs/zerolog"
    "github.com/rs/zerolog/log"
)

func main() {
    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

    log.Debug().
        Int("EmployeeID", 1001).
        Msg("Getting employee information")

    log.Debug().
        Str("Name", "John").
        Send()
}

當您執行上述程式碼時,會取得此輸出:

{"level":"debug","EmployeeID":1001,"time":1609855731,"message":"Getting employee information"}
{"level":"debug","Name":"John","time":1609855731}

請注意,我們如何為員工識別碼新增內容。 它會成為記錄行的一部分,做為另一個屬性。 此外,必須強調的是,您所加入的欄位是強型別。

您可以使用 zerolog 來實作其他功能,例如使用分級記錄、使用已格式化的堆疊追蹤,以及使用一個以上的記錄器執行個體來管理不同的輸出。 如需詳細資訊,請參閱 GitHub 網站