go/pkg/lab/collector/collector.go

83 lines
1.5 KiB
Go
Raw Normal View History

package collector
import (
"context"
"log/slog"
"sync"
"time"
)
type Collector interface {
Name() string
Collect(ctx context.Context) error
}
type Registry struct {
mu sync.Mutex
entries []entry
logger *slog.Logger
}
type entry struct {
c Collector
interval time.Duration
cancel context.CancelFunc
}
func NewRegistry(logger *slog.Logger) *Registry {
return &Registry{logger: logger}
}
func (r *Registry) Register(c Collector, interval time.Duration) {
r.mu.Lock()
defer r.mu.Unlock()
r.entries = append(r.entries, entry{c: c, interval: interval})
}
func (r *Registry) Start(ctx context.Context) {
r.mu.Lock()
defer r.mu.Unlock()
for i := range r.entries {
e := &r.entries[i]
cctx, cancel := context.WithCancel(ctx)
e.cancel = cancel
go r.run(cctx, e.c, e.interval)
}
}
func (r *Registry) run(ctx context.Context, c Collector, interval time.Duration) {
r.logger.Info("collector started", "name", c.Name(), "interval", interval)
// Run immediately on start.
if err := c.Collect(ctx); err != nil {
r.logger.Warn("collector error", "name", c.Name(), "err", err)
}
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
r.logger.Info("collector stopped", "name", c.Name())
return
case <-ticker.C:
if err := c.Collect(ctx); err != nil {
r.logger.Warn("collector error", "name", c.Name(), "err", err)
}
}
}
}
func (r *Registry) Stop() {
r.mu.Lock()
defer r.mu.Unlock()
for _, e := range r.entries {
if e.cancel != nil {
e.cancel()
}
}
}