diff options
| author | demo <demo@antix1> | 2026-05-26 15:31:39 -0400 |
|---|---|---|
| committer | demo <demo@antix1> | 2026-05-26 15:31:39 -0400 |
| commit | ec38d615c488c73b892ff19c868d38a3c646d22b (patch) | |
| tree | b1236990e39e800740b5c09af06379619299d44d /main.go | |
| parent | ad30fff0b7dbce0e46995ab41d6f5beba341cbff (diff) | |
feat: add gouroutine-leak profiling
Diffstat (limited to 'main.go')
| -rw-r--r-- | main.go | 28 |
1 files changed, 27 insertions, 1 deletions
@@ -7,7 +7,10 @@ import ( "fmt" "log" "net/url" + "runtime/pprof" + "strings" "sync" + "time" ) func main() { @@ -38,7 +41,9 @@ func main() { log.Fatal(err) } - pool(*startURL, *maxConcurrency, *maxURLs) + getLeakProfile(func() { + pool(*startURL, *maxConcurrency, *maxURLs) + }) } func pool(startURL url.URL, maxConcurrency, maxURLs int) { @@ -117,3 +122,24 @@ func fanIn(chans ...<-chan []url.URL) <-chan []url.URL { return out } + +// getLeakProfile runs a leaky program snippet, extracts the goroutine leak profile, +// and writes it to stdout. +func getLeakProfile(leakySnippet func()) { + prof := pprof.Lookup("goroutineleak") + defer func() { + time.Sleep(2 * time.Second) + var content strings.Builder + + prof.WriteTo(&content, 2) + // Ignore non leaked goroutines + leaks := strings.Split(content.String(), "\n\n") + for _, leak := range leaks { + if strings.Contains(leak, "(leaked)") { + fmt.Println(leak + "\n") + } + } + }() + + leakySnippet() +} |
