| 1 | // Package goroutine provides utilities for inspecting goroutines |
| 2 | // at runtime, including obtaining IDs and stack traces. |
| 3 | package goroutine |
| 4 | |
| 5 | import ( |
| 6 | "bytes" |
| 7 | "runtime" |
| 8 | "strconv" |
| 9 | ) |
| 10 | |
| 11 | // ID returns the goroutine ID of the caller. |
| 12 | func ID() uint64 { |
| 13 | var buf [64]byte |
| 14 | n := runtime.Stack(buf[:], false) |
| 15 | // Format: "goroutine 123 [running]:\n..." |
| 16 | s := buf[:n] |
| 17 | s = s[len("goroutine "):] |
| 18 | i := bytes.IndexByte(s, ' ') |
| 19 | id, _ := strconv.ParseUint(string(s[:i]), 10, 64) |
| 20 | return id |
| 21 | } |
| 22 | |
| 23 | // Stack returns the stack trace for the goroutine with the given ID. |
| 24 | // Returns an empty string if the goroutine is not found. |
| 25 | func Stack(goid uint64) string { |
| 26 | buf := make([]byte, 1<<16) |
| 27 | n := runtime.Stack(buf, true) |
| 28 | buf = buf[:n] |
| 29 | |
| 30 | target := []byte("goroutine " + strconv.FormatUint(goid, 10) + " ") |
| 31 | idx := bytes.Index(buf, target) |
| 32 | if idx < 0 { |
| 33 | return "" |
| 34 | } |
| 35 | |
| 36 | rest := buf[idx:] |
| 37 | end := bytes.Index(rest[1:], []byte("\ngoroutine ")) |
| 38 | if end < 0 { |
| 39 | return string(rest) |
| 40 | } |
| 41 | return string(rest[:end+1]) |
| 42 | } |
| 43 | |