Se connecter en Go : Choisir un système et l’utiliser

Vous êtes relativement nouveau dans le langage Go. Vous l’utilisez probablement pour écrire une application web ou un serveur, et vous avez besoin de créer un fichier journal. Donc, vous faites une recherche rapide sur le web et vous trouvez qu’il y a une tonne d’options pour la journalisation en go. Comment savoir laquelle choisir ? Cet article va vous équiper pour répondre à cette question.

Nous jetterons un coup d’œil au paquet intégré log et déterminerons à quels projets il convient avant d’explorer d’autres solutions de journalisation qui prévalent dans l’écosystème Go.

Qu’est-ce que la journalisation

Je n’ai pas besoin de vous dire à quel point la journalisation est importante. Les journaux sont utilisés par chaque application web de production pour aider les développeurs et les opérations :

  • Dépister les bogues dans le code de l’application
  • Découvrir les problèmes de performance
  • Faire une analyse post-mortem des pannes et des incidents de sécurité

Les données que vous enregistrez réellement dépendront du type d’application que vous construisez. La plupart du temps, vous aurez une variation des éléments suivants :

  • L’horodatage du moment où un événement s’est produit ou un journal a été généré
  • Les niveaux de journal tels que debug, error ou info
  • Des données contextuelles pour aider à comprendre ce qui s’est passé et permettre de reproduire facilement la situation

Ce qu’il ne faut pas enregistrer

En général, vous ne devriez pas enregistrer toute forme de données commerciales sensibles ou d’informations personnellement identifiables. Cela inclut, mais n’est pas limité à :

  • Noms
  • Adresses IP
  • Numéros de cartes de crédit

Ces restrictions peuvent rendre les journaux moins utiles d’un point de vue technique, mais elles rendent votre application plus sécurisée. Dans de nombreux cas, des réglementations telles que le GDPR et l’HIPAA peuvent interdire la journalisation des données personnelles.

Introduction du paquet log

La bibliothèque standard de Go possède un paquet intégré log qui fournit la plupart des fonctionnalités de journalisation de base. Bien qu’il ne dispose pas de niveaux de journalisation (tels que debug, warning ou error), il fournit néanmoins tout ce dont vous avez besoin pour mettre en place une stratégie de journalisation de base.

Voici l’exemple de journalisation le plus basique :

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

Le code ci-dessus imprime le texte  » Hello world ! » dans l’erreur standard, mais il inclut également la date et l’heure, ce qui est pratique pour filtrer les messages de journalisation par date.

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

Par défaut, le paquet log imprime dans le flux de sortie de l’erreur standard (stderr), mais vous pouvez le faire écrire dans des fichiers locaux ou toute destination qui supporte l’interface io.Writer. Il ajoute également un horodatage au message de journal sans aucune configuration supplémentaire.

Logging vers un fichier

Si vous devez stocker les messages de journal dans un fichier, vous pouvez le faire en créant un nouveau fichier ou en ouvrant un fichier existant et en le définissant comme la sortie du journal. Voici un exemple:

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

Lorsque nous exécutons le code, ce qui suit est écrit dans logs.txt.

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

Comme mentionné précédemment, vous pouvez fondamentalement sortir vos journaux vers n’importe quelle destination qui implémente l’interface io.Writer, vous avez donc beaucoup de flexibilité lorsque vous décidez où enregistrer les messages dans votre application.

Création de loggers personnalisés

Bien que le paquet log implémente un logger prédéfini qui écrit dans l’erreur standard, nous pouvons créer des types de loggers personnalisés en utilisant la méthode log.New().

Lorsque vous créez un nouveau logger, vous devez passer trois arguments à log.New():

  • out : Tout type qui implémente l’interface io.Writer, qui est l’endroit où les données du journal seront écrites
  • prefix : Une chaîne de caractères qui est ajoutée au début de chaque ligne de journal
  • flag : Un ensemble de constantes qui nous permettent de définir les propriétés de journalisation à inclure dans chaque entrée de journal générée par le logger (plus d’informations à ce sujet dans la section suivante)

Nous pouvons profiter de cette fonctionnalité pour créer des loggers personnalisés. Voici unexemple qui met en œuvre les loggers Info, Warning et Error:

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

Après avoir créé ou ouvert le fichier logs.txt en haut de la fonction init, nous initialisons ensuite les trois loggers définis en fournissant la destination de sortie, la chaîne de préfixe et les drapeaux de log.

Dans la fonction main, les enregistreurs sont utilisés en appelant la fonction Println, qui écrit une nouvelle entrée de journal dans le fichier journal. Lorsque vous exécutez ce programme, ce qui suit sera écrit dans 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

Notez que dans cet exemple, nous enregistrons dans un seul fichier, mais vous pouvez utiliser un fichier distinct pour chaque enregistreur en passant un fichier différent lors de la création de l’enregistreur.

Log flags

Vous pouvez utiliser des constantes de drapeau d’enregistrement pour enrichir un message d’enregistrement en fournissant des informations contextuelles supplémentaires, telles que le fichier, le numéro de ligne, la date et l’heure. Par exemple, le passage du message « Quelque chose s’est mal passé » par un journal avec une combinaison de drapeaux présentée ci-dessous :

log.Ldate|log.Ltime|log.Lshortfile

s’imprimera

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

Malheureusement, il n’y a aucun contrôle sur l’ordre dans lequel ils apparaissent ou le format dans lequel ils sont présentés.

Introduction des cadres de journalisation

L’utilisation du paquet log est excellente pour le développement local lorsque l’obtention d’un retour rapide est plus importante que la génération de journaux riches et structurés. Au-delà, vous serez très probablement mieux en utilisant un framework de journalisation.

Un avantage majeur de l’utilisation d’un framework de journalisation est qu’il aide à standardiser les données de journalisation. Cela signifie que :

  • Il est plus facile de lire et de comprendre les données de journalisation.
  • Il est plus facile de rassembler les journaux de plusieurs sources et de les alimenter vers une plate-forme centrale pour être analysés.

En outre, la journalisation est à peu près un problème résolu. Pourquoi réinventer la roue ?

Choisir un framework de journalisation

Décider quel framework utiliser peut être un défi, car il existe plusieurs options parmi lesquelles choisir.

Les deux frameworks de journalisation les plus populaires pour Go semblent être beglog et logrus. La popularité de glog est surprenante, car il n’a pas été mis à jour depuis plusieurs années. logrus est mieux maintenu et utilisé dans des projets populaires comme Docker, nous nous concentrerons donc sur lui.

Démarrer avec logrus

L’installation de logrus est aussi simple que d’exécuter la commande ci-dessous dans votre terminal :

go get "github.com/Sirupsen/logrus"

Une grande chose à propos de logrus est qu’il est complètement compatible avec le paquet log de la bibliothèque standard, donc vous pouvez remplacer vos importations de logs partout par log "github.com/sirupsen/logrus" et cela fonctionnera tout simplement !

Modifions notre exemple précédent « hello world » qui utilisait le paquet log et utilisons logrus à la place:

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

L’exécution de ce code produit la sortie:

INFO Hello world!

Il ne pourrait pas être plus facile !

Logging en JSON

logrus est bien adapté à la journalisation structurée en JSON qui – comme JSON est un standard bien défini – facilite l’analyse de vos journaux par des services externes et rend également l’ajout de contexte à un message de journal relativement simple grâce à l’utilisation de champs, comme indiqué ci-dessous:

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

La sortie de journal générée sera un objet JSON qui comprend le message, le niveau de journal, l’horodatage et les champs inclus.

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

Si vous n’êtes pas intéressé par la sortie de vos logs en JSON, sachez que plusieurs formateurs tiers existent pour logrus, que vous pouvez consulter sur sa page Github. Vous pouvez même écrire votre propre formateur si vous préférez.

Niveaux de logs

À la différence du paquet de logs standard, logrus supporte les niveaux de logs.

Logrus a sept niveaux de journal : Trace, Debug, Info, Warn, Error, Fatal, et Panic. La gravité de chaque niveau augmente à mesure que vous descendez dans la liste.

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

En définissant un niveau de journalisation sur un enregistreur, vous pouvez enregistrer uniquement les entrées dont vous avez besoin en fonction de votre environnement. Par défaut, logrus enregistrera tout ce qui est Info ou supérieur (Warn, Error, Fatal, ou 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.")}

L’exécution du code ci-dessus produira la sortie suivante :

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

Notez que le message de niveau Debug n’a pas été imprimé. Pour l’inclure dans leslogs, définissez log.Level pour qu’il soit égal à log.DebugLevel:

log.SetLevel(log.DebugLevel)

Wrap up

Dans ce post, nous avons exploré l’utilisation du package log intégré et établi qu’il ne devrait être utilisé que pour des applications triviales ou lors de la construction d’un prototype rapide. Pour tout le reste, l’utilisation d’un framework de journalisation grand public est indispensable.

Nous avons également examiné les moyens de s’assurer que les informations contenues dans vos logs sont cohérentes et faciles à analyser, en particulier lors de leur agrégation sur une plate-forme centralisée.

Merci de lire!

Leave a Reply