Add orphan GC sweeper and Prometheus metrics with explicit registration
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
66
internal/provider/metrics.go
Normal file
66
internal/provider/metrics.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package provider
|
||||
|
||||
import "context"
|
||||
|
||||
// RequestRecorder receives one record per provider API call. Implemented
|
||||
// by internal/metrics; defined here so this package needs no metrics
|
||||
// dependency.
|
||||
type RequestRecorder interface {
|
||||
ProviderRequest(provider, op, result string)
|
||||
}
|
||||
|
||||
// WithMetrics wraps a Provider so every call is recorded with its
|
||||
// classified result — zero-cost instrumentation for the next five
|
||||
// providers, and the one place Class is called purely for observability.
|
||||
func WithMetrics(name string, p Provider, rec RequestRecorder) Provider {
|
||||
return &instrumented{name: name, inner: p, rec: rec}
|
||||
}
|
||||
|
||||
type instrumented struct {
|
||||
name string
|
||||
inner Provider
|
||||
rec RequestRecorder
|
||||
}
|
||||
|
||||
func (i *instrumented) Create(ctx context.Context, req CreateRequest) (string, error) {
|
||||
id, err := i.inner.Create(ctx, req)
|
||||
i.record("create", err)
|
||||
return id, err
|
||||
}
|
||||
|
||||
func (i *instrumented) Get(ctx context.Context, providerID string) (*Instance, error) {
|
||||
inst, err := i.inner.Get(ctx, providerID)
|
||||
i.record("get", err)
|
||||
return inst, err
|
||||
}
|
||||
|
||||
func (i *instrumented) Delete(ctx context.Context, providerID string) error {
|
||||
err := i.inner.Delete(ctx, providerID)
|
||||
i.record("delete", err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *instrumented) ListByTag(ctx context.Context) ([]Instance, error) {
|
||||
instances, err := i.inner.ListByTag(ctx)
|
||||
i.record("list", err)
|
||||
return instances, err
|
||||
}
|
||||
|
||||
func (i *instrumented) record(op string, err error) {
|
||||
i.rec.ProviderRequest(i.name, op, resultLabel(err))
|
||||
}
|
||||
|
||||
func resultLabel(err error) string {
|
||||
switch Class(err) {
|
||||
case nil:
|
||||
return "ok"
|
||||
case ErrNotFound:
|
||||
return "not_found"
|
||||
case ErrQuotaExceeded:
|
||||
return "quota_exceeded"
|
||||
case ErrPermanent:
|
||||
return "permanent"
|
||||
default:
|
||||
return "transient"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user