frank 38308d48f2
feat_: log on panic (#5849)
* feat_: log error and stacktrace when panic in goroutine

* test_: add test TestSafeGo

* chore_: rename logAndCall to call

* chore_: rename SafeGo to Go

* chore_: make lint-fix

* chore_: use t.Cleanup

* chore_: Revert "chore_: use t.Cleanup"

This reverts commit 4eb420d179cc0e208e84c13cb941e6b3d1ed9819.

* chore_: Revert "chore_: make lint-fix"

This reverts commit fcc995f157e671a4229b47419c3a0e4004b5fdab.

* chore_: Revert "chore_: rename SafeGo to Go"

This reverts commit a6d73d6df583f313032d79aac62f66328039cb55.

* chore_: Revert "chore_: rename logAndCall to call"

This reverts commit 8fbe993bedb9fbba67349a44f151e2dd5e3bc4cc.

* chore_: Revert "test_: add test TestSafeGo"

This reverts commit a1fa91839f3960398980c6bf456e6462ec944819.

* chore_: Revert "feat_: log error and stacktrace when panic in goroutine"

This reverts commit f612dd828fa2ce410d0e806fe773ecbe3e86a68a.

* feat_: log error and stacktrace when panic in goroutine

* chore_: make lint-fix

* chore_: rename logAndCall to call

* chore_: renaming LogOnPanic

* chore_: update rest goroutine function calls

* chore_: make lint-fix
2024-09-27 06:37:32 +08:00

143 lines
2.9 KiB
Go

package centralizedmetrics
import (
"database/sql"
"sync"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/centralizedmetrics/common"
"github.com/status-im/status-go/centralizedmetrics/providers"
gocommon "github.com/status-im/status-go/common"
)
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
interval time.Duration
}
func NewDefaultMetricService(db *sql.DB) *MetricService {
repository := NewSQLiteMetricRepository(db)
processor := providers.NewMixpanelMetricProcessor(providers.MixpanelAppID, providers.MixpanelToken, providers.MixpanelBaseURL)
return NewMetricService(repository, processor, defaultPollInterval)
}
func NewMetricService(repository MetricRepository, processor common.MetricProcessor, interval time.Duration) *MetricService {
return &MetricService{
repository: repository,
processor: processor,
interval: interval,
done: make(chan bool),
}
}
func (s *MetricService) Start() {
if s.started {
return
}
s.ticker = time.NewTicker(s.interval)
s.wg.Add(1)
s.started = true
go func() {
defer gocommon.LogOnPanic()
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() {
log.Info("processing metrics")
metrics, err := s.repository.Poll()
if err != nil {
log.Warn("error polling metrics", "error", err)
return
}
log.Info("polled metrics")
if len(metrics) == 0 {
return
}
log.Info("processing metrics")
if err := s.processor.Process(metrics); err != nil {
log.Warn("error processing metrics", "error", err)
return
}
log.Info("deleting metrics")
if err := s.repository.Delete(metrics); err != nil {
log.Warn("error deleting metrics", "error", err)
}
log.Info("done metrics")
}