web-dev-qa-db-fra.com

Comment obtenir la trace de pile d'une panique (et la stocker en tant que variable)

Comme nous le savons tous, les paniques produisent une trace de pile vers stdout ( Playground link ).:

panic: runtime error: index out of range
goroutine 1 [running]:
main.main()
    /tmp/sandbox579134920/main.go:9 +0x20

Et il semble que lorsque vous récupérez d'une panique, recover() renvoie uniquement un error qui décrit la cause de la panique ( lien Playground ).

runtime error: index out of range

Ma question est, est-il possible de stocker le stacktrace qui est écrit sur stdout? Cela fournit des informations de débogage bien meilleures que la chaîne runtime error: index out of range Car elle affiche la ligne exacte dans un fichier qui a provoqué la panique.

14
hlin117

Comme @Volker mentionné ci-dessus, et ce qui a été publié en tant que commentaire, nous pouvons utiliser le runtime/debug paquet.

package main

import (
    "fmt"
    "runtime/debug"
)

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
        }
    }()

    var mySlice []int
    j := mySlice[0]

    fmt.Printf("Hello, playground %d", j)
}

impressions

stacktrace from panic: 
goroutine 1 [running]:
runtime/debug.Stack(0x1042ff18, 0x98b2, 0xf0ba0, 0x17d048)
    /usr/local/go/src/runtime/debug/stack.go:24 +0xc0
main.main.func1()
    /tmp/sandbox973508195/main.go:11 +0x60
panic(0xf0ba0, 0x17d048)
    /usr/local/go/src/runtime/panic.go:502 +0x2c0
main.main()
    /tmp/sandbox973508195/main.go:16 +0x60

Lien Playground .

15
hlin117

Créez un fichier journal pour ajouter la trace de pile au fichier pour stdout ou stderr. Cela ajoutera les données, y compris l'heure avec la ligne de l'erreur dans un fichier.

package main

import (
    "log"
    "os"
    "runtime/debug"
)

func main() {

    defer func() {
        if r := recover(); r != nil {
            log.Println(string(debug.Stack()))
        }
    }()

    //create your file with desired read/write permissions
    f, err := os.OpenFile("filename", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
    if err != nil {
        log.Println(err)
    }

    //set output of logs to f
    log.SetOutput(f)
    var mySlice []int
    j := mySlice[0]

    log.Println("Hello, playground %d", j)

    //defer to close when you're done with it, not because you think it's idiomatic!
    f.Close()
}

Exemple de travail sur Aller au terrain de je

2
Himanshu