Dowiedz się, jak zalogować się w języku Go

Ukończone

Dzienniki odgrywają znaczącą rolę w programie, ponieważ stają się źródłem informacji, które można sprawdzić, gdy coś pójdzie nie tak. Zazwyczaj w przypadku wystąpienia błędu użytkownicy końcowi widzą tylko komunikat wskazujący problem z programem. Z perspektywy dewelopera potrzebujemy więcej informacji niż prosty komunikat o błędzie. Dzieje się tak głównie dlatego, że chcemy odtworzyć problem, aby napisać właściwą poprawkę. W tym module dowiesz się, jak działa rejestrowanie w języku Go. Poznasz również kilka rozwiązań, które należy zawsze implementować.

Pakiet log

Na początek język Go oferuje prosty standardowy pakiet do pracy z dziennikami. Można go używać w taki sposób, jak używasz fmt pakietu. Pakiet standardowy nie zapewnia poziomów dzienników i nie pozwala konfigurować oddzielnych rejestratorów dla każdego pakietu. Jeśli musisz napisać bardziej złożone konfiguracje rejestrowania, możesz to zrobić przy użyciu platformy rejestrowania. Później omówimy struktury rejestrowania.

Oto najprostszy sposób używania dzienników:

import (
    "log"
)

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

Po uruchomieniu poprzedniego kodu uzyskasz następujące dane wyjściowe:

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

Domyślnie log.Print() funkcja zawiera datę i godzinę jako prefiks komunikatu dziennika. To samo zachowanie można uzyskać przy użyciu polecenia fmt.Print(), ale możesz wykonać inne czynności z pakietem log , takie jak wysyłanie dzienników do pliku. Później przyjrzymy się więcej log funkcji pakietu.

Możesz użyć log.Fatal() funkcji , aby zarejestrować błąd i zakończyć program tak, jakby był używany os.Exit(1). Aby spróbować, użyjmy tego fragmentu kodu:

package main

import (
    "fmt"
    "log"
)

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

Po uruchomieniu poprzedniego kodu uzyskasz następujące dane wyjściowe:

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

Zwróć uwagę, że ostatni wiersz , fmt.Print("Can you see me?")nie jest uruchamiany. Dzieje się tak, ponieważ log.Fatal() wywołanie funkcji zatrzymuje program. Podobne zachowanie występuje podczas korzystania z log.Panic() funkcji, która wywołuje również panic() funkcję, w następujący sposób:

package main

import (
    "fmt"
    "log"
)

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

Po uruchomieniu poprzedniego kodu uzyskasz następujące dane wyjściowe:

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

Nadal otrzymujesz komunikat dziennika, ale teraz jest również wyświetlany ślad stosu błędów.

Inną podstawową funkcją jest log.SetPrefix(). Można go użyć do dodania prefiksu do komunikatów dziennika programu. Możesz na przykład użyć tego fragmentu kodu:

package main

import (
    "log"
)

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

Po uruchomieniu poprzedniego kodu uzyskasz następujące dane wyjściowe:

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

Prefiks zostanie ustawiony raz, a dzienniki będą zawierać informacje takie jak nazwa funkcji, z której pochodzi dziennik.

Inne funkcje można eksplorować w witrynie internetowej Języka Go.

Rejestrowanie w pliku

Oprócz drukowania dzienników w konsoli programu można wysłać dzienniki do pliku, aby można je było przetworzyć później lub w czasie rzeczywistym.

Dlaczego chcesz wysyłać dzienniki do pliku? Najpierw możesz ukryć określone informacje przed użytkownikami końcowymi. Mogą one nie być zainteresowane lub mogą ujawniać poufne informacje. Gdy masz dzienniki w plikach, możesz scentralizować wszystkie dzienniki w jednej lokalizacji i skorelować je z innymi zdarzeniami. Ten wzorzec jest typowy: aby mieć aplikacje rozproszone, które mogą być efemeryczne, takie jak kontenery.

Użyjmy następującego kodu, aby przetestować wysyłanie dzienników do pliku:

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!")
}

Po uruchomieniu poprzedniego kodu nie widzisz niczego w konsoli programu . W katalogu powinien zostać wyświetlony nowy plik o nazwie info.log zawierający dzienniki wysyłane za pomocą log.Print() funkcji . Zwróć uwagę, że musisz zacząć od utworzenia lub otwarcia pliku, a następnie skonfigurowania log pakietu w celu wysłania wszystkich danych wyjściowych do pliku. Następnie możesz kontynuować korzystanie z log.Print() funkcji, jak zwykle.

Struktury rejestrowania

Na koniec może wystąpić czas, kiedy log funkcje pakietu nie są wystarczające. Warto użyć struktury rejestrowania zamiast pisania własnych bibliotek. Kilka struktur rejestrowania dla języka Go to Logrus, zerolog, zap i Apex.

Przyjrzyjmy się, co możemy zrobić za pomocą zerologu.

Najpierw należy zainstalować pakiet. Jeśli pracujesz w tej serii, prawdopodobnie używasz już modułów języka Go, więc nie musisz nic robić. W takim przypadku możesz uruchomić to polecenie na stacji roboczej, aby zainstalować biblioteki zerolog:

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

Teraz użyj tego fragmentu kodu, aby spróbować:

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!")
}

Po uruchomieniu poprzedniego kodu uzyskasz następujące dane wyjściowe:

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

Zwróć uwagę, że po prostu musisz uwzględnić poprawne nazwy importu, a następnie nadal korzystać z log.Print() funkcji, jak zwykle. Zwróć również uwagę, jak dane wyjściowe zmieniają się w formacie JSON. Kod JSON jest przydatnym formatem dzienników podczas uruchamiania wyszukiwań w centralnej lokalizacji.

Inną przydatną funkcją jest możliwość szybkiego uwzględnienia danych kontekstowych, takich jak:

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

Po uruchomieniu poprzedniego kodu uzyskasz następujące dane wyjściowe:

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

Zwróć uwagę, jak dodaliśmy jako kontekst identyfikator pracownika. Staje się częścią logline jako innej właściwości. Ważne jest również, aby podkreślić, że uwzględnione pola są silnie typizowane.

Można zaimplementować inne funkcje z dziennikiem zerowym, takie jak używanie rejestrowania wyrównanego, przy użyciu sformatowanych śladów stosu i używanie więcej niż jednego wystąpienia rejestratora do zarządzania różnymi danymi wyjściowymi. Aby uzyskać więcej informacji, zobacz witrynę usługi GitHub.