2015-04-09 11 views
5

Ho trascorso molto tempo ora a cercare e leggere post sull'argomento, ma ho ancora ricevuto una nota per ottenere pienamente la risposta alla mia domanda - o forse ho solo bisogno di ulteriori chiarimenti sulle risposte esistenti.Registrazione globale (attraverso pacchetti)

Ho letto il post this che ha lo stesso titolo del mio, ma si tratta di eseguire il log delle routine di go piuttosto che dei pacchetti.

Quello che sto cercando di risolvere è l'accesso all'app principale e ai pacchetti che utilizza. Ho bisogno di un logger che può accedere a più posizioni (che può essere fatto con io.MultiWriter) e può fare cose come log.Error() e log.Debug()

So che ci sono pacchetti che fanno questo e io so come implementare quelle cose me stesso.

Quello che non riesco a capire è come usarlo correttamente con i miei pacchetti.

Un modo è ovviamente creare il logger in main e poi passarlo a tutte le funzioni che necessitano di registrazione. Ma sembra imbarazzante.

La mia soluzione ideale sarebbe quella di avere un logger come il logger globale incorporato nel pacchetto di log, ma con le funzionalità aggiunte come sopra.

Principalmente voglio questo per la registrazione debug facoltativa all'interno dei pacchetti, quindi posso accenderlo in una versione di produzione, se necessario.

Qual è il modo corretto per farlo?

+0

Perché non utilizzare una variabile di registrazione globale in ogni pacchetto e crearli/impostarli nel pacchetto principale? –

+1

Forse puoi provare https://github.com/golang/glog. Anche se non ha Debug, ha Info, Warning, Error e Fatal. Permette anche la registrazione del livello di verbosità. Hmm, ma non consente nemmeno di impostare lo scrittore. Oh bene! Vale la pena commentare – ANisus

risposta

4

Il modo corretto è quello che pensi sia il modo ideale. Basta creare un pacchetto (preferibilmente seguendo le convenzioni di Go https://golang.org/doc/code.html) e rendere il vostro registro globale:

package mylog 

// Define your custom logger type. 
type logger struct { /* Whatever you want */ } 

// Optionally make it a interface. 
type Logger interface { /* Your functions */ } 

// And just go global. 
var defaultLogger *Logger 

func init(){ 
    defaultLogger = new(logger) 
} 

func Debug(params ...string){ 
    // Have some fun. 
} 

// ... 

Anche io consiglierei di descrivere nella documentazione che il progetto utilizza tale funzione di registrazione.

2

La risposta di @MedmundoMartinez mi ha scosso la testa abbastanza da trovare la risposta (estremamente semplice e piuttosto ovvia, ora che posso usare i miei specchietti retrovisori).

Sto postando la mia risposta qui per chiunque sia interessato a una soluzione simile.

Quello che ho fatto è stato fare una copia del pacchetto di log standard (src/log/log.go) ed estenderlo. Non potrebbe essere più semplice ottenere un logger globale che faccia già tutto ciò che fa il logger standard più qualsiasi altra cosa tu voglia che faccia! In questo caso la registrazione con supporto livellato.

Le uniche modifiche che ho dovuto fare: è stato aggiunto

type Logger struct { 
    mu  sync.Mutex // ensures atomic writes; protects the following fields 
    prefix string  // prefix to write at beginning of each line 
    flag int  // properties 
    out io.Writer // destination for output 
    buf []byte  // for accumulating text to write 
    level int  // One of DEBUG, ERROR, INFO 
} 

solo l'ultima riga. Il pacchetto log imposta una variabile globale std che può quindi essere utilizzata per accedere ai campi struct da qualsiasi funzione nel pacchetto.

Poi ho aggiunto le costanti per i diversi livelli di log:

const (
    DEBUG = 1 << iota 
    INFO 
    ERROR 
) 

Poi ho aggiunto le mie funzioni:

(Nota: ct è il pacchetto https://github.com/seago/go-colortext che permette di colore del testo della console su Windows.Quindi gli errori qui sono tutti stampati in rosso)

func Error(v ...interface{}) { 
    if std.level <= ERROR { 
     ct.ChangeColor(ct.Red, true, ct.None, false) 
     s := fmt.Sprintf("ERROR: %v", v...) 
     std.Output(2, s) 
     ct.ResetColor() 
    } 
} 

func Info(format string, v ...interface{}) { 
    if std.level <= INFO { 
     s := fmt.Sprintf("INFO: "+format, v...) 
     std.Output(2, s) 
    } 
} 

func Debug(v ...interface{}) { 
    if std.level <= DEBUG { 
     s := fmt.Sprintf("DEBUG: %v", v...) 
     std.Output(2, s) 
    } 
} 

func SetLogLevel(lvl int) { 
    std.level = lvl 
} 

E il gioco è fatto! Con che ora posso usarlo semplicemente importando il pacchetto modificato al posto del pacchetto di log standard e log via:

import (
    "errors" 
    "tryme/log" 
) 

func main() { 
    log.SetLogLevel(log.INFO) 
    log.Info("This is a test Info") 
    err := errors.New("This is a test error!!!") 
    log.Error(err) 
    log.Debug("Testing debugging") // won't be printed with log.INFO 
} 

Questo è naturalmente solo una demo e può essere facilmente esteso ulteriormente con più livelli di log, formattazione dell'output ecc

È possibile utilizzare tutte le funzioni del pacchetto di log standard fornisce come SetOutput di scrivere su un file o una MultiWriter di scrivere su file e console ecc

+2

Perché hai copiato l'intero logger e non hai semplicemente incorporato 'Logger' in una tua nuova struttura, che avrebbe poi implementato' Error', 'Info' etc? Sembra un po 'eccessivo copiarlo tutto ... – rpkamp

+0

@ScallioXT - Perché volevo un logger globale. Se creo il mio tipo e incorporo lo strumento di registrazione standard, dovrei quindi riunire tutte le funzioni (quelle che non sono metodi) del pacchetto di log per poterle accedere globalmente. E sarebbe molto più impegnativo fare ciò che ho fatto sopra, ma non vedo come farei altrimenti. Forse mi manca qualcosa. In tal caso, per favore, indicami la giusta direzione. – IamNaN

+0

Ho pensato che sarebbe stato più semplice incorporare 'log.Logger', ma l'ho appena provato e ci si mette nei guai che i campi di' log.Logger' non vengono esportati, quindi non è possibile fare riferimento a essi. Per risolvere il problema, dovresti saltare un sacco di cerchi e in effetti non ne vale la pena. Basta copiare tutto come se tu stia facendo ora sembra la soluzione migliore per quanto posso vedere. – rpkamp

1

per aggiungere, se si vuole fare la registrazione su più Vai alle applicazioni, puoi utilizzare RPC e creare un servizio di registrazione. Questa sarebbe un'applicazione in grado di fornire servizi ad altre applicazioni. Golang has its own package for it

Problemi correlati