メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

挙動変更

go directiveがGo 1.27以降のモジュールでは、トレースバックのgoroutineヘッダー行にruntime/pprofのゴルーチンラベルが既定で表示されるようになった

Runtime

この項目の注釈は AI により生成されており、誤りを含む場合があります。
使用例のコンパイル検証: 検証済み

概要

go.modgo directiveでGo 1.27以降を指定するモジュールでは、パニック時などに出力される
トレースバックの goroutine ヘッダー行に、runtime/pprof
で設定したゴルーチンラベルが既定で含まれるようになった。この挙動は、Go 1.26で追加された
GODEBUG 設定 tracebacklabels=0 を指定することで無効化できる。
このオプトアウトは、ゴルーチンラベルに機微な情報が含まれてトレースバックに漏れてしまう
ケースに備え、今後も恒久的に維持される見込みである。

使用例

Before

package main

import (
	"context"
	"fmt"
	"runtime"
	"runtime/pprof"
)

func main() {
	ctx := pprof.WithLabels(context.Background(), pprof.Labels("request_id", "abc123"))
	pprof.SetGoroutineLabels(ctx)

	buf := make([]byte, 1<<12)
	n := runtime.Stack(buf, false)
	fmt.Print(string(buf[:n]))
}

// go directiveがGo 1.27未満、またはGODEBUG=tracebacklabels=0の場合のヘッダー行:
// goroutine 1 [running]:

After

package main

import (
	"context"
	"fmt"
	"runtime"
	"runtime/pprof"
)

func main() {
	ctx := pprof.WithLabels(context.Background(), pprof.Labels("request_id", "abc123"))
	pprof.SetGoroutineLabels(ctx)

	buf := make([]byte, 1<<12)
	n := runtime.Stack(buf, false)
	fmt.Print(string(buf[:n]))
}

// go directiveがGo 1.27以降の場合(既定)のヘッダー行:
// goroutine 1 [running] {request_id: abc123}:

移行時の注意

  • ラベルのキー・値は、英数字・./_ 以外の文字を含む場合や、制御文字・改行を含む場合は
    ダブルクォートで囲まれエスケープされた上で出力される。
  • パニックログやトレースバックを機械的にパース・照合しているツールがある場合、ヘッダー行の末尾に
    {key: value, ...} が挿入されることで既存のパース処理が壊れる可能性がある。影響がある場合は
    GODEBUG=tracebacklabels=0 で従来どおりの出力に固定できる。
  • ゴルーチンラベルにトークンや個人情報など機微な情報を設定している場合、それらがトレースバックに
    そのまま出力される点に注意が必要である。

実装解説

ヘッダー行への埋め込みは
runtime/traceback.go
goroutineheader 相当の処理で行われており、gp.labels != nil && debug.tracebacklabels.Load() == 1
の場合に、ゴルーチンの label.Set をキーでソートした状態で {key: value, ...} の形式で
] の直後・: の直前に出力する。

tracebacklabels の既定値は
runtime1.go
dbgvars テーブルで def: 1 として定義されており、
internal/godebugs/table.go
側で Changed: 27, Old: "0" と登録されている。この Changed/Old の組が、go directiveで
Go 1.27以降を指定したモジュールでは既定値 1(ラベル表示あり)を使い、それより前のモジュールでは
Old の値 0(ラベル非表示、従来動作)にフォールバックする仕組みを担っている。なお同エントリは
Opaque: true が指定されており、これはシグナルハンドラ内で生成されるトレースバックから
sync.Once を使う非デフォルト値計測(IncNonDefault)を呼び出せないための措置である。

関連リンク