github.com/status-im/status-go@v1.1.0/centralizedmetrics/metrics.go (about)

     1  package centralizedmetrics
     2  
     3  import (
     4  	"database/sql"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/ethereum/go-ethereum/log"
     9  
    10  	"github.com/status-im/status-go/centralizedmetrics/common"
    11  	"github.com/status-im/status-go/centralizedmetrics/providers"
    12  )
    13  
    14  const defaultPollInterval = 10 * time.Second
    15  
    16  type MetricsInfo struct {
    17  	Enabled       bool `json:"enabled"`
    18  	UserConfirmed bool `json:"userConfirmed"`
    19  }
    20  
    21  type MetricRepository interface {
    22  	Poll() ([]common.Metric, error)
    23  	Delete(metrics []common.Metric) error
    24  	Add(metric common.Metric) error
    25  	Info() (*MetricsInfo, error)
    26  	ToggleEnabled(isEnabled bool) error
    27  }
    28  
    29  type MetricService struct {
    30  	repository MetricRepository
    31  	processor  common.MetricProcessor
    32  	ticker     *time.Ticker
    33  	done       chan bool
    34  	started    bool
    35  	wg         sync.WaitGroup
    36  	interval   time.Duration
    37  }
    38  
    39  func NewDefaultMetricService(db *sql.DB) *MetricService {
    40  	repository := NewSQLiteMetricRepository(db)
    41  	processor := providers.NewMixpanelMetricProcessor(providers.MixpanelAppID, providers.MixpanelToken, providers.MixpanelBaseURL)
    42  	return NewMetricService(repository, processor, defaultPollInterval)
    43  }
    44  
    45  func NewMetricService(repository MetricRepository, processor common.MetricProcessor, interval time.Duration) *MetricService {
    46  	return &MetricService{
    47  		repository: repository,
    48  		processor:  processor,
    49  		interval:   interval,
    50  		done:       make(chan bool),
    51  	}
    52  }
    53  
    54  func (s *MetricService) Start() {
    55  	if s.started {
    56  		return
    57  	}
    58  	s.ticker = time.NewTicker(s.interval)
    59  	s.wg.Add(1)
    60  	s.started = true
    61  	go func() {
    62  		defer s.wg.Done()
    63  		for {
    64  			select {
    65  			case <-s.done:
    66  				return
    67  			case <-s.ticker.C:
    68  				s.processMetrics()
    69  			}
    70  		}
    71  	}()
    72  }
    73  
    74  func (s *MetricService) Stop() {
    75  	if !s.started {
    76  		return
    77  	}
    78  	s.ticker.Stop()
    79  	s.done <- true
    80  	s.wg.Wait()
    81  	s.started = false
    82  }
    83  
    84  func (s *MetricService) EnsureStarted() error {
    85  	info, err := s.Info()
    86  	if err != nil {
    87  		return err
    88  	}
    89  	if info.Enabled {
    90  		s.Start()
    91  	}
    92  	return nil
    93  }
    94  
    95  func (s *MetricService) Info() (*MetricsInfo, error) {
    96  	return s.repository.Info()
    97  }
    98  
    99  func (s *MetricService) ToggleEnabled(isEnabled bool) error {
   100  	err := s.repository.ToggleEnabled(isEnabled)
   101  	if err != nil {
   102  		return err
   103  	}
   104  	if isEnabled {
   105  		s.Start()
   106  	} else {
   107  		s.Stop()
   108  	}
   109  	return nil
   110  }
   111  
   112  func (s *MetricService) AddMetric(metric common.Metric) error {
   113  	return s.repository.Add(metric)
   114  }
   115  
   116  func (s *MetricService) processMetrics() {
   117  	log.Info("processing metrics")
   118  	metrics, err := s.repository.Poll()
   119  	if err != nil {
   120  		log.Warn("error polling metrics", "error", err)
   121  		return
   122  	}
   123  	log.Info("polled metrics")
   124  
   125  	if len(metrics) == 0 {
   126  		return
   127  	}
   128  	log.Info("processing metrics")
   129  
   130  	if err := s.processor.Process(metrics); err != nil {
   131  		log.Warn("error processing metrics", "error", err)
   132  		return
   133  	}
   134  
   135  	log.Info("deleting metrics")
   136  	if err := s.repository.Delete(metrics); err != nil {
   137  		log.Warn("error deleting metrics", "error", err)
   138  	}
   139  	log.Info("done metrics")
   140  }