Bejelentkezés Go:

Viszonylag új vagy a Go nyelvben. Valószínűleg webes alkalmazás vagy szerver írására használod, és naplófájlt kell létrehoznod. Ezért gyorsan rákeresel a weben, és rájössz, hogy a go-ban rengeteg lehetőség van a naplózásra. Honnan tudod, hogy melyiket válaszd? Ez a cikk felvértezi Önt, hogy megválaszolja ezt a kérdést.

Megnézzük a beépített log csomagot, és meghatározzuk, hogy milyen projektekre alkalmas, mielőtt megvizsgálnánk a Go ökoszisztémában elterjedt egyéb naplózási megoldásokat.

Mit kell naplózni

Nem kell mondanom, mennyire fontos a naplózás. A naplókat minden termelő webes alkalmazás használja, hogy segítse a fejlesztőket és az üzemeltetést:

  • Feltárja a hibákat az alkalmazás kódjában
  • Teljesítményproblémák felfedezése
  • Kiesések és biztonsági incidensek utólagos elemzése

Az, hogy ténylegesen milyen adatokat naplózol, attól függ, hogy milyen típusú alkalmazást építesz. Legtöbbször az alábbiak közül valamilyen variációval fog rendelkezni:

  • Az esemény bekövetkezésének vagy a napló generálásának időbélyege
  • Naplózási szintek, például debug, error vagy info
  • Kontextuális adatok, amelyek segítenek megérteni, mi történt, és lehetővé teszik a helyzet egyszerű reprodukálását

Mit nem szabad naplózni

Általában nem szabad semmilyen érzékeny üzleti adatot vagy személyazonosításra alkalmas információt naplózni. Ide tartoznak többek között:

  • Nevek
  • IP-címek
  • Hitelkártyaszámok

Ezek a korlátozások mérnöki szempontból kevésbé hasznossá tehetik a naplókat, de biztonságosabbá teszik az alkalmazást. Sok esetben az olyan előírások, mint a GDPR és a HIPAA tilthatják a személyes adatok naplózását.

A log csomag bemutatása

A Go szabványkönyvtár rendelkezik egy beépített log csomaggal, amely a legtöbb alapvető naplózási funkciót biztosítja. Bár nem rendelkezik naplózási szintekkel (például debug, warning vagy error), mégis mindent biztosít, ami egy alapvető naplózási stratégia beállításához szükséges.

Itt a legalapvetőbb naplózási példa:

package mainimport "log"func main() { log.Println("Hello world!")}

A fenti kód kiírja a “Hello world!” a standard hibaüzenetre, de tartalmazza a dátumot és az időt is, ami praktikus a naplóüzenetek dátum szerinti szűréséhez.

2019/12/09 17:21:53 Hello world!

A log csomag alapértelmezés szerint a standard hiba (stderr) kimeneti folyamra ír, de elérhetjük, hogy a helyi fájlba vagy bármilyen más, a io.Writer interfészt támogató célba írjon. Emellett minden további beállítás nélkül hozzáad egy időbélyeget a naplóüzenethez.

Naplózás egy fájlba

Ha a naplóüzeneteket egy fájlban kell tárolni, akkor ezt egy új fájl létrehozásával vagy egy meglévő fájl megnyitásával és a napló kimenetének beállításával teheti meg. Íme egy példa:

package mainimport ( "log" "os")func main() { // If the file doesn't exist, create it or append to the file file, err := os.OpenFile("logs.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) if err != nil { log.Fatal(err) } log.SetOutput(file) log.Println("Hello world!")}

A kód futtatásakor az alábbiakat írja ki a logs.txt.

2019/12/09 17:22:47 Hello world!

Amint korábban említettük, a naplófájlokat alapvetően bármilyen, a io.Writer interfészt megvalósító rendeltetési helyre kiadhatjuk, így nagy rugalmassággal dönthetünk arról, hogy az alkalmazásunkban hova naplózzuk az üzeneteket.

Egyéni naplózók létrehozása

Noha a log csomag egy előre definiált logger-et implementál, amely a standard hibába ír, a log.New() módszerrel létrehozhatunk egyéni naplózó típusokat.

Az új naplózó létrehozásakor három argumentumot kell átadnunk a log.New()-nak:

  • out: Bármilyen típus, amely megvalósítja a io.Writer interfészt, ahová a naplóadatok íródnak
  • prefix: Egy karakterlánc, amelyet minden naplósor elejére csatolnak
  • flag: Egy konstanskészlet, amely lehetővé teszi számunkra, hogy meghatározzuk, milyen naplózási tulajdonságokat tartalmazzon minden egyes naplóbejegyzés, amelyet a naplózó generál (erről bővebben a következő szakaszban)

Ezt a funkciót kihasználva egyéni naplózókat hozhatunk létre. Íme egy példa, amely a Info, Warning és Error naplózókat valósítja meg:

package mainimport ( "log" "os")var ( WarningLogger *log.Logger InfoLogger *log.Logger ErrorLogger *log.Logger)func init() { file, err := os.OpenFile("logs.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) if err != nil { log.Fatal(err) } InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) WarningLogger = log.New(file, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile) ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)}func main() { InfoLogger.Println("Starting the application...") InfoLogger.Println("Something noteworthy happened") WarningLogger.Println("There is something you should know about") ErrorLogger.Println("Something went wrong")}

A logs.txt fájl létrehozása vagy megnyitása után a init függvény tetején lévő logs.txt fájl létrehozása vagy megnyitása után inicializáljuk a három meghatározott naplózót a kimeneti cél, a prefix string és a naplózási zászlók megadásával.

A main függvényben a naplózókat a Println függvény meghívásával használjuk, amely új naplóbejegyzést ír a naplófájlba. A program futtatásakor az alábbiakat írja a logs.txt-be.

INFO: 2019/12/09 12:01:06 main.go:26: Starting the application...INFO: 2019/12/09 12:01:06 main.go:27: Something noteworthy happenedWARNING: 2019/12/09 12:01:06 main.go:28: There is something you should know aboutERROR: 2019/12/09 12:01:06 main.go:29: Something went wrong

Megjegyezzük, hogy ebben a példában egyetlen fájlba naplózunk, de minden naplózóhoz külön fájlt használhatunk, ha a naplózó létrehozásakor más fájlt adunk meg.

Log flags

A log flag konstansok segítségével további kontextuális információk, például a fájl, a sorszám, a dátum és az idő megadásával gazdagíthatjuk a naplóüzenetet. Például a “Valami baj történt” üzenet átadása egy naplózón keresztül az alábbi flag-kombinációval:

log.Ldate|log.Ltime|log.Lshortfile

kiírja

2019/12/09 12:01:06 main.go:29: Something went wrong

A megjelenés sorrendjét és formátumát sajnos nem lehet befolyásolni.

Naplózási keretrendszerek bevezetése

A log csomag használata nagyszerű a helyi fejlesztésekhez, amikor a gyors visszajelzés fontosabb, mint a gazdag, strukturált naplók generálása. Ezen túlmenően többnyire valószínűleg jobban jársz egy naplózási keretrendszer használatával.

A naplózási keretrendszer használatának nagy előnye, hogy segít a naplóadatok szabványosításában. Ez azt jelenti, hogy:

  • Egyszerűbb olvasni és megérteni a naplóadatokat.
  • Egyszerűbb több forrásból összegyűjteni a naplókat, és egy központi platformra táplálni őket elemzésre.

A naplózás emellett nagyjából megoldott probléma. Miért kellene újra feltalálni a kereket?

Naplózási keretrendszer kiválasztása

Az, hogy melyik keretrendszert használjuk, kihívást jelenthet, mivel számos lehetőség közül választhatunk.

A Go két legnépszerűbb naplózási keretrendszerének a beglog és a logrus tűnik. A glog népszerűsége meglepő, mivel több éve nem frissítették. a logrus jobban karbantartott és olyan népszerű projektekben használják, mint a Docker, ezért erre fogunk koncentrálni.

Kezdés a logrusszal

A logrus telepítése olyan egyszerű, mint az alábbi parancs futtatása a terminálban:

go get "github.com/Sirupsen/logrus"

A logrus egyik nagyszerű tulajdonsága, hogy teljesen kompatibilis a szabványos könyvtár log csomagjával, így a log importját mindenhol lecserélheti log "github.com/sirupsen/logrus"-re, és egyszerűen működni fog!

Módosítsuk a korábbi “hello world” példánkat, amely a log csomagot használta, és használjuk helyette a logrus-t:

package mainimport ( log "github.com/sirupsen/logrus")func main() { log.Println("Hello world!")}

A kód futtatása a következő kimenetet eredményezi:

INFO Hello world!

Egyszerűbb már nem is lehetne!

A JSON-ban történő naplózás

logrus jól használható JSON-ban történő strukturált naplózáshoz, ami – mivel a JSON egy jól definiált szabvány – megkönnyíti a külső szolgáltatások számára a naplók elemzését, és viszonylag egyszerűvé teszi a naplóüzenetek kontextusának hozzáadását is a mezők használatával, ahogy az alább látható:

package mainimport ( log "github.com/sirupsen/logrus")func main() { log.SetFormatter(&log.JSONFormatter{}) log.WithFields( log.Fields{ "foo": "foo", "bar": "bar", }, ).Info("Something happened")}

A létrehozott napló kimenet egy JSON objektum lesz, amely tartalmazza az üzenetet, a naplószintet, az időbélyeget és a bevont mezőket.

{"bar":"bar","foo":"foo","level":"info","msg":"Something happened","time":"2019-12-09T15:55:24+01:00"}

Ha nem érdekel a naplóid JSON-ként történő kiadása, vedd figyelembe, hogy a logrushoz számos harmadik féltől származó formázó létezik, amelyeket a Github-oldalán tekinthetsz meg. Ha szeretné, akár saját formázót is írhat.

Naplószintek

A standard naplócsomagtól eltérően a logrus támogatja a naplószinteket.

A logrus hét naplószintet tartalmaz: Trace, Debug, Info, Warn, Error, Fatal és Panic. Az egyes szintek súlyossága a listán lefelé haladva növekszik.

log.Trace("Something very low level.")log.Debug("Useful debugging information.")log.Info("Something noteworthy happened!")log.Warn("You should probably take a look at this.")log.Error("Something failed but I'm not quitting.")// Calls os.Exit(1) after logginglog.Fatal("Bye.")// Calls panic() after logginglog.Panic("I'm bailing.")

A naplózási szint beállításával a loggeren csak azokat a bejegyzéseket naplózhatja, amelyekre a környezetétől függően szüksége van. Alapértelmezés szerint a logrus mindent naplóz, ami Info vagy annál magasabb (Warn, Error, Fatal vagy Panic).

package mainimport ( log "github.com/sirupsen/logrus")func main() { log.SetFormatter(&log.JSONFormatter{}) log.Debug("Useful debugging information.") log.Info("Something noteworthy happened!") log.Warn("You should probably take a look at this.") log.Error("Something failed but I'm not quitting.")}

A fenti kód futtatása a következő kimenetet eredményezi:

{"level":"info","msg":"Something noteworthy happened!","time":"2019-12-09T16:18:21+01:00"}{"level":"warning","msg":"You should probably take a look at this.","time":"2019-12-09T16:18:21+01:00"}{"level":"error","msg":"Something failed but I'm not quitting.","time":"2019-12-09T16:18:21+01:00"}

Megjegyezzük, hogy a Debug szintű üzenet nem került kiírásra. Ahhoz, hogy felvegyük a naplóba, állítsuk a log.Level értékét log.DebugLevel-nek:

log.SetLevel(log.DebugLevel)

Wrap up

Ebben a bejegyzésben a beépített naplócsomag használatát vizsgáltuk, és megállapítottuk, hogy azt csak triviális alkalmazásokhoz vagy egy gyors prototípus készítésekor érdemes használni. Minden máshoz elengedhetetlen egy mainstream naplózási keretrendszer használata.

Megnéztük azt is, hogyan biztosíthatjuk, hogy a naplóinkban szereplő információk konzisztensek és könnyen elemezhetőek legyenek, különösen, ha azokat egy központi platformon aggregáljuk.

Köszönjük az olvasást!

Leave a Reply