web-dev-qa-db-fra.com

Comment obtenez-vous un programme Golang pour imprimer le numéro de ligne de l'erreur qu'il vient d'appeler?

J'essayais de générer des erreurs dans mon programme Golang avec log.Fatal, mais log.Fatal n'imprime pas également la ligne où le log.Fatal a été exécuté. N'y a-t-il aucun moyen d'avoir accès au numéro de ligne appelé log.Fatal? c’est-à-dire qu’il ya un moyen d’obtenir le numéro de ligne lorsqu’une erreur est générée?

J'essayais de google ceci mais je ne savais pas comment. La meilleure chose que je pouvais obtenir était en imprimant la trace de la pile , ce qui, je suppose, est bon mais peut-être un peu trop. Je ne veux pas non plus écrire debug.PrintStack() chaque fois que j'ai besoin du numéro de ligne. Je suis simplement surpris de constater qu'il n'existe aucune fonction intégrée pour ce type log.FatalStackTrace() ou quelque chose qui n'est pas en costume.

De plus, si je ne veux pas créer mes propres outils de débogage/de gestion des erreurs, c'est parce que je ne veux pas que les gens aient à apprendre à utiliser mon code spécial de traitement des costumes. Je veux juste quelque chose de standard où les gens peuvent lire mon code plus tard et être comme 

"ah ok, alors ça lance une erreur et fait X ..."

Moins les gens doivent apprendre mon code, mieux c'est :)

68
Pinocchio

Vous pouvez définir les indicateurs sur un enregistreur personnalisé ou sur la valeur par défaut pour inclure Llongfile OU Lshortfile

// to change the flags on the default logger
log.SetFlags(log.LstdFlags | log.Lshortfile)
87
JimB

Version courte, il n'y a rien directement construit dansCependant, vous pouvez le mettre en œuvre avec une courbe d’apprentissage minimale en utilisant runtime.Caller

func HandleError(err error) (b bool) {
    if err != nil {
        // notice that we're using 1, so it will actually log where
        // the error happened, 0 = this function, we don't want that.
        _, fn, line, _ := runtime.Caller(1)
        log.Printf("[error] %s:%d %v", fn, line, err)
        b = true
    }
    return
}

//this logs the function name as well.
func FancyHandleError(err error) (b bool) {
    if err != nil {
        // notice that we're using 1, so it will actually log the where
        // the error happened, 0 = this function, we don't want that.
        pc, fn, line, _ := runtime.Caller(1)

        log.Printf("[error] in %s[%s:%d] %v", runtime.FuncForPC(pc).Name(), fn, line, err)
        b = true
    }
    return
}

func main() {
    if FancyHandleError(fmt.Errorf("it's the end of the world")) {
        log.Print("stuff")
    }
}

playground

67
OneOfOne

Si vous avez exactement besoin d’une trace de pile, consultez https://github.com/ztrue/tracerr

J'ai créé ce package afin d'avoir à la fois une trace de pile et des fragments source pour pouvoir déboguer plus rapidement et consigner les erreurs avec beaucoup plus de détails.

Voici un exemple de code:

package main

import (
    "io/ioutil"
    "github.com/ztrue/tracerr"
)

func main() {
    if err := read(); err != nil {
        tracerr.PrintSourceColor(err)
    }
}

func read() error {
    return readNonExistent()
}

func readNonExistent() error {
    _, err := ioutil.ReadFile("/tmp/non_existent_file")
    // Add stack trace to existing error, no matter if it's nil.
    return tracerr.Wrap(err)
}

Et voici le résultat:  golang error stack trace

0
Johan