Як отримати програму Golang для друку номера рядка помилки, яку вона щойно викликала?


94

Я намагався видалити помилки в моїй програмі Golang за допомогою, log.Fatalале log.Fatalтакож не друкує рядок, де log.Fatalбуло запущено. Чи неможливо отримати доступ до номера рядка, який називається log.Fatal? тобто чи є спосіб отримати номер рядка при появі помилки?

Я намагався погуглити це, але не був впевнений, як. Найкраще, що я міг отримати, - це друк трасування стека , що, на мою думку, добре, але може бути трохи занадто. Я також не хочу писати debug.PrintStack()щоразу, коли мені потрібен номер рядка, я просто здивований, що для цього не вбудована функція log.FatalStackTrace()або щось, що не є костюмом.

Крім того, причина, через яку я не хочу робити власні речі для налагодження / обробки помилок, полягає в тому, що я не хочу, щоб люди вчились користуватися моїм спеціальним кодом для обробки костюмів. Я просто хочу щось стандартне, де люди можуть читати мій код пізніше і бути схожими

"ах гаразд, отже, видає помилку і робить X ..."

Чим менше людей дізнається про мій код, тим краще :)



У той момент, коли ви друкуєте номери рядків, це означає, що мені доведеться зануритися у ваш код, тому "чим менше людей доведеться дізнаватися про мій код, тим краще". Потрібно мати чіткі та короткі помилки.
Wessie

Відповіді:


122

Ви можете встановити прапори як у користувацькому реєстраторі, так і за замовчуванням для включення LlongfileабоLshortfile

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

Отже, щоб це працювало, мені потрібно лише встановити, що вгорі одного з файлів пакета, і він буде доступний для всіх моїх файлів для цього пакету?
Буратіно,

4
Так, якщо ви використовуєте власний журнал, ви можете використовувати його як var mylog = log.New(os.Stderr, "app: ", log.LstdFlags | log.Lshortfile).
OneOfOne

чи справді мені потрібно створювати змінну? Я не можу просто зробити log.SetFlags (log.LstdFlags | log.Lshortfile) у верхній частині мого go-файлу? Я отримую повідомлення про помилку: expected declaration, found 'INDENT' logколи я намагаюся це зробити log.SetFlags(log.LstdFlags | log.Lshortfile). Мене просто дратує, що мені доводиться створювати для нього змінну, чому не може бути log.Fatal("string", log.Flag). Але створення нового журналу змінних справді спрацювало. Це стандартна річ для створення змінних журналу та іншого?
Буратіно,

3
@Pinocchio: Ця помилка пов’язана з тим, що вона недійсна. Помістіть його в init () або іншу точку входу.
JimB

5
ви повинні помістити цеfunc init() {}
OneOfOne

94

Коротка версія, немає нічого безпосередньо вбудованого, проте ви можете реалізувати це з мінімальною кривою навчання, використовуючи 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


11
Хоча вже дана відповідь акуратно вирішує проблему, ваше рішення попередило мене про існування чогось приголомшливого - пакету виконання! Прекрасні речі :) golang.org/pkg/runtime
Гвінет Ллевелін

fnЗмінної присвоюється від runtime.Caller()фактично ім'я файлу, а не функція відліку. Я вважаю fn функцією, а не ім'ям файлу .
шоу

1
Чудово! Дякую. Це чудовий приклад використання runtimeпакетів. Дуже корисно для налагодження журналів.
вересня

1

Якщо вам потрібен саме трасування стека, загляньте на https://github.com/ztrue/tracerr

Я створив цей пакет, щоб мати як стек трасування, так і вихідні фрагменти, щоб мати змогу швидше налагоджувати і реєструвати помилки з набагато більше деталей.

Ось приклад коду:

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

І ось результат: трасування стеку помилок golang

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.