81 lines
2.6 KiB
Go
81 lines
2.6 KiB
Go
package extraction
|
|
|
|
import (
|
|
"errors"
|
|
|
|
domain "proxy-pool/internal/domain/extraction"
|
|
)
|
|
|
|
// MetricResult is a fixed, low-cardinality classification of one extraction
|
|
// request after application-level validation, admission, and storage handling.
|
|
type MetricResult string
|
|
|
|
const (
|
|
MetricComplete MetricResult = "complete"
|
|
MetricPartial MetricResult = "partial"
|
|
MetricEmpty MetricResult = "empty"
|
|
MetricInsufficient MetricResult = "insufficient"
|
|
MetricIdempotencyConflict MetricResult = "idempotency_conflict"
|
|
MetricRateLimited MetricResult = "rate_limited"
|
|
MetricUnavailable MetricResult = "unavailable"
|
|
MetricInvalid MetricResult = "invalid"
|
|
MetricError MetricResult = "error"
|
|
)
|
|
|
|
// MetricsEvent contains only aggregate request and response counts. It must
|
|
// never contain a Client, Proxy, Upstream, filter, identifier, or error text.
|
|
type MetricsEvent struct {
|
|
Result MetricResult
|
|
Requested int
|
|
Returned int
|
|
}
|
|
|
|
// MetricsObserver receives one completed extraction request. Implementations
|
|
// must return promptly and must not perform network or persistent storage I/O.
|
|
type MetricsObserver interface {
|
|
ObserveExtraction(MetricsEvent)
|
|
}
|
|
|
|
func classifyMetricsEvent(response Response, resultErr error) MetricsEvent {
|
|
event := MetricsEvent{Requested: response.Requested, Returned: response.Returned}
|
|
if resultErr == nil {
|
|
switch {
|
|
case response.Returned == response.Requested:
|
|
event.Result = MetricComplete
|
|
case response.Returned > 0 && response.Returned < response.Requested:
|
|
event.Result = MetricPartial
|
|
case response.Returned == 0:
|
|
event.Result = MetricEmpty
|
|
default:
|
|
event.Result = MetricError
|
|
}
|
|
return event
|
|
}
|
|
switch {
|
|
case errors.Is(resultErr, domain.ErrInsufficientProxies):
|
|
event.Result = MetricInsufficient
|
|
case errors.Is(resultErr, domain.ErrIdempotencyConflict):
|
|
event.Result = MetricIdempotencyConflict
|
|
case errors.Is(resultErr, ErrAdmissionRejected):
|
|
event.Result = MetricRateLimited
|
|
case errors.Is(resultErr, ErrUnavailable):
|
|
event.Result = MetricUnavailable
|
|
case errors.Is(resultErr, ErrInvalidRequest), errors.Is(resultErr, ErrCountExceeded),
|
|
errors.Is(resultErr, ErrInvalidFulfillment), errors.Is(resultErr, domain.ErrInvalidCommand):
|
|
event.Result = MetricInvalid
|
|
default:
|
|
event.Result = MetricError
|
|
}
|
|
return event
|
|
}
|
|
|
|
func validMetricResult(result MetricResult) bool {
|
|
switch result {
|
|
case MetricComplete, MetricPartial, MetricEmpty, MetricInsufficient, MetricIdempotencyConflict,
|
|
MetricRateLimited, MetricUnavailable, MetricInvalid, MetricError:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|