Как получить трассировку стека паники (и сохранить как переменную)

Как мы все знаем, паника производит трассировку стека на стандартный вывод (Ссылка на игровую площадку) .:

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

И кажется, что когда вы оправляетесь от паники, recover() возвращает только error, который описывает причину паники (Ссылка на игровую площадку).

runtime error: index out of range

Мой вопрос: можно ли сохранить трассировку стека, которая записывается в стандартный вывод? Это обеспечивает гораздо лучшую отладочную информацию, чем строка runtime error: index out of range, потому что она показывает точную строку в файле, которая вызвала панику.

вы должны прочитать это и проверить тот

mh-cbon 30.08.2018 20:26

Используйте отладку пакета.

Volker 30.08.2018 20:37

Я бы хотел думать, что есть способ. Например, я использовал runtime/debug для захвата трассировки стека, см. здесь. Мне любопытно, есть ли у других участников лучшее решение.

hlin117 30.08.2018 20:37
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
44
3
20 454
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Создайте файл журнала, чтобы добавить трассировку стека в файл для stdout или stderr. Это добавит данные, включая время, со строкой ошибки внутри файла.

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

Рабочий пример на Перейти на игровую площадку

Ответ принят как подходящий

Подобно упомянутому выше @Volker и тому, что было опубликовано в качестве комментария, мы можем использовать пакет runtime/debug.

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

отпечатки

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

Ссылка на игровую площадку.

Чтобы прояснить это (потому что в этом случае это явно не проверяется): когда вы находитесь внутри recovery (), функция debug.Stack () вернет стек ПАНИКИ, а не только лексический стек отложенной функции.

Jon Watte 18.04.2019 21:01

@JonWatte кроме того, исходное место паники будет выше в трассировке стека.

Pavel Patrin 14.04.2020 20:46

Другие вопросы по теме