고 루틴 스택 트레이스를 덤프하는 방법은 무엇입니까?


답변:


108

에 대한 스택 추적을 인쇄하려면 현재의 goroutine 사용 PrintStack()에서runtime/debug .

PrintStack은 Stack이 반환 한 스택 추적을 표준 오류로 인쇄합니다.

예를 들면 :

import(
   "runtime/debug"
)
...    
debug.PrintStack()

스택 추적을 인쇄하려면 모든 goroutines 사용 Lookup하고 WriteTo부터 runtime/pprof.

func Lookup(name string) *Profile
// Lookup returns the profile with the given name,
// or nil if no such profile exists.

func (p *Profile) WriteTo(w io.Writer, debug int) error
// WriteTo writes a pprof-formatted snapshot of the profile to w.
// If a write to w returns an error, WriteTo returns that error.
// Otherwise, WriteTo returns nil.

각 프로필에는 고유 한 이름이 있습니다. 몇 가지 프로필이 미리 정의되어 있습니다.

goroutine-모든 현재 고 루틴
힙의
스택 추적- 모든 힙 할당의 샘플링 threadcreate-새 OS 스레드
블록 생성으로 이어진 스택 추적-동기화 기본 요소에 대한 차단으로 이어진 스택 추적

예를 들면 :

pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)

1
모든 고 루틴의 스택 추적을 인쇄합니까?

그것은 호출해야합니다 Stack. "Stack은이를 호출하는 goroutine의 형식화 된 스택 추적을 반환합니다. 각 루틴에 대해 소스 행 정보와 PC 값이 포함 된 다음 Go 함수의 경우 호출 함수 또는 메서드와 기도."
Intermernet 2013 년

1
죄송합니다. 현재 고 루틴 스택 추적 만 인쇄합니다.

4
@HowardGuo 런타임 / pprof를 사용하여 모든 스택 추적을 덤프하는 예제를 추가했습니다.
Intermernet

1
나는이 각 스레드의 현재 실행중인 goroutine이 아닌 출력만을 생각하는 모든 : goroutines, 전 play.golang.org/p/0hVB0_LMdm
rogerdpack

42

runtime/pprofIntermernet의 답변에 언급 된 패키지에 대한 HTTP 프런트 엔드가 있습니다 . net / http / pprof 패키지를 가져와 다음에 대한 HTTP 처리기를 등록합니다 /debug/pprof.

import _ "net/http/pprof"
import _ "net/http"

HTTP 리스너가 아직없는 경우 시작하십시오.

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()

그런 다음 브라우저에서 http://localhost:6060/debug/pprof메뉴 또는 http://localhost:6060/debug/pprof/goroutine?debug=2전체 고 루틴 스택 덤프를 가리 킵니다.

이런 식으로 코드를 실행하는 것에 대해 배울 수있는 다른 재미있는 것도 있습니다. 예제 및 자세한 내용은 블로그 게시물을 확인하십시오. http://blog.golang.org/profiling-go-programs


나는 그것을 실행시켜 내가 보는 한 실행 된 고 루틴만을 보여준다. main.go가 시작된 후 실행되는 모든 "메서드"를 볼 수있는 방법이 있습니까?
Lukas Lukac

38

SIGQUIT에서 스택 덤프의 Java 동작을 모방하지만 프로그램을 계속 실행하려면 다음을 수행하십시오.

go func() {
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGQUIT)
    buf := make([]byte, 1<<20)
    for {
        <-sigs
        stacklen := runtime.Stack(buf, true)
        log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen])
    }
}()

4
나는 이것이 저자가 정말로 찾고있는 것이라고 생각한다. 당신이 kill -QUIT를 보낼 때 자바가하는 일을 모방한다. 한 가지 작은 변경 사항은 for () 루프의 첫 번째 줄을 "<-sigs"로 변경하는 것입니다. 즉, 신호를 기다린 후 버립니다. 최신 버전의 Go에서는 나중에 사용하지 않고 변수를 선언 할 수 없습니다.
George Armhold 2015 년

@Bryan, BSD 또는 StackOverflow에서 요구하는 CC-BY-SA 3.0에 추가로 더 관대 한 조건에 따라 라이선스를 부여 하시겠습니까?
Charles Duffy

1
@CharlesDuffy 당신은 여기에 아파치 라이선스에 따라 거의 같은 일을 찾을 수 있습니다 github.com/weaveworks/weave/blob/...
브라이언

37

Java와 마찬가지로 SIGQUIT는 Go 프로그램 및 해당 고 루틴의 스택 추적을 인쇄하는 데 사용할 수 있습니다.
그러나 주요 차이점은 기본적으로 SIGQUIT를 Java 프로그램에 전송하면 종료되지 않지만 Go 프로그램은 종료된다는 것입니다.

이 접근 방식은 기존 프로그램의 모든 고 루틴의 스택 추적을 인쇄하기 위해 코드를 변경할 필요가 없습니다.

환경 변수 GOTRACEBACK ( 런타임 패키지 설명서 참조 )은 생성되는 출력의 양을 제어합니다. 예를 들어 모든 고 루틴을 포함하려면 GOTRACEBACK = all을 설정합니다.

스택 추적의 인쇄는 원래이 commit에 문서화 된 예기치 않은 런타임 조건 (처리되지 않은 신호)에 의해 트리거되어 최소 Go 1.1 이후부터 사용할 수 있습니다.


또는 소스 코드 수정이 옵션 인 경우 다른 답변을 참조하십시오.


Linux 터미널에서 SIGQUIT는 Ctrl+ 키 조합을 사용하여 편리하게 전송할 수 있습니다 \.


5
문서를 살펴 보는 동안 SIGQUIT에 대한 언급이 아니라 SIGABRT에 대한 언급을 찾지 못했습니다. 내 자신의 테스트 (go 1.7 포함)에서 후자는 전자보다 작동했습니다.
soltysh

4
이것이 최고의 답변이어야합니다.
Steven Soroka

문서는 "복구되지 않은 패닉 또는 예기치 않은 런타임 조건으로 인해 Go 프로그램이 실패하는 경우"를 참조합니다. 포착되지 않은 신호 (SIGQUIT 등)는 후자 중 하나입니다. SIGQUIT을 언급 한 이유는 무엇입니까? OP는 SIGQUIT를 Java와 함께 사용하는 것에 대한 애정을 표현하기 때문에이 답변은 유사성을 강조합니다. 더 명확하게 대답을 바꾸십시오.
Rodolfo Carvalho

26

runtime.Stack 을 사용 하여 모든 고 루틴의 스택 추적을 가져올 수 있습니다 .

buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)

문서에서 :

func Stack(buf []byte, all bool) int

Stack은 호출하는 goroutine의 스택 추적을 buf로 포맷하고 buf에 기록 된 바이트 수를 반환합니다. 모두 참이면 스택은 현재 고 루틴에 대한 추적 후에 다른 모든 고 루틴의 스택 추적을 buf로 형식화합니다.


여기에는 모든 고 루틴의 역 추적이 포함됩니다 .
rogerdpack

이것이 회복되지 않은 패닉이 사용하는 형식인가?
Ztyx 2014

2
string (buf)를 추가하는 것을 잊지 마십시오. 그렇지 않으면 거기에 원시 바이트를 인쇄 할 것입니다.
koda

2
내가 뭔가 잘못했거나 기능이 변경되었지만 빈 바이트 조각을 제외하고는 아무것도 검색하지 않습니까?
17xande 2011

1
@koda 할 필요가 없습니다 string(buf)여기 fmt.Printf("%s", buf)fmt.Printf("%s", string(buf))똑같은 (대한 문서를 참조 할 fmt패키지); 여기서 유일한 차이점은 string버전이 buf불필요하게 바이트를 복사한다는 것입니다
kbolino

20

Ctrl + \를 누릅니다.

(터미널에서 실행하고 프로그램을 종료하고 go 루틴을 덤프하려는 경우)

이 질문은 키 시퀀스를 찾고 있습니다. 내 프로그램이 루틴을 유출하는지 빠르고 쉬운 방법을 원했습니다. :)


11

* NIX 시스템 (OSX 포함)에서 abort 신호를 보냅니다 SIGABRT.

pkill -SIGABRT program_name


분명히 SIGQUIT를 Java 프로세스에 보내는 것은 SIGABRT처럼 종료되지 않습니다 .
Dave C

나는 이것이 원래 질문에 가장 간단하고 가장 일치하는 솔루션이라는 것을 알았습니다. 종종 코드를 변경하지 않고 즉시 스택 트레이스가 필요합니다.
jotrocken

5

runtime.Stack()스택 추적 후 빈 줄을 인쇄하지 않으려면에서 반환 된 길이를 사용해야합니다 . 다음 복구 함수는 멋지게 형식화 된 추적을 인쇄합니다.

if r := recover(); r != nil {
    log.Printf("Internal error: %v", r))
    buf := make([]byte, 1<<16)
    stackSize := runtime.Stack(buf, true)
    log.Printf("%s\n", string(buf[0:stackSize]))
}

없다 runtime.Trace; runtime.Stack 이미 1 년 반 전에 언급되었습니다 .
Dave C

나는 본 적이 없다. 어떤 플랫폼에서 실행 중입니까?
Bryan

당신이 보지 못한 것은 무엇입니까? 코드는 모든 플랫폼에서 실행되어야합니다. Windows 7, Ubuntu 14.04 및 Mac에서 테스트했습니다.
David Tootill 2015

빈 줄을 본 적이 없습니다.
Bryan

5

기본적으로 ^\키 ( CTRL + \ )를 눌러 모든 고 루틴의 스택 추적을 덤프합니다.


그렇지 않으면보다 세분화 된 제어를 위해 panic. Go 1.6+ 의 간단한 방법 :

go func() {
    s := make(chan os.Signal, 1)
    signal.Notify(s, syscall.SIGQUIT)
    <-s
    panic("give me the stack")
}()

그런 다음 다음과 같이 프로그램을 실행하십시오.

# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go

go 런타임 고 루틴도 인쇄하려면 :

$ GOTRACEBACK=system go run main.go

다음은 모든 GOTRACEBACK 옵션입니다.

  • GOTRACEBACK=none 고 루틴 스택 추적을 완전히 생략합니다.
  • GOTRACEBACK=single (기본값) 위에서 설명한대로 작동합니다.
  • GOTRACEBACK=all 사용자가 만든 모든 고 루틴에 대한 스택 추적을 추가합니다.
  • GOTRACEBACK=system ``all ''과 비슷하지만 런타임 함수에 대한 스택 프레임을 추가하고 런타임에 의해 내부적으로 생성 된 고 루틴을 표시합니다.
  • GOTRACEBACK=crash``시스템 ''과 비슷하지만 종료하는 대신 운영 체제 별 방식으로 충돌합니다. 예를 들어 Unix 시스템에서 크래시가 SIGABRT발생하여 코어 덤프가 트리거됩니다.

다음은 문서입니다.

GOTRACEBACK 변수는 복구되지 않은 패닉 또는 예기치 않은 런타임 조건으로 인해 Go 프로그램이 실패 할 때 생성되는 출력의 양을 제어합니다.

기본적으로 오류는 현재 고 루틴에 대한 스택 추적을 인쇄하여 런타임 시스템 내부의 함수를 제거한 다음 종료 코드 2로 종료됩니다. 오류는 현재 고 루틴이 없거나 오류가있는 경우 모든 고 루틴에 대한 스택 추적을 인쇄합니다. 런타임 내부.

역사적 이유로 GOTRACEBACK 설정 0, 1 및 2는 각각 none, all 및 system의 동의어입니다.

런타임 / 디버그 패키지의 SetTraceback 함수를 사용하면 런타임에 출력량을 늘릴 수 있지만 환경 변수에 지정된 값 이하로 줄일 수는 없습니다. https://golang.org/pkg/runtime/debug/#SetTraceback을 참조 하십시오 .

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