Skip to content

Commit 9bec28d

Browse files
committed
runtime: add goroutine labels to traceback/debug=2 headers
This is a small, self-contained patch to include goroutine labels in the debug=2/ traceback/runtime.Stack format goroutine dumps, as labels are extremely useful in correlating a given goroutine with some user-facing operation or behavior. We cannot directly import or use the pprof.labelMap type in the traceback code, but we can cast to an equivalent type and iterate over it to print the labels. This adds them to the header, eg. goroutine 123 [select, 7m, "foobar:1", "barbaz:abc"]:
1 parent 370d2fb commit 9bec28d

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

src/runtime/traceback.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,9 +1264,23 @@ func goroutineheader(gp *g) {
12641264
if bubble := gp.bubble; bubble != nil {
12651265
print(", synctest bubble ", bubble.id)
12661266
}
1267+
if gp.labels != nil {
1268+
printLabelMap(gp.labels)
1269+
}
12671270
print("]:\n")
12681271
}
12691272

1273+
// printLabelMap prints a pprof.labelMap while avoiding a dependency on pprof.
1274+
func printLabelMap(p unsafe.Pointer) {
1275+
if p == nil {
1276+
return
1277+
}
1278+
// This must match the layout of pprof/label.go's labelMap and labelSet.
1279+
for _, lbl := range *(*([]struct{ k, v string }))(p) {
1280+
print(`, "`, lbl.k, `":"`, lbl.v, `"`)
1281+
}
1282+
}
1283+
12701284
func tracebackothers(me *g) {
12711285
tracebacksomeothers(me, func(*g) bool { return true })
12721286
}

src/runtime/traceback_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ package runtime_test
66

77
import (
88
"bytes"
9+
"context"
910
"fmt"
1011
"internal/abi"
1112
"internal/testenv"
1213
"regexp"
1314
"runtime"
1415
"runtime/debug"
16+
"runtime/pprof"
1517
"strconv"
1618
"strings"
1719
"sync"
@@ -867,3 +869,15 @@ func TestTracebackGeneric(t *testing.T) {
867869
}
868870
}
869871
}
872+
873+
func TestTracebackContainsLabels(t *testing.T) {
874+
pprof.Do(context.Background(), pprof.Labels("foolabel", "barvalue"), func(_ context.Context) {
875+
buf := make([]byte, 1<<10)
876+
n := runtime.Stack(buf, false)
877+
header := strings.Split(string(buf[:n]), "\n")[0]
878+
t.Log(header)
879+
if !strings.Contains(header, `"foolabel":"barvalue"`) {
880+
t.Errorf("stack does not contain label:\n%s", string(buf[:n]))
881+
}
882+
})
883+
}

0 commit comments

Comments
 (0)