저는 Java 배경 지식이 있으며 Java 스레드 덤프를 검사하기 위해 신호 QUIT를 사용하는 것을 좋아합니다.
Golang이 모든 고 루틴 스택 추적을 인쇄하도록하는 방법은 무엇입니까?
답변:
에 대한 스택 추적을 인쇄하려면 현재의 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)
Stack
. "Stack은이를 호출하는 goroutine의 형식화 된 스택 추적을 반환합니다. 각 루틴에 대해 소스 행 정보와 PC 값이 포함 된 다음 Go 함수의 경우 호출 함수 또는 메서드와 기도."
runtime/pprof
Intermernet의 답변에 언급 된 패키지에 대한 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
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])
}
}()
Java와 마찬가지로 SIGQUIT는 Go 프로그램 및 해당 고 루틴의 스택 추적을 인쇄하는 데 사용할 수 있습니다.
그러나 주요 차이점은 기본적으로 SIGQUIT를 Java 프로그램에 전송하면 종료되지 않지만 Go 프로그램은 종료된다는 것입니다.
이 접근 방식은 기존 프로그램의 모든 고 루틴의 스택 추적을 인쇄하기 위해 코드를 변경할 필요가 없습니다.
환경 변수 GOTRACEBACK ( 런타임 패키지 설명서 참조 )은 생성되는 출력의 양을 제어합니다. 예를 들어 모든 고 루틴을 포함하려면 GOTRACEBACK = all을 설정합니다.
스택 추적의 인쇄는 원래이 commit에 문서화 된 예기치 않은 런타임 조건 (처리되지 않은 신호)에 의해 트리거되어 최소 Go 1.1 이후부터 사용할 수 있습니다.
또는 소스 코드 수정이 옵션 인 경우 다른 답변을 참조하십시오.
Linux 터미널에서 SIGQUIT는 Ctrl+ 키 조합을 사용하여 편리하게 전송할 수 있습니다 \.
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로 형식화합니다.
string(buf)
여기 fmt.Printf("%s", buf)
와 fmt.Printf("%s", string(buf))
똑같은 (대한 문서를 참조 할 fmt
패키지); 여기서 유일한 차이점은 string
버전이 buf
불필요하게 바이트를 복사한다는 것입니다
Ctrl + \를 누릅니다.
(터미널에서 실행하고 프로그램을 종료하고 go 루틴을 덤프하려는 경우)
이 질문은 키 시퀀스를 찾고 있습니다. 내 프로그램이 루틴을 유출하는지 빠르고 쉬운 방법을 원했습니다. :)
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]))
}
기본적으로 ^\
키 ( 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을 참조 하십시오 .