web-dev-qa-db-fra.com

Approche correcte de la journalisation globale à Golang

Quel est le modèle de connexion des applications dans Go? Si j'ai, par exemple, 5 goroutines dont je dois me connecter, devrais-je ...

  • Créer un seul log.Logger et le faire circuler?
  • Passez un pointeur sur ce log.Logger?
  • Chaque goroutine ou fonction doit-elle créer un enregistreur?
  • Devrais-je créer le logger en tant que variable globale?
99
Carson
  • Créer un seul log.Logger et le transmettre?

C'est possible. Un log.Logger peut être utilisé simultanément par plusieurs goroutines.

  • Passez un pointeur sur ce log.Logger?

log.New renvoie un *Logger qui indique généralement que vous devez passer l'objet comme un pointeur. Le passer en tant que valeur créerait une copie de la structure (c'est-à-dire une copie du journal), puis plusieurs goroutines pourraient écrire simultanément sur le même io.Writer . Cela pourrait être un problème grave, en fonction de la mise en œuvre de l'auteur.

  • Chaque goroutine ou fonction doit-elle créer un enregistreur?

Je ne créerais pas d'enregistreur distinct pour chaque fonction ou goroutine. Les Goroutines (et leurs fonctions) sont utilisées pour des tâches très légères qui ne justifieront pas la maintenance d'un enregistreur séparé. C'est probablement une bonne idée de créer un enregistreur pour chaque composant plus important de votre projet. Par exemple, si votre projet utilise un service SMTP pour l'envoi de courrier électronique, la création d'un enregistreur distinct pour le service de messagerie semble être une bonne idée, car vous pouvez filtrer et désactiver la sortie séparément.

  • Devrais-je créer le logger en tant que variable globale?

Cela dépend de votre colis. Dans le précédent exemple de service de messagerie, il serait probablement judicieux d’avoir un enregistreur pour chaque instance de votre service, afin que les utilisateurs puissent enregistrer les échecs lorsqu’ils utilisent le service de messagerie gmail différemment de ceux qui se produisaient lors de l’utilisation du MTA local (par exemple, sendmail ).

49
tux21b

Pour les cas simples, il existe un enregistreur global défini dans le package de journaux, log.Logger . Cet enregistreur global peut être configuré via log.SetFlags .

Ensuite, vous pouvez simplement appeler les fonctions de niveau supérieur du package de journalisation, comme log.Printf et log.Fatalf , qui utilise cette instance globale.

32
zzzz

Ceci est un simple enregistreur

package customlogger

import (
    "log"
    "os"
    "sync"
)

type logger struct {
    filename string
    *log.Logger
}

var logger *logger
var once sync.Once

// start loggeando
func GetInstance() *logger {
    once.Do(func() {
        logger = createLogger("mylogger.log")
    })
    return logger
}

func createLogger(fname string) *logger {
    file, _ := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)

    return &logger{
        filename: fname,
        Logger:   log.New(file, "My app Name ", log.Lshortfile),
    }
}

Vous pouvez l'utiliser de cette façon

package main

import (
    "customlogger"
    "fmt"
    "net/http"
)

func main() {
    logger := customlogger.GetInstance()
    logger.Println("Starting")

    http.HandleFunc("/", sroot)
    http.ListenAndServe(":8080", nil)
}

func sroot(w http.ResponseWriter, r *http.Request) {
    logger := customlogger.GetInstance()

    fmt.Fprintf(w, "welcome")
    logger.Println("Starting")
}
10
Israel Barba

Je sais que cette question est un peu ancienne, mais si, comme moi, vos projets sont constitués de plusieurs fichiers plus petits, je vote pour votre quatrième option - j'ai créé un logger.go cela fait partie du paquet principal. Ce fichier va crée l’enregistreur, l’assigne à un fichier et le fournit au reste de main. Notez que je n'ai pas trouvé de moyen élégant pour fermer le journal des erreurs ...

package main

import (
    "fmt"
    "log"
    "os"
)

var errorlog *os.File
var logger *log.Logger

func init() {
    errorlog, err := os.OpenFile(logfile,  os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        fmt.Printf("error opening file: %v", err)
        os.Exit(1)
    }

    logger = log.New(errorlog, "applog: ", log.Lshortfile|log.LstdFlags)
}
9
Omortis

C'est une question plus ancienne, mais je voudrais suggérer l'utilisation de http://github.com/romana/rlog (que nous avons développée). Il est configuré via des variables d'environnement, l'objet de journalisation est créé et initialisé lors de l'importation de rlog. Par conséquent, pas besoin de passer un enregistreur.

rlog a pas mal de fonctionnalités:

  • Tampons date/heure entièrement configurables
  • Sortie simultanée sur stderr ou stdout ainsi que sur fichier.
  • Niveaux de journalisation standard (Debug, Info, etc.), ainsi que journalisation à plusieurs niveaux librement configurable.
  • Enregistrement à la demande des informations sur l'appelant (fichier, numéro de ligne, fonction).
  • Possibilité de définir différents niveaux de journalisation pour différents fichiers source.

Il est très petit, n'a pas de dépendances externes, à l'exception de la bibliothèque standard de Golang, et est en cours de développement. Des exemples sont fournis dans le rapport.

3
Juergen Brendel

J'ai trouvé le package de journal par défaut ( https://golang.org/pkg/log/ ) quelque peu limitant. Par exemple, aucun support pour les journaux d’information ou de débogage.
Après quelques fouilles, décidé d'utiliser https://github.com/golang/glog . Cela semble être un port de https://github.com/google/glog et offre une flexibilité décente pour la journalisation. Par exemple, lorsque vous exécutez une application localement, vous souhaitez peut-être consigner le journal de niveau DEBUG, mais uniquement le niveau INFO/ERROR en production. La liste complète des fonctionnalités/guide est, ici https://google-glog.googlecode.com/svn/trunk/doc/glog.html (son pour le module c ++, mais pour la plupart traduit au port de golang)

2
factotum