// Package metrics exposes Prometheus metrics for the logarchiver service. The // logging stack ships no metrics convention today, so this is the first // /metrics endpoint there; it is opt-in via config. package metrics import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) // Metrics holds the collectors. type Metrics struct { objectsStored *prometheus.CounterVec eventsArchived *prometheus.CounterVec rawBytes *prometheus.CounterVec storedBytes *prometheus.CounterVec storeFailures *prometheus.CounterVec indexFailures *prometheus.CounterVec messagesFetched prometheus.Counter acksSent prometheus.Counter batchesFlushed *prometheus.CounterVec pendingEvents prometheus.Gauge } // New registers the collectors on reg (use prometheus.DefaultRegisterer for the // default /metrics handler). func New(reg prometheus.Registerer) *Metrics { f := promauto.With(reg) return &Metrics{ objectsStored: f.NewCounterVec(prometheus.CounterOpts{ Name: "logarchiver_objects_stored_total", Help: "Objects successfully sealed, uploaded and indexed.", }, []string{"subject"}), eventsArchived: f.NewCounterVec(prometheus.CounterOpts{ Name: "logarchiver_events_archived_total", Help: "Log events archived.", }, []string{"subject"}), rawBytes: f.NewCounterVec(prometheus.CounterOpts{ Name: "logarchiver_raw_bytes_total", Help: "Raw NDJSON bytes archived (pre-compression).", }, []string{"subject"}), storedBytes: f.NewCounterVec(prometheus.CounterOpts{ Name: "logarchiver_stored_bytes_total", Help: "Stored object bytes written to S3 (post-compression/encryption).", }, []string{"subject"}), storeFailures: f.NewCounterVec(prometheus.CounterOpts{ Name: "logarchiver_store_failures_total", Help: "Failed store attempts (seal/upload); batch not acked.", }, []string{"subject"}), indexFailures: f.NewCounterVec(prometheus.CounterOpts{ Name: "logarchiver_index_failures_total", Help: "Failed index writes after a successful S3 upload; batch not acked.", }, []string{"subject"}), messagesFetched: f.NewCounter(prometheus.CounterOpts{ Name: "logarchiver_messages_fetched_total", Help: "JetStream messages fetched.", }), acksSent: f.NewCounter(prometheus.CounterOpts{ Name: "logarchiver_acks_total", Help: "JetStream acknowledgements sent (after successful persist).", }), batchesFlushed: f.NewCounterVec(prometheus.CounterOpts{ Name: "logarchiver_batches_flushed_total", Help: "Batches flushed, labelled by trigger (full|age|shutdown).", }, []string{"trigger"}), pendingEvents: f.NewGauge(prometheus.GaugeOpts{ Name: "logarchiver_pending_events", Help: "Events currently buffered in open batches (unacked).", }), } } // ObjectStored records a successful persist. func (m *Metrics) ObjectStored(subject string, events int, rawBytes, storedBytes int64) { m.objectsStored.WithLabelValues(subject).Inc() m.eventsArchived.WithLabelValues(subject).Add(float64(events)) m.rawBytes.WithLabelValues(subject).Add(float64(rawBytes)) m.storedBytes.WithLabelValues(subject).Add(float64(storedBytes)) } // StoreFailed records a seal/upload failure. func (m *Metrics) StoreFailed(subject string) { m.storeFailures.WithLabelValues(subject).Inc() } // IndexFailed records an index-write failure. func (m *Metrics) IndexFailed(subject string) { m.indexFailures.WithLabelValues(subject).Inc() } // MessagesFetched records fetched messages. func (m *Metrics) MessagesFetched(n int) { m.messagesFetched.Add(float64(n)) } // Acked records sent acknowledgements. func (m *Metrics) Acked(n int) { m.acksSent.Add(float64(n)) } // BatchFlushed records a flush by trigger. func (m *Metrics) BatchFlushed(trigger string) { m.batchesFlushed.WithLabelValues(trigger).Inc() } // SetPending sets the pending-events gauge. func (m *Metrics) SetPending(n int) { m.pendingEvents.Set(float64(n)) }