2024-07-03 11:51:14 +00:00
|
|
|
package centralizedmetrics
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2024-10-28 20:54:17 +00:00
|
|
|
"go.uber.org/zap"
|
2024-07-03 11:51:14 +00:00
|
|
|
|
|
|
|
"github.com/status-im/status-go/centralizedmetrics/common"
|
|
|
|
"github.com/status-im/status-go/centralizedmetrics/providers"
|
2024-09-26 22:37:32 +00:00
|
|
|
gocommon "github.com/status-im/status-go/common"
|
2024-07-03 11:51:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const defaultPollInterval = 10 * time.Second
|
|
|
|
|
|
|
|
type MetricsInfo struct {
|
|
|
|
Enabled bool `json:"enabled"`
|
|
|
|
UserConfirmed bool `json:"userConfirmed"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type MetricRepository interface {
|
|
|
|
Poll() ([]common.Metric, error)
|
|
|
|
Delete(metrics []common.Metric) error
|
|
|
|
Add(metric common.Metric) error
|
|
|
|
Info() (*MetricsInfo, error)
|
|
|
|
ToggleEnabled(isEnabled bool) error
|
|
|
|
}
|
|
|
|
|
|
|
|
type MetricService struct {
|
|
|
|
repository MetricRepository
|
|
|
|
processor common.MetricProcessor
|
|
|
|
ticker *time.Ticker
|
|
|
|
done chan bool
|
|
|
|
started bool
|
|
|
|
wg sync.WaitGroup
|
2024-07-22 08:56:17 +00:00
|
|
|
interval time.Duration
|
2024-10-28 20:54:17 +00:00
|
|
|
|
|
|
|
logger *zap.Logger
|
2024-07-03 11:51:14 +00:00
|
|
|
}
|
|
|
|
|
2024-10-28 20:54:17 +00:00
|
|
|
func NewDefaultMetricService(db *sql.DB, logger *zap.Logger) *MetricService {
|
2024-07-03 11:51:14 +00:00
|
|
|
repository := NewSQLiteMetricRepository(db)
|
2024-10-28 20:54:17 +00:00
|
|
|
processor := providers.NewMixpanelMetricProcessor(providers.MixpanelAppID, providers.MixpanelToken, providers.MixpanelBaseURL, logger)
|
|
|
|
return NewMetricService(repository, processor, defaultPollInterval, logger)
|
2024-07-03 11:51:14 +00:00
|
|
|
}
|
|
|
|
|
2024-10-28 20:54:17 +00:00
|
|
|
func NewMetricService(repository MetricRepository, processor common.MetricProcessor, interval time.Duration, logger *zap.Logger) *MetricService {
|
2024-07-03 11:51:14 +00:00
|
|
|
return &MetricService{
|
|
|
|
repository: repository,
|
|
|
|
processor: processor,
|
2024-07-22 08:56:17 +00:00
|
|
|
interval: interval,
|
2024-07-03 11:51:14 +00:00
|
|
|
done: make(chan bool),
|
2024-10-28 20:54:17 +00:00
|
|
|
logger: logger.Named("MetricService"),
|
2024-07-03 11:51:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MetricService) Start() {
|
|
|
|
if s.started {
|
|
|
|
return
|
|
|
|
}
|
2024-07-22 08:56:17 +00:00
|
|
|
s.ticker = time.NewTicker(s.interval)
|
2024-07-03 11:51:14 +00:00
|
|
|
s.wg.Add(1)
|
|
|
|
s.started = true
|
|
|
|
go func() {
|
2024-09-26 22:37:32 +00:00
|
|
|
defer gocommon.LogOnPanic()
|
2024-07-03 11:51:14 +00:00
|
|
|
defer s.wg.Done()
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-s.done:
|
|
|
|
return
|
|
|
|
case <-s.ticker.C:
|
|
|
|
s.processMetrics()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MetricService) Stop() {
|
|
|
|
if !s.started {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
s.ticker.Stop()
|
|
|
|
s.done <- true
|
|
|
|
s.wg.Wait()
|
|
|
|
s.started = false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MetricService) EnsureStarted() error {
|
|
|
|
info, err := s.Info()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if info.Enabled {
|
|
|
|
s.Start()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MetricService) Info() (*MetricsInfo, error) {
|
|
|
|
return s.repository.Info()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MetricService) ToggleEnabled(isEnabled bool) error {
|
|
|
|
err := s.repository.ToggleEnabled(isEnabled)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if isEnabled {
|
|
|
|
s.Start()
|
|
|
|
} else {
|
|
|
|
s.Stop()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MetricService) AddMetric(metric common.Metric) error {
|
|
|
|
return s.repository.Add(metric)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MetricService) processMetrics() {
|
2024-10-28 20:54:17 +00:00
|
|
|
s.logger.Info("processing metrics")
|
2024-07-03 11:51:14 +00:00
|
|
|
metrics, err := s.repository.Poll()
|
|
|
|
if err != nil {
|
2024-10-28 20:54:17 +00:00
|
|
|
s.logger.Warn("error polling metrics", zap.Error(err))
|
2024-07-03 11:51:14 +00:00
|
|
|
return
|
|
|
|
}
|
2024-10-28 20:54:17 +00:00
|
|
|
s.logger.Info("polled metrics")
|
2024-07-03 11:51:14 +00:00
|
|
|
|
|
|
|
if len(metrics) == 0 {
|
|
|
|
return
|
|
|
|
}
|
2024-10-28 20:54:17 +00:00
|
|
|
s.logger.Info("processing metrics")
|
2024-07-03 11:51:14 +00:00
|
|
|
|
|
|
|
if err := s.processor.Process(metrics); err != nil {
|
2024-10-28 20:54:17 +00:00
|
|
|
s.logger.Warn("error processing metrics", zap.Error(err))
|
2024-07-03 11:51:14 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-10-28 20:54:17 +00:00
|
|
|
s.logger.Info("deleting metrics")
|
2024-07-03 11:51:14 +00:00
|
|
|
if err := s.repository.Delete(metrics); err != nil {
|
2024-10-28 20:54:17 +00:00
|
|
|
s.logger.Warn("error deleting metrics", zap.Error(err))
|
2024-07-03 11:51:14 +00:00
|
|
|
}
|
2024-10-28 20:54:17 +00:00
|
|
|
s.logger.Info("done metrics")
|
2024-07-03 11:51:14 +00:00
|
|
|
}
|