proxy-pool/internal/platform/metrics/checker.go
youfak b35092ccdd
Some checks are pending
ci / proto (push) Waiting to run
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run
ci / race (push) Waiting to run
ci / integration (push) Waiting to run
feat: expose checker task metrics
2026-08-02 09:24:46 +08:00

81 lines
2.8 KiB
Go

package metrics
import (
"errors"
"fmt"
"github.com/prometheus/client_golang/prometheus"
healthDomain "proxy-pool/internal/domain/health"
)
// CheckerCollector exposes bounded Checker task-flow counters. The only
// labels are the three fixed health levels and accepted/rejected outcome.
type CheckerCollector struct {
tasksDispatched *prometheus.CounterVec
observations *prometheus.CounterVec
}
var _ healthDomain.TaskMetricsObserver = (*CheckerCollector)(nil)
func NewCheckerCollector(registerer prometheus.Registerer) (*CheckerCollector, error) {
if registerer == nil {
return nil, ErrInvalidDependencies
}
tasks, err := registerCounterVec(registerer, prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "proxy_pool", Subsystem: "checker", Name: "tasks_dispatched_total",
Help: "Number of checker tasks dispatched after a successful task-stream send.",
}, []string{"level"}))
if err != nil {
return nil, err
}
observations, err := registerCounterVec(registerer, prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "proxy_pool", Subsystem: "checker", Name: "observations_total",
Help: "Number of checker observations accepted or rejected after decoding a known level.",
}, []string{"level", "result"}))
if err != nil {
return nil, err
}
return &CheckerCollector{tasksDispatched: tasks, observations: observations}, nil
}
func (collector *CheckerCollector) ObserveTaskDispatch(level healthDomain.Level, count int) {
if collector == nil || collector.tasksDispatched == nil || count <= 0 || !validCheckerLevel(level) {
return
}
collector.tasksDispatched.WithLabelValues(string(level)).Add(float64(count))
}
func (collector *CheckerCollector) ObserveObservation(level healthDomain.Level, result healthDomain.ObservationMetricResult) {
if collector == nil || collector.observations == nil || !validCheckerLevel(level) ||
(result != healthDomain.ObservationMetricAccepted && result != healthDomain.ObservationMetricRejected) {
return
}
collector.observations.WithLabelValues(string(level), string(result)).Inc()
}
func registerCounterVec(registerer prometheus.Registerer, candidate *prometheus.CounterVec) (*prometheus.CounterVec, error) {
if err := registerer.Register(candidate); err == nil {
return candidate, nil
} else {
var registered prometheus.AlreadyRegisteredError
if !errors.As(err, &registered) {
return nil, fmt.Errorf("register checker metrics: %w", err)
}
existing, ok := registered.ExistingCollector.(*prometheus.CounterVec)
if !ok {
return nil, fmt.Errorf("register checker metrics: existing collector has unexpected type")
}
return existing, nil
}
}
func validCheckerLevel(level healthDomain.Level) bool {
switch level {
case healthDomain.LevelBasic, healthDomain.LevelEgress, healthDomain.LevelTarget:
return true
default:
return false
}
}