spancheck は OpenTelemetry / OpenCensus のスパンが正しく扱われているかをチェックするツールです。
解決する問題 分散トレーシングのスパンは、作成後に必ず終了(End)し、エラー時にはステータス設定やエラー記録を行う必要があります。これらのボイラープレートを忘れると、メモリリーク、トレースの欠落、障害調査時の情報不足を引き起こします。
1 2 3 4 5 6 7 8 9 10 11 12 13 func ProcessOrder (ctx context.Context, orderID string ) error { ctx, span := tracer.Start(ctx, "ProcessOrder" ) order, err := fetchOrder(ctx, orderID) if err != nil { return fmt.Errorf("fetch order %s: %w" , orderID, err) } return nil }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func ProcessOrder (ctx context.Context, orderID string ) error { ctx, span := tracer.Start(ctx, "ProcessOrder" ) defer span.End() order, err := fetchOrder(ctx, orderID) if err != nil { span.SetStatus(codes.Error, err.Error()) span.RecordError(err) return fmt.Errorf("fetch order %s: %w" , orderID, err) } _ = order return nil }
設定 公式ドキュメント
1 2 3 4 5 6 7 8 9 10 11 12 version: "2" linters: enable: - spancheck settings: spancheck: checks: - end - set-status - record-error
オプション
オプション
型
デフォルト
説明
checks
[]string
[end]
有効にするチェック。end、set-status、record-error を指定可能
ignore-check-signatures
[]string
[]
指定したシグネチャの関数呼び出しがある場合、チェックを抑制する
extra-start-span-signatures
[]string
[]
カスタムのスパン開始関数を追加する
チェックの種類
チェック
デフォルト
検出内容
end
有効
span.End() が呼ばれていない
set-status
無効
エラーパスで span.SetStatus(codes.Error, ...) が呼ばれていない
record-error
無効
エラーパスで span.RecordError(err) が呼ばれていない
サンプル 検出例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 func example1 (ctx context.Context) error { _, span := tracer.Start(ctx, "example1" ) return doWork(ctx) } func example2 (ctx context.Context) error { ctx, span := tracer.Start(ctx, "example2" ) defer span.End() if err := doWork(ctx); err != nil { return err } return nil } func example3 (ctx context.Context) error { ctx, span := tracer.Start(ctx, "example3" ) defer span.End() if err := doWork(ctx); err != nil { span.SetStatus(codes.Error, err.Error()) return err } return nil }
修正例 1 2 3 4 5 6 7 8 9 10 11 func example (ctx context.Context) error { ctx, span := tracer.Start(ctx, "example" ) defer span.End() if err := doWork(ctx); err != nil { span.SetStatus(codes.Error, err.Error()) span.RecordError(err) return fmt.Errorf("do work: %w" , err) } return nil }
カスタムスパン関数の登録 1 2 3 4 5 6 7 8 9 10 11 12 linters: settings: spancheck: checks: - end - set-status - record-error extra-start-span-signatures: - "github.com/myorg/pkg/trace.Start:opentelemetry" ignore-check-signatures: - "github.com/myorg/pkg/telemetry.RecordError"
注意点
end チェックはデフォルトで有効。set-status と record-error は明示的に有効化する必要がある
ignore-check-signatures を使うと、ヘルパー関数内でエラー処理を一括で行っている場合に誤検知を抑制できる
OpenTelemetry の仕様上、スパンが End されないとバックエンドに送信されずメモリリークの原因になる
OpenCensus を使っている場合も同様にチェックされる
参考リンク