grafana/pkg/infra/usagestats/service/service.go
Emil Tullstedt 3df625e9f4
UsageStats: Move stats collection to separate service (#47381)
* Remove specific stats from usage stats service

* Create statscollector service

* refactor

* Update and move tests

Mostly equivalent tests to before, but they've been divided over the two
services and removed the behavior driven legacy from GoConvey to
reduce the complexity of the tests.

* Collect featuremgmr metrics (copied over from #47407)

I removed the metrics registration from the feature manager in the merge
and re-add them in this commit. Separated to make things easier to
review.
2022-04-08 13:41:26 +02:00

103 lines
2.7 KiB
Go

package service
import (
"context"
"time"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
)
type UsageStats struct {
Cfg *setting.Cfg
kvStore *kvstore.NamespacedKVStore
RouteRegister routing.RouteRegister
pluginStore plugins.Store
log log.Logger
externalMetrics []usagestats.MetricsFunc
sendReportCallbacks []usagestats.SendReportCallbackFunc
}
func ProvideService(cfg *setting.Cfg, pluginStore plugins.Store, kvStore kvstore.KVStore, routeRegister routing.RouteRegister) *UsageStats {
s := &UsageStats{
Cfg: cfg,
RouteRegister: routeRegister,
pluginStore: pluginStore,
kvStore: kvstore.WithNamespace(kvStore, 0, "infra.usagestats"),
log: log.New("infra.usagestats"),
}
s.registerAPIEndpoints()
return s
}
func (uss *UsageStats) Run(ctx context.Context) error {
// try to load last sent time from kv store
lastSent := time.Now()
if val, ok, err := uss.kvStore.Get(ctx, "last_sent"); err != nil {
uss.log.Error("Failed to get last sent time", "error", err)
} else if ok {
if parsed, err := time.Parse(time.RFC3339, val); err != nil {
uss.log.Error("Failed to parse last sent time", "error", err)
} else {
lastSent = parsed
}
}
// calculate initial send delay
sendInterval := time.Hour * 24
nextSendInterval := time.Until(lastSent.Add(sendInterval))
if nextSendInterval < time.Minute {
nextSendInterval = time.Minute
}
sendReportTicker := time.NewTicker(nextSendInterval)
defer sendReportTicker.Stop()
for {
select {
case <-sendReportTicker.C:
if err := uss.sendUsageStats(ctx); err != nil {
uss.log.Warn("Failed to send usage stats", "error", err)
}
lastSent = time.Now()
if err := uss.kvStore.Set(ctx, "last_sent", lastSent.Format(time.RFC3339)); err != nil {
uss.log.Warn("Failed to update last sent time", "error", err)
}
if nextSendInterval != sendInterval {
nextSendInterval = sendInterval
sendReportTicker.Reset(nextSendInterval)
}
for _, callback := range uss.sendReportCallbacks {
callback()
}
case <-ctx.Done():
return ctx.Err()
}
}
}
func (uss *UsageStats) RegisterSendReportCallback(c usagestats.SendReportCallbackFunc) {
uss.sendReportCallbacks = append(uss.sendReportCallbacks, c)
}
func (uss *UsageStats) ShouldBeReported(ctx context.Context, dsType string) bool {
ds, exists := uss.pluginStore.Plugin(ctx, dsType)
if !exists {
return false
}
return ds.Signature.IsValid() || ds.Signature.IsInternal()
}