141 votes

Approche correcte de l'exploitation forestière globale

Quel est le modèle de journalisation des applications en Go ? Si j'ai, disons, 5 goroutines dont j'ai besoin d'enregistrer, dois-je...

  • Créez un seul log.Logger et le faire circuler ?
  • Transmettez un pointeur à cette log.Logger ?
  • Chaque goroutine ou fonction doit-elle créer un logger ?
  • Dois-je créer le logger comme une variable globale ?

66voto

tux21b Points 17336
  • Créer un seul log.Logger et le faire circuler ?

C'est possible. A log.enregistreur peut être utilisé simultanément à partir de plusieurs goroutines.

  • Transmettre un pointeur vers ce log.Logger ?

log.nouveau renvoie un *Logger ce qui est généralement une indication que vous devez passer l'objet comme un pointeur. Le passer en tant que valeur créerait une copie de la structure (i.e. une copie du Logger) et plusieurs goroutines pourraient alors écrire dans le même fichier io.Writer en même temps. Cela pourrait être un problème sérieux, en fonction de l'implémentation du rédacteur.

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

Je ne créerais pas un logger séparé pour chaque fonction ou goroutine. Les goroutines (et les fonctions) sont utilisées pour des tâches très légères qui ne justifieront pas la maintenance d'un logger séparé. C'est probablement une bonne idée de créer un logger pour chaque composant plus important de votre projet. Par exemple, si votre projet utilise un service SMTP pour envoyer des mails, créer un logger séparé pour le service de messagerie semble être une bonne idée afin de pouvoir filtrer et désactiver la sortie séparément.

  • Dois-je créer le logger comme une variable globale ?

Cela dépend de votre paquet. Dans l'exemple précédent du service de messagerie, ce serait probablement une bonne idée d'avoir un enregistreur pour chaque instance de votre service, afin que les utilisateurs puissent enregistrer les échecs lors de l'utilisation du service de messagerie gmail différemment des échecs survenus lors de l'utilisation du MTA local (par exemple, sendmail).

45voto

zzzz Points 23017

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

Ensuite, il suffit d'appeler les fonctions de haut niveau du paquet log comme log.Printf y log.Fatalf qui utilisent cette instance globale.

24voto

Israel Barba Points 255

Il s'agit d'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 la manière suivante

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

11voto

Omortis Points 453

Je sais que cette question est un peu ancienne, mais si, comme moi, vos projets sont constitués de plusieurs petits fichiers, je vote pour la quatrième option. logger.go qui fait partie du paquet principal. Ce fichier go crée le logger, l'assigne à un fichier, et le fournit au reste de main. Notez que je n'ai pas encore trouvé une façon élégante de fermer errorlog...

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

3voto

Juergen Brendel Points 71

C'est une question plus ancienne, mais je voudrais suggérer l'utilisation de http://github.com/romana/rlog (que nous avons développé). Il est configuré par des variables d'environnement, l'objet logger est créé et initialisé lorsque rlog est importé. Par conséquent, il n'est pas nécessaire de passer autour d'un logger.

rlog possède un grand nombre de fonctionnalités :

  • Estampilles date/heure entièrement configurables
  • Sortie simultanée vers stderr ou stdout ainsi que vers un fichier.
  • Niveaux d'enregistrement standard (Debug, Info, etc.) et enregistrement multi-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 sources.

Il est très petit, n'a pas de dépendances externes, à l'exception de la bibliothèque standard de Golang et est activement développé. Des exemples sont fournis dans le dépôt.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X