Próbowałem zgłosić błędy w moim programie Golang, log.Fatal
ale log.Fatal
nie wypisuje również wiersza, w którym log.Fatal
został uruchomiony. Czy nie ma możliwości uzyskania dostępu do numeru linii, który nazywa się log.Fatal? tj. czy istnieje sposób, aby uzyskać numer linii podczas zgłaszania błędu?
Próbowałem to wygooglować, ale nie byłem pewien jak. Najlepsze, co mogłem uzyskać, to wydrukowanie śladu stosu , co wydaje mi się dobre, ale może być trochę za dużo. Nie chcę też pisać za debug.PrintStack()
każdym razem, gdy potrzebuję numeru wiersza, jestem po prostu zaskoczony, że nie ma żadnej wbudowanej funkcji log.FatalStackTrace()
lub czegoś, co nie jest kostiumem.
Ponadto powodem, dla którego nie chcę tworzyć własnych rzeczy związanych z debugowaniem / obsługą błędów, jest to, że nie chcę, aby ludzie musieli uczyć się, jak używać mojego specjalnego kodu do obsługi kostiumów. Po prostu chcę czegoś standardowego, w którym ludzie będą mogli później przeczytać mój kod i być jak
„ah ok, więc zgłasza błąd i robi X ...”
Im mniej osób musi się uczyć o moim kodzie, tym lepiej :)
źródło
Odpowiedzi:
Możesz ustawić flagi w niestandardowym rejestratorze lub domyślnie uwzględniać
Llongfile
lubLshortfile
// to change the flags on the default logger log.SetFlags(log.LstdFlags | log.Lshortfile)
źródło
var mylog = log.New(os.Stderr, "app: ", log.LstdFlags | log.Lshortfile)
.expected declaration, found 'INDENT' log
kiedy próbuję to zrobićlog.SetFlags(log.LstdFlags | log.Lshortfile)
. Po prostu irytuje mnie konieczność tworzenia dla niego zmiennej, dlaczego nie może istniećlog.Fatal("string", log.Flag)
. Ale utworzenie nowego dziennika zmiennych zadziałało. Czy tworzenie zmiennych dziennika i takie tam jest standardem?func init() {}
Krótka wersja,
nie ma nic bezpośrednio wbudowanegojednak można go zaimplementować przy minimalnej krzywej uczenia się przy użyciuruntime.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
źródło
fn
Zmienna przypisana odruntime.Caller()
rzeczywistości jest nazwa pliku, a nie funkcja odniesienia. Myślę o fn jako funkcji, a nie nazwie pliku .runtime
użycia pakietu. Bardzo przydatne do debugowania za pomocą dzienników.Jeśli potrzebujesz dokładnego śladu stosu, zajrzyj na https://github.com/ztrue/tracerr
Utworzyłem ten pakiet, aby mieć zarówno ślad stosu, jak i fragmenty źródła, aby móc szybciej debugować i rejestrować błędy ze znacznie większą liczbą szczegółów.
Oto przykład kodu:
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) }
A oto wynik:
źródło