Files
orca/internal/transport/metrics.go
T
Jon Chery ed91d68fbf feat(P10): observability expansion — metrics + security headers (REQ-159)
New metrics:
- orca_jobs_running / orca_jobs_failed / orca_jobs_complete (gauges)
- orca_audit_chain_head (gauge, chain integrity)
- orca_drift_events_total, orca_ssh_errors_total (counters)
- orca_txn_apply_total, orca_txn_rollback_total (counters)
- orca_acl_denials_total (counter)

Security headers on metrics + healthz endpoints:
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY

New file: docs/metrics.md (Prometheus reference + scrape config)

---ci---
project: orca
phase: 10
milestone: v0.13
status: complete
requirements:
  covered: [159]
---/ci---
2026-08-10 13:44:04 +00:00

142 lines
3.3 KiB
Go

package transport
import (
"fmt"
"io"
"strconv"
"sync"
"sync/atomic"
)
type metricDef struct {
help string
typ string
}
var metricOrder = []string{
"txns_applied_total",
"txns_drifted_total",
"drifts_remediated_total",
"drifts_remediated_total",
"peers_total",
"nodes_total",
"allocs_total",
"orca_jobs_running",
"orca_jobs_failed",
"orca_jobs_complete",
"orca_audit_chain_head",
"orca_drift_events_total",
"orca_ssh_errors_total",
"orca_txn_apply_total",
"orca_txn_rollback_total",
"orca_acl_denials_total",
}
var metricMeta = map[string]metricDef{
"txns_applied_total": {"Total transactions applied", "counter"},
"txns_drifted_total": {"Total transactions drifted", "counter"},
"drifts_remediated_total": {"Total drifts remediated", "counter"},
"peers_total": {"Current peer count", "gauge"},
"nodes_total": {"Current node count", "gauge"},
"allocs_total": {"Current allocation count", "gauge"},
"orca_jobs_running": {"Jobs currently running", "gauge"},
"orca_jobs_failed": {"Jobs that failed", "gauge"},
"orca_jobs_complete": {"Jobs completed successfully", "gauge"},
"orca_audit_chain_head": {"Audit chain integrity (1=verified)", "gauge"},
"orca_drift_events_total": {"Total drift events detected", "counter"},
"orca_ssh_errors_total": {"Total SSH errors", "counter"},
"orca_txn_apply_total": {"Total transaction applies", "counter"},
"orca_txn_rollback_total": {"Total transaction rollbacks", "counter"},
"orca_acl_denials_total": {"Total ACL denials (enforce mode)", "counter"},
}
type Metrics struct {
cmu sync.RWMutex
counters map[string]*atomic.Int64
gmu sync.RWMutex
gauges map[string]float64
}
func NewMetrics() *Metrics {
m := &Metrics{
counters: make(map[string]*atomic.Int64),
gauges: make(map[string]float64),
}
for name, meta := range metricMeta {
if meta.typ == "counter" {
m.counters[name] = new(atomic.Int64)
} else {
m.gauges[name] = 0
}
}
return m
}
func (m *Metrics) counter(name string) *atomic.Int64 {
m.cmu.RLock()
c := m.counters[name]
m.cmu.RUnlock()
if c != nil {
return c
}
m.cmu.Lock()
defer m.cmu.Unlock()
if c = m.counters[name]; c != nil {
return c
}
c = new(atomic.Int64)
m.counters[name] = c
return c
}
func (m *Metrics) IncCounter(name string) {
m.counter(name).Add(1)
}
func (m *Metrics) AddCounter(name string, delta int64) {
m.counter(name).Add(delta)
}
func (m *Metrics) SetGauge(name string, value float64) {
m.gmu.Lock()
m.gauges[name] = value
m.gmu.Unlock()
}
func (m *Metrics) WritePrometheus(w io.Writer) error {
for _, name := range metricOrder {
meta, ok := metricMeta[name]
if !ok {
continue
}
if _, err := fmt.Fprintf(w, "# HELP %s %s\n", name, meta.help); err != nil {
return err
}
if _, err := fmt.Fprintf(w, "# TYPE %s %s\n", name, meta.typ); err != nil {
return err
}
switch meta.typ {
case "counter":
m.cmu.RLock()
c := m.counters[name]
m.cmu.RUnlock()
var v int64
if c != nil {
v = c.Load()
}
if _, err := fmt.Fprintf(w, "%s %d\n", name, v); err != nil {
return err
}
case "gauge":
m.gmu.RLock()
v := m.gauges[name]
m.gmu.RUnlock()
if _, err := fmt.Fprintf(w, "%s %s\n", name, strconv.FormatFloat(v, 'g', -1, 64)); err != nil {
return err
}
}
}
return nil
}