방금 호출 한 오류의 줄 번호를 인쇄하는 Golang 프로그램을 어떻게 얻습니까?


96

내 Golang 프로그램에서 오류를 던지려고 log.Fatal했지만 실행 된 log.Fatal줄도 인쇄하지 않습니다 log.Fatal. log.Fatal을 호출 한 줄 번호에 액세스 할 수있는 방법이 없습니까? 즉, 오류를 던질 때 줄 번호를 얻는 방법이 있습니까?

나는 이것을 구글로 시도했지만 방법을 확신하지 못했습니다. 내가 얻을 수있는 가장 좋은 방법 은 스택 트레이스를 인쇄하는 것이 었는데 , 이것은 좋지만 너무 많을 수 있습니다. 나는 또한 debug.PrintStack()줄 번호가 필요할 때마다 쓰고 싶지 않습니다. 이와 같은 기능 log.FatalStackTrace()이나 의상이 아닌 것에 대한 내장 기능이 없다는 것에 놀랐습니다 .

또한, 내가 직접 디버깅 / 오류 처리를하고 싶지 않은 이유는 사람들이 내 특별한 의상 처리 코드를 사용하는 방법을 배우지 않기를 원하기 때문입니다. 나는 사람들이 나중에 내 코드를 읽고

"아 좋아, 그래서 오류가 발생하고 X를 수행하는 중 ..."

사람들이 내 코드에 대해 배울수록 더 좋습니다. :)



줄 번호를 인쇄하는 순간 나는 당신의 코드에 깊이 빠져 들어야 할 것이므로 "내 코드에 대해 배우는 사람이 적을수록 더 좋다"는 것이 논쟁의 여지가 있습니다. 당신이해야 할 일은 명확하고 간결한 오류가있는 것입니다.
Wessie

답변:


124

사용자 정의 로거에서 플래그를 설정하거나 기본값을 포함 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 2014-07-17

정말 변수를 만들어야합니까? 내 go 파일 상단에서 log.SetFlags (log.LstdFlags | log.Lshortfile) 할 수 없습니까? 오류가 발생합니다. expected declaration, found 'INDENT' log시도 할 때 log.SetFlags(log.LstdFlags | log.Lshortfile). 그것에 대한 변수를 만들어야한다는 것은 나를 짜증나게합니다. 왜 log.Fatal("string", log.Flag). 그러나 새 변수 로그를 만들면 효과가있었습니다. 로그 변수 등을 만드는 것이 표준입니까?
피노키오

3
@Pinocchio :이 오류는 유효한 Go가 아니기 때문에 최상위 수준에서 베어 함수 호출을 가질 수 없습니다. init () 또는 다른 진입 점에 넣으십시오.
JimB 2014

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파일 이름이 아닌 함수로 생각 합니다.
sshow

1
대박! 감사. 이것은 runtime패키지 사용 의 좋은 예입니다 . 로그를 통한 디버깅에 매우 유용합니다.
18augst

2

정확히 스택 추적이 필요한 경우 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 오류 스택 추적

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.