mcpField
P
prometheus-go-code-review

prometheus-go-code-review

github.com/existential-birdsテスト・品質85121 回インストール11 週間前に更新
リポジトリ

prometheus-go-code-review について

Go プロジェクトの Prometheus 計測コードをレビューするスキルです。メトリクス型、ラベルのカーディナリティ、登録ライフサイクル、命名を確認し、指摘には具体的なコード上の根拠を求めます。

主な機能

  1. 01測定内容に合うメトリクス型の確認
  2. 02ラベル値が有界かの点検
  3. 03メトリクス名と単位サフィックスの確認
  4. 04メトリクスが一度だけ登録されるか確認
  5. 05コレクターの並行処理と指標エンドポイントの確認
  6. 06段階的なレビューゲートに基づく指摘

活用シーン

  1. 01Go サービスの Prometheus メトリクスをレビュー
  2. 02高カーディナリティのラベルや型の誤りを発見
  3. 03登録箇所と /metrics の公開を検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/existential-birds/beagle --skill prometheus-go-code-review

インストール後、Claude Code で/prometheus-go-code-reviewを入力して読み込まれたか確認します。

詳細

Prometheus Go コードレビュー

レビューチェックリスト

  • メトリクスの種類が測定の意味と一致している(Counter/Gauge/Histogram)
  • ラベルのカーディナリティが低い(ユーザー ID、タイムスタンプ、パスを含まない)
  • メトリクス名が規則に従っている(snake_case、単位のサフィックス)
  • ヒストグラムで適切なバケット境界を使用している
  • メトリクスは一度だけ登録され、リクエストごとに登録されていない
  • コレクターが競合状態でパニックを起こさない
  • /metrics エンドポイントが公開され、アクセス可能である

ハードゲート(順番に実施)

指摘事項を記録する前に、順番に完了してください。差分に明らかに該当しないゲートはスキップしてください。

  1. エビデンスの範囲 — Prometheus(prometheus/client_golang、promauto、promhttp、または MustRegister)に関係するレビュー対象ファイルを列挙します。合格条件:(差分または明示的なファイルセットから)具体的なパスの一覧があること。少なくとも 1 つのパスを示さずにリポジトリ全体について主張しないこと。

  2. ラベルのカーディナリティ — 対象範囲内の各 *Vec またはラベル付きメトリクスについて、ラベル名と値の取得元(定数、上限のあるコード、リクエスト由来の文字列など)を列挙します。合格条件: コードで上限のあるマッピングを使用し、その箇所を明示している場合を除き、上限のない値(生の user_id、完全な URL パス、タイムスタンプなど)を使うラベルがないこと。

  3. 登録のライフサイクル — 対象範囲内のメトリクス定義について、コンストラクターが(パッケージレベルの var、init、または sync.Once によって)一度だけ実行され、リクエストごとのハンドラー内では実行されないことを確認します。合格条件: 同一の論理メトリクスに対して、リクエストごとに新しい Counter/Histogram/*Vec を割り当て、登録するパターンがないこと。

  4. 指摘事項の形式 — 各指摘事項でファイル名(可能であれば行番号またはシンボル名)を示し、問題が実際にある場合にどのゲート(2 または 3)に抵触するかを述べ、確認したコードに結び付けます。合格条件: 該当コードがゲート 2~3 を満たしている場合、単独のスタイル上の指摘をしないこと。

メトリクスの種類の選択

測定対象種類例
処理したリクエスト数Counterrequests_total
キュー内のアイテム数Gaugequeue_length
リクエストの所要時間Histogramrequest_duration_seconds
同時接続数Gaugeactive_connections
起動後のエラー数Countererrors_total
メモリ使用量Gaugememory_bytes

重大なアンチパターン

1. カーディナリティの高いラベル
// BAD - unique per user/request
counter := promauto.NewCounterVec(
    prometheus.CounterOpts{Name: "requests_total"},
    []string{"user_id", "path"},  // millions of series!
)
counter.WithLabelValues(userID, request.URL.Path).Inc()

// GOOD - bounded label values
counter := promauto.NewCounterVec(
    prometheus.CounterOpts{Name: "requests_total"},
    []string{"method", "status_code"},  // <100 series
)
counter.WithLabelValues(r.Method, statusCode).Inc()
2. 誤ったメトリクスの種類
// BAD - using gauge for monotonic value
requestCount := promauto.NewGauge(prometheus.GaugeOpts{
    Name: "http_requests",
})
requestCount.Inc()  // should be Counter!

// GOOD
requestCount := promauto.NewCounter(prometheus.CounterOpts{
    Name: "http_requests_total",
})
requestCount.Inc()
3. リクエストごとの登録
// BAD - new metric per request
func handler(w http.ResponseWriter, r *http.Request) {
    counter := prometheus.NewCounter(...)  // creates new each time!
    prometheus.MustRegister(counter)       // panics on duplicate!
}

// GOOD - register once
var requestCounter = promauto.NewCounter(prometheus.CounterOpts{
    Name: "http_requests_total",
})

func handler(w http.ResponseWriter, r *http.Request) {
    requestCounter.Inc()
}
4. 単位のサフィックスがない
// BAD
duration := promauto.NewHistogram(prometheus.HistogramOpts{
    Name: "request_duration",  // no unit!
})

// GOOD
duration := promauto.NewHistogram(prometheus.HistogramOpts{
    Name: "request_duration_seconds",  // unit in name
})

優れたパターン

メトリクスの定義
var (
    httpRequests = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Namespace: "myapp",
            Subsystem: "http",
            Name:      "requests_total",
            Help:      "Total HTTP requests processed",
        },
        []string{"method", "status"},
    )

    httpDuration = promauto.NewHistogramVec(
        prometheus.HistogramOpts{
            Namespace: "myapp",
            Subsystem: "http",
            Name:      "request_duration_seconds",
            Help:      "HTTP request latencies",
            Buckets:   []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10},
        },
        []string{"method"},
    )
)
ミドルウェアのパターン
func metricsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        timer := prometheus.NewTimer(httpDuration.WithLabelValues(r.Method))
        defer timer.ObserveDuration()

        wrapped := &responseWriter{ResponseWriter: w, status: 200}
        next.ServeHTTP(wrapped, r)

        httpRequests.WithLabelValues(r.Method, strconv.Itoa(wrapped.status)).Inc()
    })
}
メトリクスの公開
import "github.com/prometheus/client_golang/prometheus/promhttp"

func main() {
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe(":9090", nil)
}

レビューの質問

  1. メトリクスの種類は適切ですか(Counter、Gauge、Histogram のどれですか)?
  2. ラベルの値には上限がありますか(UUID、タイムスタンプ、パスを含みませんか)?
  3. メトリクス名に単位(_seconds、_bytes)が含まれていますか?
  4. メトリクスは一度だけ登録されていますか(リクエストごとに登録されていませんか)?
  5. /metrics エンドポイントは適切に公開されていますか?

コメント