我有一个简单的golang程序:
package main
import (
"fmt"
"net/http"
_ "net/http/pprof"
"os/exec"
)
func bar() {
// wait 5 seconds
cmd := exec.Command("sleep", "5")
err := cmd.Run()
if err != nil {
panic(err)
}
}
func fooHandler(w http.ResponseWriter, r *http.Request) {
bar()
fmt.Fprintf(w, "Hello, world!")
}
func main() {
http.HandleFunc("/foo", fooHandler)
http.ListenAndServe(":8080", nil)
}
我想做的就是使用 golang 的跟踪功能来查明导致 5 秒延迟的函数。但是,我不知道该怎么做。
我已经跑了
curl -o trace.out http://localhost:8080/debug/pprof/trace?seconds=20
然后到达
/foo
端点。这会生成一个 trace.out
,我可以使用 go tool trace trace.out
查看它。我可以看到这个:
事实上,在 9 秒标记左右,我可以在可视化工具中看到一个线程花了 5 秒才能完成,但我似乎找不到如何获取堆栈跟踪或可以以某种方式向我指出
bar()
的事实罪魁祸首一直在耗尽。我在这里使用了错误的工具吗?
您有几个选择:
runtime/trace
golang.org/x/net/trace
并使用实时可视化工具如果您想使用事实上的
go tool trace
或 /dominikh/gotraceui
挖掘痕迹的方法,那么选项 1 是最好的。
选项 2 启动很快,但我没有在示例程序之外使用过它。以下是我们如何将其连接到您的示例上:
package main
import (
"context"
"fmt"
"net/http"
_ "net/http/pprof"
"os/exec"
"golang.org/x/net/trace"
)
func bar(ctx context.Context) {
tr, _ := trace.FromContext(ctx)
tr.LazyPrintf("bar")
cmd := exec.Command("sleep", "5")
err := cmd.Run()
if err != nil {
panic(err)
}
}
func fooHandler(w http.ResponseWriter, r *http.Request) {
tr := trace.New("foo", r.URL.Path)
defer tr.Finish()
ctx := trace.NewContext(r.Context(), tr)
bar(ctx)
fmt.Fprintf(w, "Hello, world!")
}
func main() {
// This pulls in /debug/requests and /debug/events
mux := http.DefaultServeMux
mux.HandleFunc("/foo", fooHandler)
http.ListenAndServe(":8080", mux)
}
向
/foo
发出请求后,我们可以在浏览器中打开localhost:8080/debug/requests
看到以下内容: