Kirjautuminen Go:

Olet suhteellisen uusi Go-kielessä. Käytät sitä luultavasti verkkosovelluksen tai palvelimen kirjoittamiseen, ja sinun on luotava lokitiedosto. Teet siis nopean web-haun ja huomaat, että Go:ssa on valtavasti vaihtoehtoja lokitiedostojen tekemiseen. Mistä tiedät, minkä valitset? Tämä artikkeli varustaa sinut vastaamaan tähän kysymykseen.

Katsomme sisäänrakennettua log-pakettia ja määrittelemme, mihin projekteihin se soveltuu, ennen kuin tutkimme muita Go:n ekosysteemissä vallitsevia lokitusratkaisuja.

Mitä pitää lokata

Minulle ei tarvitse kertoa, kuinka tärkeää lokitus on. Lokeja käytetään jokaisessa tuotantoverkkosovelluksessa auttamaan kehittäjiä ja operaattoreita:

  • Havaitsemaan virheitä sovelluksen koodissa
  • Havaitsemaan suorituskykyongelmia
  • Tekemään jälkianalyysejä käyttökatkoksista ja tietoturvatapahtumista

Tosiasiallisesti loggaamasi tiedot riippuvat siitä, minkä tyyppistä sovellusta olet rakentamassa. Useimmiten sinulla on jonkinlaista vaihtelua seuraavista:

  • Aikaleima siitä, milloin tapahtuma tapahtui tai loki luotiin
  • Lokin tasot, kuten debug-, error- tai info-tasot
  • Yhteystietoja, jotka auttavat ymmärtämään, mitä tapahtui, ja mahdollistavat tilanteen helpon toistamisen

Mitä ei kannata lokata

Yleisesti ottaen sinun ei kannata lokata mitään arkaluonteisia liiketoimintatietoja tai henkilökohtaisesti tunnistettavia tietoja. Näitä ovat muun muassa:

  • Nimet
  • IP-osoitteet
  • Luottokorttinumerot

Nämä rajoitukset voivat tehdä lokitiedostoista vähemmän käyttökelpoisia teknisen suunnittelun näkökulmasta, mutta ne tekevät sovelluksestasi turvallisemman. Monissa tapauksissa GDPR:n ja HIPAA:n kaltaiset säädökset saattavat kieltää henkilötietojen kirjaamisen.

Logipaketin esittely

Gon standardikirjastossa on sisäänrakennettu logpaketti, joka tarjoaa perustavanlaatuisimmat lokiominaisuudet. Vaikka siinä ei ole lokitasoja (kuten debug, warning tai error), se tarjoaa kuitenkin kaiken, mitä tarvitset peruslogausstrategian käyttöönottoon.

Tässä on yksinkertaisin esimerkki loggauksesta:

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

Yllä oleva koodi tulostaa tekstin ”Hello world!”.” vakiovirheeseen, mutta se sisältää myös päivämäärän ja kellonajan, mikä on kätevää lokiviestien suodattamisessa päivämäärän mukaan.

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

Paketti log tulostaa oletusarvoisesti vakiovirheiden (stderr) ulostulovirtaan, mutta voit saada sen kirjoittamaan paikallisiin tiedostoihin tai mihin tahansa määränpäähän, joka tukee io.Writer-rajapintaa. Se lisää myös aikaleiman lokiviestiin ilman lisämäärityksiä.

Loggaaminen tiedostoon

Jos haluat tallentaa lokiviestit tiedostoon, voit tehdä sen luomalla uuden tiedoston tai avaamalla olemassa olevan tiedoston ja asettamalla sen lokin tulosteeksi. Tässä on esimerkki:

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

Kun suoritamme koodin, seuraava kirjoitetaan tiedostoon logs.txt.

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

Kuten aiemmin mainittiin, voit periaatteessa tulostaa lokit mihin tahansa määränpäähän, joka toteuttaa io.Writer-rajapinnan, joten sinulla on paljon liikkumavaraa päättäessäsi, minne lokiviestit kirjataan sovelluksessasi.

Kustomoitujen lokien luominen

Vaikka log-paketti toteuttaa valmiiksi määritellyn logger:n, joka kirjoittaa vakiovirheeseen, voimme luoda mukautettuja lokityyppejä log.New()-metodin avulla.

Uutta lokia luodessasi sinun täytyy välittää kolme argumenttia log.New():

  • out: Mikä tahansa tyyppi, joka toteuttaa io.Writer-rajapinnan, johon lokitiedot kirjoitetaan
  • prefix: Merkkijono, joka liitetään jokaisen lokirivin alkuun
  • flag: Joukko vakioita, joiden avulla voimme määritellä, mitkä lokiominaisuudet sisällytetään kuhunkin lokin tuottamaan lokimerkintään (tästä lisää seuraavassa kappaleessa)

Voitamme hyödyntää tätä ominaisuutta luodaksemme mukautettuja lokimerkintöjä. Tässä on esimerkkinä esimerkki, joka toteuttaa Info-, Warning– ja Error-loggerit:

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

Luotuamme tai avattuamme logs.txt-tiedoston init-toiminnon yläosassa alustamme kolme määriteltyä loggaajaa antamalla tulostuskohteen, etuliite-merkkijonon ja loki-liput.

Funktiossa main loggaajia hyödynnetään kutsumalla funktiota Println, joka kirjoittaa uuden lokimerkinnän lokitiedostoon. Kun suoritat tämän ohjelman, seuraava kirjoitetaan tiedostoon logs.txt.

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

Huomaa, että tässä esimerkissä kirjaamme lokin yhteen tiedostoon, mutta voit käyttää erillistä tiedostoa kullekin lokimerkille välittämällä eri tiedoston lokimerkkiä luodessasi.

Log flags

Log flag -vakiot voit käyttää lokilippuvakioita lokiviestin rikastuttamiseen antamalla ylimääräisiä asiayhteyteen kuuluvia tietoja, kuten tiedoston, rivinumeron, päivämäärän ja ajan. Esimerkiksi viestin ”Jotain meni pieleen” kuljettaminen loggaajan läpi alla esitetyllä lippukombinaatiolla:

log.Ldate|log.Ltime|log.Lshortfile

tulostaa

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

Näyttämisjärjestykseen tai esitysmuotoon ei valitettavasti voi vaikuttaa.

Lokituskehysten käyttöönotto

Paketin log käyttäminen sopii erinomaisesti paikalliseen kehitystyöhön, kun nopean palautteen saaminen on tärkeämpää kuin runsaiden, jäsenneltyjen lokien tuottaminen. Sen jälkeen sinun on useimmiten todennäköisesti parempi käyttää lokikehystä.

Lokituskehyksen käyttämisen suuri etu on se, että se auttaa vakioimaan lokitiedot. Tämä tarkoittaa, että:

  • Lokitietoja on helpompi lukea ja ymmärtää.
  • Lokitietoja on helpompi kerätä useista eri lähteistä ja syöttää ne keskitettyyn alustaan analysoitavaksi.

Loggaaminen on lisäksi melko pitkälti ratkaistu ongelma. Miksi keksiä pyörä uudelleen?

Loggauskehyksen valitseminen

Päätöksenteko siitä, mitä kehystä käyttää, voi olla haastavaa, sillä vaihtoehtoja on useita.

Kaksi suosituinta Go:n loggauskehystä näyttävät olevan beglog ja logrus. Beglogin suosio on yllättävää, sillä sitä ei ole päivitetty moneen vuoteen. logrus on paremmin ylläpidetty ja sitä käytetään suosituissa projekteissa kuten Dockerissa, joten keskitymme siihen.

Aloittaminen logrusin kanssa

Logrusin asentaminen on yhtä yksinkertaista kuin alla olevan komennon suorittaminen terminaalissa:

go get "github.com/Sirupsen/logrus"

Yksi hieno asia logrusissa on se, että se on täysin yhteensopiva standardikirjaston log-paketin log:n kanssa, joten voit korvata login tuonnit joka paikassa log "github.com/sirupsen/logrus":llä, ja se vain toimii!

Muutetaan aiempaa ”hello world”-esimerkkiämme, joka käytti log-pakettia, ja käytetään sen sijaan logrusta:

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

Tämän koodin suorittaminen tuottaa tulosteen:

INFO Hello world!

Et voisi olla enää helpompaa!

Loggaaminen JSON:na

logrus soveltuu hyvin JSON:na tapahtuvaan strukturoituun lokitiedostoon, joka – koska JSON on hyvin määritelty standardi – helpottaa ulkoisia palveluita jäsentämään lokitiedostojasi ja tekee myös kontekstin lisäämisestä lokiviestiin suhteellisen suoraviivaista kenttien avulla, kuten alla on esitetty:

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

Tuotettu lokitiedostotuloste on JSON-olio, joka sisältää viestin, lokitason, aikaleiman ja mukana olevat kentät.

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

Jos et ole kiinnostunut tuottamaan lokejasi JSON-muodossa, ota huomioon, että logrukselle on olemassa useita kolmannen osapuolen muotoilijoita, joita voit tarkastella sen Github-sivulla. Voit halutessasi jopa kirjoittaa oman muotoilijasi.

Logitasot

Vakiolokipaketista poiketen logrus tukee lokitasoja.

logruksessa on seitsemän lokitasoa: Trace, Debug, Info, Warn, Error, Fatal ja Panic. Kunkin tason vakavuusaste kasvaa listaa alaspäin mentäessä.

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.")

Asettamalla lokitason logrukselle voit lokata vain ne merkinnät, joita tarvitset ympäristöstäsi riippuen. Oletusarvoisesti logrus kirjaa kaiken, mikä on tasolla Info tai korkeampi (Warn, Error, Fatal tai 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.")}

Yllä olevan koodin suorittaminen tuottaa seuraavan tulosteen:

{"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"}

Huomaa, että Debug-tason viestiä ei tulostettu. Jos haluat sisällyttää sen lokiin, aseta log.Level arvoksi log.DebugLevel:

log.SetLevel(log.DebugLevel)

Pakkaus

Tässä postauksessa tutustuimme sisäänrakennetun lokipaketin käyttöön ja totesimme, että sitä tulisi käyttää vain triviaaleissa sovelluksissa tai nopeaa prototyyppiä rakennettaessa. Kaikkeen muuhun on pakko käyttää valtavirran lokikehystä.

Katsoimme myös tapoja varmistaa, että lokien sisältämä tieto on johdonmukaista ja helposti analysoitavissa, etenkin kun se kootaan yhteen keskitetylle alustalle.

Kiitos lukemisesta!

Leave a Reply