Depuis Go 1.21, un nouveau package est disponible pour logger en Go. J’attendais ce nouveau package avec impatience, il permet beaucoup de chose et rend la lib de base de Go encore plus intéressante. le package log reste en place, cependant slog est bien plus intéressant.
Ce nouveau logger permet d’avoir différents niveaux de logs, un mode debug. Il permet également de gérer la sortie des logs et d’avoir différents mode, mode classique ou log en JSON.
Les fonctions de base
Pour logger avec slog, il suffit d’utiliser les fonctions Info,Warn,Error ou Debug du package slog.
2023/08/21 18:59:30 INFO Hello info 2023/08/21 18:59:30 WARN Hello Warning 2023/08/21 18:59:30 ERROR Hello Error
Notons que le mode debug n’est pas activé.
La création d’un système de log avancé
Il est important de savoir que la base de slog est basé sur du JSON, à partir ou l’on modifie le logger, on se retrouve avec des logs au format clé-valeur.
Plutot que faire un paragraphe par élément, je trouve plus simple de commencer par un seul gros bloc de code:
packagemainimport (
"log/slog")
funcmain(){
logger:=slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug, // niveau des Logs, le nom est slog.Level + niveau souhaité (Info,Error,Warn,Debug)
AddSource: true, // permet d'afficher l'emplacement de l'erreur du log
ReplaceAttr: func(groups []string, aslog.Attr) slog.Attr { // redéfinition des clés:
ifa.Key==slog.TimeKey {
returnslog.String("timeCustom", a.Value.Time().Format("2006-01-02 15:04:05")) // modifie la valeur du temps pour afficher l'heure comme sur les logs normaux
}
ifa.Key==slog.LevelKey { // renomme la clé level
a.Key = "lvl" }
returna },
}))
logger.Debug("Il s'agit d'une erreur et la source de l'erreur est affichée")
}
La sortie des logs peux également se faire intégralement en JSON (cette fois je ne modifie pas le handle de base donc il vaut nil):
packagemainimport (
"log/slog")
funcmain(){
logger:=slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Warn("Message de log")
}
Créer des clés
Dans les messages de log, il est possible d’ajouter de nouvelles clés grace aux fonctions slog.TypeClé, ces clés peuvent être groupée grace à la fonction slog.Group
packagemainimport"log/slog"funcmain(){
logger:=slog.New(slog.NewTextHandler(os.Stdout, nil))
logger.Info("Texte du message", "Nombre", 100, "bool", true, "String", "Bonjour!") // méthode 1: param: msg + clé1 + val1 + clé 2 + val 2 +...
logger.Info("Texte du message", slog.Group("Nom de la clé du groupe", slog.Int("Nombre", 100), slog.Bool("Bool", true), slog.String("String val", "Bonjour!")))
// dans le Group, les valeurs sont affiché en nomgroupe.clé
}
On peux également ajouter un attribut à chaque log:
packagemainimport"log/slog"funcmain(){
logger:=slog.New(slog.NewTextHandler(os.Stdout, nil).WithAttrs([]slog.Attr{
slog.String("Ajout d'un attribut aux logs", "Valeur"),
}))
logger.Info("Texte du message")
// dans le Group, les valeurs sont affiché en nomgroupe.clé
}
Adapter l’affichage des structures
Pour les structures, on peux les afficher et les récupérer en JSON grâce à une interface de slog:
packagemainimport (
"fmt""log/slog""os")
typePointstruct {
XintYint}
func (pPoint) LogValue() slog.Value {
returnslog.GroupValue(
slog.Int("X", p.X),
slog.Int("Y", p.Y),
)
}
funcmain() {
logger:=slog.New(slog.NewJSONHandler(os.Stdout, nil))
pt:=Point{X: 50, Y: 30}
logger.Info("Utilisation de la fonction interface de slog", "Point:", pt)
}
Redéfinir le logger par défaut
Un des avantages de slog est de pouvoir redéfinir le logger par défaut, ainsi tous les futurs appels à slog.Info prendront les paramètres personnalisés, les logs du package log seront également impactés par ces modifications.