prometheus-go-code-review

Reviews Prometheus instrumentation in Go code for proper metric types, labels, and patterns. Use when reviewing code with prometheus/client_golang metrics.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "prometheus-go-code-review" with this command: npx skills add anderskev/prometheus-go-code-review

Prometheus Go Code Review

Review Checklist

  • Metric types match measurement semantics (Counter/Gauge/Histogram)
  • Labels have low cardinality (no user IDs, timestamps, paths)
  • Metric names follow conventions (snake_case, unit suffix)
  • Histograms use appropriate bucket boundaries
  • Metrics registered once, not per-request
  • Collectors don't panic on race conditions
  • /metrics endpoint exposed and accessible

Hard gates (sequenced)

Complete in order before recording a finding. Skip gates that clearly do not apply to the diff.

  1. Evidence scope — Enumerate the files you are reviewing that touch Prometheus (prometheus/client_golang, promauto, promhttp, or MustRegister). Pass: you have a concrete path list (from the diff or an explicit file set); no repo-wide claim without at least one path.

  2. Label cardinality — For each *Vec or labeled metric in scope, list label names and where values come from (constants, bounded codes, vs request-derived strings). Pass: no label uses unbounded values (e.g. raw user_id, full URL path, timestamps) unless the code uses a bounded mapping and you cite it.

  3. Registration lifecycle — For metric definitions in scope, confirm constructors run once (package-level var, init, or sync.Once), not inside per-request handlers. Pass: no pattern that allocates/registers a new Counter/Histogram/*Vec on every request for the same logical metric.

  4. Finding shape — Each finding names a file (and line or symbol where possible), states which gate (2 or 3) would fail if the issue is real, and ties to observed code. Pass: no standalone style nit when gates 2–3 are satisfied for that code.

Metric Type Selection

MeasurementTypeExample
Requests processedCounterrequests_total
Items in queueGaugequeue_length
Request durationHistogramrequest_duration_seconds
Concurrent connectionsGaugeactive_connections
Errors since startCountererrors_total
Memory usageGaugememory_bytes

Critical Anti-Patterns

1. High Cardinality Labels

// 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. Wrong Metric Type

// 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. Registering Per-Request

// 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. Missing Unit Suffix

// BAD
duration := promauto.NewHistogram(prometheus.HistogramOpts{
    Name: "request_duration",  // no unit!
})

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

Good Patterns

Metric Definition

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"},
    )
)

Middleware Pattern

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()
    })
}

Exposing Metrics

import "github.com/prometheus/client_golang/prometheus/promhttp"

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

Review Questions

  1. Are metric types correct (Counter vs Gauge vs Histogram)?
  2. Are label values bounded (no UUIDs, timestamps, paths)?
  3. Do metric names include units (_seconds, _bytes)?
  4. Are metrics registered once (not per-request)?
  5. Is /metrics endpoint properly exposed?

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

run.dev — Local Dev Environment Manager

Local dev environment manager. Process management, automatic HTTPS domains, SSL certificates, reverse proxy, and AI crash diagnosis — single binary, zero con...

Registry SourceRecently Updated
Coding

ifly-image-understanding

iFlytek Image Understanding (图片理解) — analyze and answer questions about images using Spark Vision model. WebSocket API, pure Python stdlib, no pip dependencies.

Registry SourceRecently Updated
Coding

Civic Google

Use gog (Google CLI) without manual OAuth setup — Civic handles token management automatically

Registry SourceRecently Updated
2000Profile unavailable
Coding

Agent Browser.Skip

A fast Rust-based headless browser automation CLI with Node.js fallback that enables AI agents to navigate, click, type, and snapshot pages via structured co...

Registry SourceRecently Updated
2000Profile unavailable