ProofedMesh/services/attest-reconciler/internal/metrics/metrics.go

75 lines
3.1 KiB
Go
Raw Normal View History

// Package metrics implements the three Prometheus counters the reconciler
// exposes, without pulling the prometheus/client_golang module. The /metrics
// handler prints the standard text exposition format.
package metrics
import (
"fmt"
"io"
"net/http"
"sync/atomic"
)
// Registry holds the reconciler's counters. Use New() to construct and share
// one instance across the scheduler and the HTTP handler.
type Registry struct {
dirtyRows atomic.Int64
reconciliationAttempts atomic.Int64
reconciliationFailures atomic.Int64
reconciliationNoopHits atomic.Int64
}
func New() *Registry { return &Registry{} }
// SetDirtyRows sets the current pending-row count. Called at the top of each
// tick, before any attempts land.
func (r *Registry) SetDirtyRows(n int64) { r.dirtyRows.Store(n) }
func (r *Registry) IncAttempts() { r.reconciliationAttempts.Add(1) }
func (r *Registry) IncFailures() { r.reconciliationFailures.Add(1) }
func (r *Registry) IncIdempotentNoopHits() { r.reconciliationNoopHits.Add(1) }
// Snapshot returns a point-in-time copy; useful for tests.
type Snapshot struct {
DirtyRows int64
ReconciliationAttempts int64
ReconciliationFailures int64
IdempotentNoopHits int64
}
func (r *Registry) Snapshot() Snapshot {
return Snapshot{
DirtyRows: r.dirtyRows.Load(),
ReconciliationAttempts: r.reconciliationAttempts.Load(),
ReconciliationFailures: r.reconciliationFailures.Load(),
IdempotentNoopHits: r.reconciliationNoopHits.Load(),
}
}
// Handler returns an http.HandlerFunc that writes the Prometheus text format.
func (r *Registry) Handler() http.HandlerFunc {
return func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
r.write(w)
}
}
func (r *Registry) write(w io.Writer) {
s := r.Snapshot()
fmt.Fprintln(w, "# HELP attest_reconciler_dirty_rows_total Current count of per_diem_rates rows missing an attestation reference (gauge-style, overwritten each tick).")
fmt.Fprintln(w, "# TYPE attest_reconciler_dirty_rows_total gauge")
fmt.Fprintf(w, "attest_reconciler_dirty_rows_total %d\n", s.DirtyRows)
fmt.Fprintln(w, "# HELP attest_reconciler_reconciliation_attempts_total Total pending rows the reconciler attempted to re-sign.")
fmt.Fprintln(w, "# TYPE attest_reconciler_reconciliation_attempts_total counter")
fmt.Fprintf(w, "attest_reconciler_reconciliation_attempts_total %d\n", s.ReconciliationAttempts)
fmt.Fprintln(w, "# HELP attest_reconciler_reconciliation_failures_total Total pending-row attempts that returned an error from the signer or transparency log.")
fmt.Fprintln(w, "# TYPE attest_reconciler_reconciliation_failures_total counter")
fmt.Fprintf(w, "attest_reconciler_reconciliation_failures_total %d\n", s.ReconciliationFailures)
fmt.Fprintln(w, "# HELP attest_reconciler_idempotent_noop_total Rows the reconciler re-signed where the TLog already had the entry (safe no-op; proves the idempotency contract works).")
fmt.Fprintln(w, "# TYPE attest_reconciler_idempotent_noop_total counter")
fmt.Fprintf(w, "attest_reconciler_idempotent_noop_total %d\n", s.IdempotentNoopHits)
}