2015-11-24 15 views
8

Ho finora evitato l'uso di log.Fatal, ma recentemente ho scoperto casualmente queste domande; code-coverage e tests-using-log-fatal.Nel caso in cui un pacchetto Go utilizzi log.Fatal e quando?

Uno dei commenti delle domande di copertura 100 del codice dice:

... Nella stragrande maggioranza dei casi log.Fatal dovrebbe essere essere utilizzato solo nelle funzioni principali, o init (o, eventualmente, alcune cose destinata a essere chiamato solo direttamente da loro)"

andare fatto pensare, così ho cominciato a guardare il codice della libreria standard fornito con Go. ci sono un sacco di esempi in cui il codice prova nella biblioteca fa uso di log.Fatal che sembra soddisfacente alcuni esempi al di fuori del codice di test, come ad esempio in net/http, di seguito riportate:

// net/http/transport.go 
func (t *Transport) putIdleConn(pconn *persistConn) bool { 
    ... 
    for _, exist := range t.idleConn[key] { 
     if exist == pconn { 
      log.Fatalf("dup idle pconn %p in freelist", pconn) 
     } 
    } 
    ... 
} 

Se la sua è delle migliori pratiche per evitare l'uso di log.Fatal, perché è utilizzato a tutti nelle librerie standard, mi sarei aspettato basta restituire un errore. Sembra ingiusto che l'utente della libreria faccia chiamare os.Exit e non fornisca alcuna possibilità per l'applicazione di ripulire.

posso essere ingenuo, così da qui la mia domanda come una pratica migliore sembrerebbe quella di chiamare log.Panic che può essere recuperata e la mia teorica lungo in esecuzione un'applicazione stabile potrebbe avere la possibilità di salire dalle ceneri.

Quindi cosa sarebbe meglio dire per Go in merito a quando dovrebbe log.Fatal dovrebbe essere utilizzato?

+3

La mia speranza sarebbe che questo codice sia assolutamente irraggiungibile. Che un errore che fa sì che una connessione inattiva rimanga nell'elenco di inattività mentre viene utilizzato anche come connessione attiva non dovrebbe essere qualcosa che dovrebbe accadere sempre e che ciò avvenga dovrebbe essere qualcosa di catastrofico. Ma dal momento che sembrano utilizzare correttamente i mutex attorno alla lista inattiva e così via, non ho idea del perché questo ciclo e il codice sarebbero addirittura necessari. Perché dovrebbero uscire ulteriormente dal tuo programma immediatamente, piuttosto che fare un po 'di panico è un altro mistero. Grande domanda. – captncraig

+0

Alcuni test di quel pacchetto sono in grado di raggiungere quella linea? – captncraig

+0

Una buona domanda, ha avuto un aspetto piccolo e non vedo nulla che assomigli al suo specifico design per raggiungere quella linea. Non ancora conclusivo ... – miltonb

risposta

8

Potrebbe essere solo io, ma ecco come uso log.Fatal. Secondo le convenzioni UNIX, un processo che rileva un errore dovrebbe fallire il prima possibile con un codice di uscita diverso da zero. Questo mi ha portato alle seguenti linee guida da utilizzare quando log.Fatal ...

  1. ... si verifica un errore in uno dei miei func init(), in quanto questi si verificano quando le importazioni sono trattati o prima della func principale si chiama, rispettivamente. Viceversa, faccio solo cose che non influiscono direttamente sull'unità di lavoro che la biblioteca o il cmd dovrebbero fare. Ad esempio, ho impostato la registrazione e controllo se abbiamo un ambiente sano e parametri. Non è necessario eseguire main se abbiamo bandiere non valide, giusto? E se non possiamo dare un feedback adeguato, dovremmo dirlo presto.
  2. ... succede un errore di cui so che è irrecuperabile. Supponiamo di avere un programma che crea una miniatura di un file immagine dato sulla riga di comando. Se questo file non esiste o non è leggibile a causa di autorizzazioni insufficienti, non vi è alcun motivo per continuare e questo errore non può essere ripristinato da. Quindi aderiamo alle convenzioni e falliamo.
  3. ... si verifica un errore durante un processo che potrebbe non essere reversibile. Questa è una specie di definizione morbida, lo so. Lascia che ti illustri. Supponiamo di avere un'implementazione di cp e che sia stata avviata per essere non interattiva e copiare ricorsivamente una directory. Ora, assumiamo che incontriamo un file nella directory di destinazione che ha lo stesso nome (ma contenuto diverso) come file da copiare lì. Dal momento che non possiamo chiedere all'utente di decidere cosa fare e non possiamo copiare questo file, abbiamo un problema. Poiché l'utente supporrà che le directory di origine e di destinazione siano copie esatte quando finiamo con codice di uscita zero, non possiamo semplicemente saltare il file in questione. Tuttavia, non possiamo semplicemente sovrascriverlo, poiché questo potrebbe potenzialmente distruggere le informazioni.Questa è una situazione che non possiamo recuperare da una richiesta esplicita da parte dell'utente, quindi userei lo log.Fatal per spiegare la situazione, obbedendo al principio di fallire il prima possibile.
+1

Mi piace la tua risposta in quanto spiega bene i punti (e risuona con le mie idee su questo argomento) ma temo che manchi un punto cruciale: l'OP ha chiesto esplicitamente di usare 'log.Fatal' * in un pacchetto * - - cioè, in un pezzo di codice non controllato da chiunque abbia scritto 'main()'. Come potete vedere, in realtà questo sposta la domanda da un dominio di "processo ben funzionante" al dominio del "pacchetto ben funzionante" - una storia abbastanza diversa per la domanda diventa: se va bene fallire irreversibilmente il programma di qualcun altro? – kostix

+1

È coperto, anche se un po 'implicito: applico quelle regole indipendentemente dal fatto che scrivo un pacchetto o un cmd: un errore irrecuperabile è un errore irrecuperabile. È responsabilità di un programma dare un input igienizzato al pacchetto. Se ciò non è possibile, è necessario restituire un errore, ma solo se l'input non può essere disinfettato in precedenza. Così fatale, se appropriato, aiuta effettivamente l'utente di un pacchetto a scrivere codice migliore. –

+1

La cosa è, non è la chiamata del manutentore del pacchetto se qualcosa è irrecuperabile o meno. Certo, non hai generato una miniatura, ma la stavo usando come una piccola parte del mio server web. Se un pacchetto di miniature chiama os.Exit perché non può caricare un file, sarei irritato. – captncraig