package metrics import ( "github.com/prometheus/client_golang/prometheus" controllerProvider "proxy-pool/internal/controller/provider" "proxy-pool/internal/domain/upstream" ) // ProviderCollector exposes bounded Provider fetch outcomes. It never uses // upstream names, proxy addresses, response bodies or error strings as labels. type ProviderCollector struct { results *prometheus.CounterVec candidates prometheus.Counter inserted prometheus.Counter } var _ controllerProvider.ResultObserver = (*ProviderCollector)(nil) func NewProviderCollector(registerer prometheus.Registerer) (*ProviderCollector, error) { if registerer == nil { return nil, ErrInvalidDependencies } results, err := registerCounterVec(registerer, prometheus.NewCounterVec(prometheus.CounterOpts{ Namespace: "proxy_pool", Subsystem: "controller", Name: "provider_fetch_results_total", Help: "Number of completed Provider fetch reconciliations by fixed result class.", }, []string{"class"})) if err != nil { return nil, err } candidates, err := registerCounter(registerer, prometheus.NewCounter(prometheus.CounterOpts{ Namespace: "proxy_pool", Subsystem: "controller", Name: "provider_valid_candidates_total", Help: "Number of valid Provider proxy candidates parsed before deduplication.", })) if err != nil { return nil, err } inserted, err := registerCounter(registerer, prometheus.NewCounter(prometheus.CounterOpts{ Namespace: "proxy_pool", Subsystem: "controller", Name: "provider_new_proxies_total", Help: "Number of Provider proxy candidates inserted into the activity pool.", })) if err != nil { return nil, err } return &ProviderCollector{results: results, candidates: candidates, inserted: inserted}, nil } func (collector *ProviderCollector) ObserveProviderResult(result controllerProvider.Result) { if collector == nil || collector.results == nil || !validProviderFetchClass(result.Class) { return } collector.results.WithLabelValues(string(result.Class)).Inc() if result.ValidCount > 0 && collector.candidates != nil { collector.candidates.Add(float64(result.ValidCount)) } if result.NewCount > 0 && collector.inserted != nil { collector.inserted.Add(float64(result.NewCount)) } } func validProviderFetchClass(class upstream.FetchClass) bool { switch class { case upstream.FetchValid, upstream.FetchEmpty, upstream.FetchDuplicateOnly, upstream.FetchError: return true default: return false } }