Skip to content

Instrument resources (DB, cache, breakers, queues)

Databases, caches, circuit breakers and work queues are the resources whose USE signals — Utilization, Saturation, Errors — tell you whether a service is healthy under load. transport-metrics ships ready-made helpers for each, so you instrument them without hand-rolling Prometheus. All register on the same registry that serves /metrics, and each carries a constant identifying label.

Database

Query RED plus connection-pool USE:

db, err := m.NewDB("orders")
if err != nil { return err }

// Query RED — labelled by a bounded query name (never a raw SQL string):
err = db.Query(ctx, "get_order", func() error {
    return sqldb.QueryRowContext(ctx, q, id).Scan(&o)
})

// Pool USE — scraped from database/sql on each collect:
_ = db.RegisterPool(func() metrics.PoolStats {
    s := sqldb.Stats()
    return metrics.PoolStats{
        MaxOpen: s.MaxOpenConnections, Open: s.OpenConnections,
        InUse: s.InUse, Idle: s.Idle,
        WaitCount: s.WaitCount, WaitSeconds: s.WaitDuration.Seconds(),
    }
})

Metrics (const label db="orders"): db_queries_total, db_query_errors_total, db_query_duration_seconds, db_queries_in_flight (label query); and db_pool_{max_open,open,in_use,idle}, db_pool_wait_count_total, db_pool_wait_seconds_total.

Cache

c, _ := m.NewCache("sessions")
if hit { c.Hit() } else { c.Miss() }
c.Eviction(1)
c.SetSize(cache.Len())
c.SetCapacity(cache.Cap())

Metrics (const label cache="sessions"): cache_hits_total, cache_misses_total, cache_evictions_total, cache_size, cache_capacity. Hit ratio is rate(cache_hits_total[5m]) / (rate(cache_hits_total[5m]) + rate(cache_misses_total[5m])).

Circuit breaker

cb, _ := m.NewCircuitBreaker("payments")
cb.SetState(metrics.BreakerClosed) // 0 closed, 1 half-open, 2 open
cb.Success()                        // or cb.Failure()
cb.Trip()                           // increments trips and sets state open
cb.ShortCircuit()                   // a request rejected while open

Metrics (const label name="payments"): circuit_breaker_state (gauge 0/½), circuit_breaker_trips_total, circuit_breaker_short_circuits_total, circuit_breaker_successes_total, circuit_breaker_failures_total.

Queue

q, _ := m.NewQueue("jobs")
q.Enqueue(); q.SetDepth(queue.Len())
// on dequeue:
q.Dequeue(); q.ObserveWait(waited)
q.ObserveProcessing(ctx, took) // exemplar-aware

Metrics (const label queue="jobs"): queue_depth, queue_enqueued_total, queue_dequeued_total, queue_wait_seconds, queue_processing_seconds.

Options

Every helper (and NewOperations) takes the same HelperOption set:

Option Effect
WithNamespace("app") prefix the metric names (app_cache_hits_total)
WithBuckets(...) duration-histogram buckets (default prometheus.DefBuckets)
WithConstLabels{...} extra constant labels, merged with the identifying label

Multiple instances

Call the constructor once per resource (NewDB("orders"), NewDB("billing")) — the identifying label distinguishes them and they share metric names. A repeated name is a duplicate-registration error. Keep those names bounded, as always.