Làm thế nào để bạn có được một chương trình Golang để in số dòng của lỗi mà nó vừa gọi?


94

Tôi đã cố gắng xử lý lỗi trong chương trình Golang của mình với log.Fatalnhưng, log.Fatalcũng không in dòng nơi log.Fatalchạy. Không có cách nào để truy cập vào số dòng được gọi là log.Fatal? tức là có cách nào để lấy số dòng khi ném lỗi không?

Tôi đã cố gắng google cái này nhưng không chắc làm thế nào. Điều tốt nhất tôi có thể nhận được là in dấu vết ngăn xếp , tôi đoán là tốt nhưng có thể hơi nhiều. Tôi cũng không muốn viết debug.PrintStack()mỗi khi tôi cần số dòng, tôi chỉ ngạc nhiên là không có bất kỳ chức năng nào được tích hợp sẵn cho cái này log.FatalStackTrace()hoặc cái gì đó không phải là trang phục.

Ngoài ra, lý do tôi không muốn tạo công cụ gỡ lỗi / xử lý lỗi của riêng mình là vì tôi không muốn mọi người phải học cách sử dụng mã xử lý trang phục đặc biệt của tôi. Tôi chỉ muốn một cái gì đó tiêu chuẩn, nơi mọi người có thể đọc mã của tôi sau này và giống như

"à được rồi, vậy là nó đang mắc lỗi và làm X ..."

Càng ít người phải tìm hiểu về mã của tôi thì càng tốt :)



Thời điểm bạn đang in số dòng, điều đó có nghĩa là tôi sẽ phải đi sâu vào mã của bạn, vì vậy, "Càng ít người phải tìm hiểu về mã của tôi càng tốt" được nêu ra ở đây. Điều bạn nên làm là có lỗi rõ ràng và ngắn gọn.
Wessie,

Câu trả lời:


122

Bạn có thể đặt Cờ trên một Trình ghi tùy chỉnh hoặc mặc định để bao gồm LlongfilehoặcLshortfile

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

Vì vậy, để điều này hoạt động, tôi chỉ cần đặt nó ở đầu một trong các tệp gói và nó sẽ có sẵn cho tất cả các tệp của tôi cho gói đó?
Pinocchio

4
Có, nếu bạn đang sử dụng nhật ký tùy chỉnh, bạn có thể sử dụng nó như thế nào var mylog = log.New(os.Stderr, "app: ", log.LstdFlags | log.Lshortfile).
OneOfOne

tôi có thực sự phải tạo một biến không? Tôi không thể chỉ làm log.SetFlags (log.LstdFlags | log.Lshortfile) ở đầu tệp go của tôi? Tôi gặp lỗi: expected declaration, found 'INDENT' logkhi tôi cố gắng làm log.SetFlags(log.LstdFlags | log.Lshortfile). Nó chỉ làm tôi khó chịu khi phải tạo ra một biến cho nó, tại sao không thể có a log.Fatal("string", log.Flag). Nhưng tạo một bản ghi biến mới đã hoạt động. Nó có phải là một điều tiêu chuẩn để tạo các biến và nội dung nhật ký không?
Pinocchio

3
@Pinocchio: Lỗi đó là do Go không hợp lệ, bạn không thể có một lệnh gọi hàm đơn giản ở cấp cao nhất. Đặt nó vào init () hoặc một số điểm nhập khác.
JimB

5
bạn phải đặt nó vàofunc init() {}
OneOfOne

94

Phiên bản ngắn, không có gì được tích hợp trực tiếp, tuy nhiên, bạn có thể triển khai nó với một đường cong học tập tối thiểu bằng cách sử dụng 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
Mặc dù câu trả lời đã được đưa ra khắc phục sự cố một cách gọn gàng, nhưng giải pháp của bạn đã cảnh báo tôi về sự tồn tại của một thứ tuyệt vời - gói thời gian chạy! Đáng yêu thứ :) golang.org/pkg/runtime
Gwyneth Llewelyn

Các fnbiến được gán từ runtime.Caller()thực sự là tên của tập tin, không phải là một tài liệu tham khảo chức năng. Tôi nghĩ về fn như một hàm, không phải tên tệp .
sshow 25/09/19

1
Tuyệt vời! Cảm ơn. Đây là một ví dụ tuyệt vời về runtimeviệc sử dụng gói. Rất hữu ích cho việc gỡ lỗi thông qua các bản ghi.
18augst

1

Nếu bạn cần một dấu vết ngăn xếp chính xác, hãy xem tại https://github.com/ztrue/tracerr

Tôi đã tạo gói này để có cả dấu vết ngăn xếp và phân đoạn nguồn để có thể gỡ lỗi nhanh hơn và ghi lại lỗi với nhiều chi tiết hơn.

Đây là một ví dụ về mã:

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

Và đây là kết quả: dấu vết ngăn xếp lỗi golang

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.