proxy-pool/internal/platform/metrics/drain.go
2026-08-02 13:20:42 +08:00

59 lines
2.0 KiB
Go

package metrics
import (
"github.com/prometheus/client_golang/prometheus"
healthDomain "proxy-pool/internal/domain/health"
)
// DrainCollector exposes only fixed Controller Drain reasons. It never uses
// proxy, Upstream, Worker, session, routing or endpoint values as labels.
type DrainCollector struct {
candidates *prometheus.CounterVec
started *prometheus.CounterVec
}
var _ healthDomain.DrainMetricsObserver = (*DrainCollector)(nil)
func NewDrainCollector(registerer prometheus.Registerer) (*DrainCollector, error) {
if registerer == nil {
return nil, ErrInvalidDependencies
}
candidates, err := registerCounterVec(registerer, prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "proxy_pool", Subsystem: "controller", Name: "drain_candidates_total",
Help: "Number of bounded Controller Drain candidates selected by reason.",
}, []string{"reason"}))
if err != nil {
return nil, err
}
started, err := registerCounterVec(registerer, prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "proxy_pool", Subsystem: "controller", Name: "drains_started_total",
Help: "Number of Controller Drain tickets started by reason.",
}, []string{"reason"}))
if err != nil {
return nil, err
}
return &DrainCollector{candidates: candidates, started: started}, nil
}
func (collector *DrainCollector) ObserveDrain(reason healthDomain.DrainReason, candidates, started int) {
if collector == nil || !validDrainReason(reason) || candidates < 0 || started < 0 || started > candidates {
return
}
if candidates > 0 && collector.candidates != nil {
collector.candidates.WithLabelValues(string(reason)).Add(float64(candidates))
}
if started > 0 && collector.started != nil {
collector.started.WithLabelValues(string(reason)).Add(float64(started))
}
}
func validDrainReason(reason healthDomain.DrainReason) bool {
switch reason {
case healthDomain.DrainReasonUnhealthy, healthDomain.DrainReasonUpstreamDisabled:
return true
default:
return false
}
}