Hero Image
更强大的Go执行跟踪能力

更强大的 Go 执行跟踪能力 runtime/trace golang.org/x/exp/trace 飞行记录(flight recording) // 设置飞行记录器 fr := trace.NewFlightRecorder() fr.Start() // 设置和运行HTTP服务器 var once sync.Once http.HandleFunc("/my-endpoint", func(w http.ResponseWriter, r *http.Request) { start := time.Now() // 干些事情 doWork(w, r) // 盼到了长耗时请求,来个快照 if time.Since(start) > 300*time.Millisecond { // 这里我们为了简化只做一次,实际上你可以做多次 once.Do(func() { // 抓取快照 var b bytes.Buffer _, err = fr.WriteTo(&b) if err != nil { log.Print(err) return } // 把快照写入文件 if err := os.WriteFile("trace.out", b.Bytes(), 0o755); err != nil { log.Print(err) return } }) } }) log.Fatal(http.ListenAndServe(":8080", nil)) 跟踪读取器 API // 开始从标准输入读取跟踪数据。 r, err := trace.NewReader(os.Stdin) if err != nil { log.Fatal(err) } var blocked int var blockedOnNetwork int for { // 读取事件 ev, err := r.ReadEvent() if err == io.EOF { break } else if err != nil { log.Fatal(err) } // 处理它 if ev.Kind() == trace.EventStateTransition { st := ev.StateTransition() if st.Resource.Kind == trace.ResourceGoroutine { id := st.Resource.Goroutine() from, to := st.GoroutineTransition() // 查找阻塞的goroutine, 统计计数 if from.Executing() && to == trace.GoWaiting { blocked++ if strings.Contains(st.Reason, "network") { blockedOnNetwork++ } } } } } // 打印我们所需 p := 100 * float64(blockedOnNetwork) / float64(blocked) fmt.Printf("%2.3f%% instances of goroutines blocking were to block on the network\n", p)