ฉันมีพื้นหลัง Java และฉันชอบใช้สัญญาณ QUIT เพื่อตรวจสอบการถ่ายโอนข้อมูลเธรด Java
จะให้ Golang พิมพ์ goroutines stack trace ได้อย่างไร?
ฉันมีพื้นหลัง Java และฉันชอบใช้สัญญาณ QUIT เพื่อตรวจสอบการถ่ายโอนข้อมูลเธรด Java
จะให้ Golang พิมพ์ goroutines stack trace ได้อย่างไร?
คำตอบ:
หากต้องการพิมพ์กองติดตามสำหรับปัจจุบัน 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 - สแต็กเทรซของ goroutines
heap ปัจจุบันทั้งหมด- การสุ่มตัวอย่างของการจัดสรร heap ทั้งหมด
threadcreate - สแต็กเทรซที่นำไปสู่การสร้าง
บล็อกเธรด OS ใหม่- สแต็กเทรซที่นำไปสู่การบล็อกบนพื้นฐานการซิงโครไนซ์
ตัวอย่างเช่น:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
Stack
มันควรจะเรียก "Stack ส่งคืนการติดตามสแต็กที่จัดรูปแบบแล้วของ goroutine ที่เรียกมันสำหรับแต่ละรูทีนจะมีข้อมูลรายการต้นทางและค่าพีซีจากนั้นจะพยายามค้นหาสำหรับฟังก์ชัน Go ฟังก์ชันการโทรหรือวิธีการและข้อความของบรรทัดที่มี การวิงวอน "
มีส่วนหน้า HTTP สำหรับruntime/pprof
แพ็คเกจที่กล่าวถึงในคำตอบของ Intermernet นำเข้าแพ็คเกจ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
สำหรับกองถ่าย goroutine แบบเต็ม
ยังมีเรื่องสนุก ๆ อื่น ๆ ที่คุณสามารถเรียนรู้เกี่ยวกับโค้ดที่ใช้งานได้ด้วยวิธีนี้ ดูตัวอย่างและรายละเอียดเพิ่มเติมในบล็อกโพสต์: http://blog.golang.org/profiling-go-programs
ในการเลียนแบบพฤติกรรม Java ของสแต็กดัมพ์บน SIGQUIT แต่ยังคงปล่อยให้โปรแกรมทำงานอยู่:
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 สามารถใช้เพื่อพิมพ์ stack trace ของโปรแกรม Go และ goroutines
อย่างไรก็ตามความแตกต่างที่สำคัญคือโดยค่าเริ่มต้นการส่ง SIGQUIT ไปยังโปรแกรม Java จะไม่ยุติลงในขณะที่โปรแกรม Go จะออก
วิธีนี้ไม่จำเป็นต้องเปลี่ยนรหัสเพื่อพิมพ์ stack trace ของ goroutines ทั้งหมดของโปรแกรมที่มีอยู่
ตัวแปรสภาพแวดล้อม GOTRACEBACK ( ดูเอกสารประกอบของแพ็กเกจรันไทม์ ) ควบคุมจำนวนเอาต์พุตที่สร้างขึ้น ตัวอย่างเช่นหากต้องการรวม goroutines ทั้งหมดให้ตั้งค่า GOTRACEBACK = all
การพิมพ์การติดตามสแต็กถูกทริกเกอร์โดยเงื่อนไขรันไทม์ที่ไม่คาดคิด (สัญญาณที่ไม่ได้จัดการ) ซึ่งเดิมบันทึกไว้ในคอมมิตนี้ทำให้พร้อมใช้งานตั้งแต่อย่างน้อย Go 1.1
หรือหากเป็นทางเลือกในการแก้ไขซอร์สโค้ดโปรดดูคำตอบอื่น ๆ
ทราบว่าในขั้ว Linux, SIGQUIT สามารถส่งสะดวกสบายด้วยคีย์ผสม+Ctrl\
คุณสามารถใช้runtime.Stackเพื่อรับ stack trace ของ goroutines ทั้งหมด:
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)
จากเอกสารประกอบ:
func Stack(buf []byte, all bool) int
Stack จัดรูปแบบการติดตามสแต็กของ goroutine ที่เรียกเป็น buf และส่งคืนจำนวนไบต์ที่เขียนไปยัง buf ถ้าทั้งหมดเป็นจริง Stack จะจัดรูปแบบสแต็กเทรซของ goroutines อื่น ๆ ทั้งหมดลงใน buf หลังจากการติดตามสำหรับ goroutine ปัจจุบัน
string(buf)
ที่นี่fmt.Printf("%s", buf)
และfmt.Printf("%s", string(buf))
ทำสิ่งเดียวกันทุกประการ(ดูเอกสารสำหรับfmt
แพ็คเกจ); ข้อแตกต่างเพียงอย่างเดียวคือstring
เวอร์ชันจะคัดลอกไบต์จากbuf
โดยไม่จำเป็น
กดCTRL + \
(หากคุณเรียกใช้ในเทอร์มินัลและเพียงแค่ต้องการฆ่าโปรแกรมของคุณและทิ้งกิจวัตรการไป ฯลฯ )
ฉันพบว่าคำถามนี้กำลังมองหาลำดับคีย์ แค่อยากได้วิธีที่ง่ายและรวดเร็วในการบอกว่าโปรแกรมของฉันรั่วไหลหรือไม่ :)
บนระบบ * NIX (รวม OSX) ส่งสัญญาณยกเลิกSIGABRT
:
pkill -SIGABRT program_name
จำเป็นต้องใช้ความยาวที่ส่งคืน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 + \ ) เพื่อดัมพ์สแต็กเทรซของ goroutines ทั้งหมด
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 runtime goroutines ด้วย:
$ GOTRACEBACK=system go run main.go
นี่คือตัวเลือก GOTRACEBACK ทั้งหมด:
GOTRACEBACK=none
ละเว้นการติดตามกองซ้อน goroutine โดยสิ้นเชิงGOTRACEBACK=single
(ค่าเริ่มต้น)ทำงานตามที่อธิบายไว้ข้างต้นGOTRACEBACK=all
เพิ่มสแต็กเทรซสำหรับ goroutines ที่ผู้ใช้สร้างขึ้นทั้งหมดGOTRACEBACK=system
เหมือนกับ `` ทั้งหมด '' แต่จะเพิ่มสแต็กเฟรมสำหรับฟังก์ชันรันไทม์และแสดง goroutines ที่สร้างขึ้นภายในโดยรันไทม์GOTRACEBACK=crash
เป็นเหมือน `` ระบบ '' แต่ขัดข้องในลักษณะเฉพาะของระบบปฏิบัติการแทนที่จะออก ตัวอย่างเช่นในระบบ Unix ความผิดพลาดจะเพิ่มขึ้นSIGABRT
เพื่อทริกเกอร์ดัมพ์หลักตัวแปร GOTRACEBACK ควบคุมจำนวนเอาต์พุตที่สร้างขึ้นเมื่อโปรแกรม Go ล้มเหลวเนื่องจากความตื่นตระหนกที่ไม่ได้รับการกู้คืนหรือสภาวะรันไทม์ที่ไม่คาดคิด
ตามค่าเริ่มต้นความล้มเหลวจะพิมพ์สแต็กแทร็กสำหรับ goroutine ปัจจุบันโดยกำหนดฟังก์ชันภายในระบบรันไทม์จากนั้นออกด้วยโค้ด exit 2 ความล้มเหลวจะพิมพ์สแต็กเทรซสำหรับ goroutines ทั้งหมดหากไม่มี goroutine ในปัจจุบันหรือความล้มเหลวคือ ภายในรันไทม์
ด้วยเหตุผลทางประวัติศาสตร์การตั้งค่า GOTRACEBACK 0, 1 และ 2 จึงเป็นคำพ้องความหมายของ none ทั้งหมดและระบบตามลำดับ
ฟังก์ชัน SetTraceback ของแพ็กเกจรันไทม์ / ดีบักอนุญาตให้เพิ่มจำนวนเอาต์พุตในขณะรัน แต่ไม่สามารถลดจำนวนที่ต่ำกว่าที่ระบุโดยตัวแปรสภาพแวดล้อมได้ ดูhttps://golang.org/pkg/runtime/debug/#SetTraceback