Skip to content
This repository was archived by the owner on Jul 19, 2023. It is now read-only.

Commit 7de0c86

Browse files
Adds anonymous statistics reporting (#356)
* Adds anonymous statistics reporting * Update go mod * Review feedback Co-authored-by: Christian Simon <simon@swine.de>
1 parent d0f67b4 commit 7de0c86

File tree

13 files changed

+1366
-16
lines changed

13 files changed

+1366
-16
lines changed

docs/sources/operators-guide/configure/reference-configuration-parameters/index.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ storage:
211211
# CLI flag: -auth.multitenancy-enabled
212212
[multitenancy_enabled: <boolean> | default = false]
213213

214+
analytics:
215+
# Enable anonymous usage reporting.
216+
# CLI flag: -reporting.enabled
217+
[reporting_enabled: <boolean> | default = true]
218+
214219
# yaml file to load
215220
# CLI flag: -config.file
216221
[configfile: <string> | default = ""]

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ require (
1717
github.com/grafana/regexp v0.0.0-20220304095617-2e8d9baf4ac2
1818
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
1919
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.2
20+
github.com/json-iterator/go v1.1.12
2021
github.com/klauspost/compress v1.15.9
2122
github.com/minio/minio-go/v7 v7.0.23
2223
github.com/mitchellh/go-wordwrap v1.0.0
@@ -163,7 +164,6 @@ require (
163164
github.com/jmespath/go-jmespath v0.4.0 // indirect
164165
github.com/josharian/intern v1.0.0 // indirect
165166
github.com/jpillora/backoff v1.0.0 // indirect
166-
github.com/json-iterator/go v1.1.12 // indirect
167167
github.com/julienschmidt/httprouter v1.3.0 // indirect
168168
github.com/klauspost/cpuid v1.3.1 // indirect
169169
github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b // indirect

pkg/distributor/distributor.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"flag"
7+
"fmt"
78
"hash/fnv"
89
"strconv"
910
"time"
@@ -27,18 +28,25 @@ import (
2728
phlaremodel "github.com/grafana/phlare/pkg/model"
2829
"github.com/grafana/phlare/pkg/pprof"
2930
"github.com/grafana/phlare/pkg/tenant"
31+
"github.com/grafana/phlare/pkg/usagestats"
3032
)
3133

3234
type PushClient interface {
3335
Push(context.Context, *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error)
3436
}
3537

3638
// todo: move to non global metrics.
37-
var clients = promauto.NewGauge(prometheus.GaugeOpts{
38-
Namespace: "phlare",
39-
Name: "distributor_ingester_clients",
40-
Help: "The current number of ingester clients.",
41-
})
39+
var (
40+
clients = promauto.NewGauge(prometheus.GaugeOpts{
41+
Namespace: "phlare",
42+
Name: "distributor_ingester_clients",
43+
Help: "The current number of ingester clients.",
44+
})
45+
rfStats = usagestats.NewInt("distributor_replication_factor")
46+
bytesReceivedStats = usagestats.NewStatistics("distributor_bytes_received")
47+
bytesReceivedTotalStats = usagestats.NewCounter("distributor_bytes_received_total")
48+
profileReceivedStats = usagestats.NewCounter("distributor_profiles_received")
49+
)
4250

4351
// Config for a Distributor.
4452
type Config struct {
@@ -83,6 +91,7 @@ func New(cfg Config, ingestersRing ring.ReadRing, factory ring_client.PoolFactor
8391
d.subservicesWatcher = services.NewFailureWatcher()
8492
d.subservicesWatcher.WatchManager(d.subservices)
8593
d.Service = services.NewBasicService(d.starting, d.running, d.stopping)
94+
rfStats.Set(int64(ingestersRing.ReplicationFactor()))
8695
return d, nil
8796
}
8897

@@ -117,6 +126,10 @@ func (d *Distributor) Push(ctx context.Context, req *connect.Request[pushv1.Push
117126
keys = append(keys, TokenFor(tenantID, labelsString(series.Labels)))
118127
profName := phlaremodel.Labels(series.Labels).Get(scrape.ProfileName)
119128
for _, raw := range series.Samples {
129+
usagestats.NewCounter(fmt.Sprintf("distributor_profile_type_%s_received", profName)).Inc(1)
130+
profileReceivedStats.Inc(1)
131+
bytesReceivedTotalStats.Inc(int64(len(raw.RawProfile)))
132+
bytesReceivedStats.Record(float64(len(raw.RawProfile)))
120133
d.metrics.receivedCompressedBytes.WithLabelValues(profName).Observe(float64(len(raw.RawProfile)))
121134
p, err := pprof.RawFromBytes(raw.RawProfile)
122135
if err != nil {

pkg/gen/google/v1/profile.pb.go

Lines changed: 9 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ingester/ingester.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ import (
2222
"github.com/grafana/phlare/pkg/phlaredb"
2323
"github.com/grafana/phlare/pkg/pprof"
2424
"github.com/grafana/phlare/pkg/tenant"
25+
"github.com/grafana/phlare/pkg/usagestats"
2526
"github.com/grafana/phlare/pkg/util"
2627
)
2728

29+
var activeTenantsStats = usagestats.NewInt("ingester_active_tenants")
30+
2831
type Config struct {
2932
LifecyclerConfig ring.LifecyclerConfig `yaml:"lifecycler,omitempty"`
3033
}
@@ -137,6 +140,7 @@ func (i *Ingester) GetOrCreateInstance(tenantID string) (*instance, error) { //n
137140
return nil, err
138141
}
139142
i.instances[tenantID] = inst
143+
activeTenantsStats.Set(int64(len(i.instances)))
140144
}
141145
return inst, nil
142146
}

pkg/phlare/modules.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"net/http"
7+
"os"
78

89
grpchealth "github.com/bufbuild/connect-grpchealth-go"
910
"github.com/go-kit/log"
@@ -35,10 +36,13 @@ import (
3536
"github.com/grafana/phlare/pkg/gen/push/v1/pushv1connect"
3637
"github.com/grafana/phlare/pkg/gen/querier/v1/querierv1connect"
3738
"github.com/grafana/phlare/pkg/ingester"
39+
"github.com/grafana/phlare/pkg/objstore"
3840
objstoreclient "github.com/grafana/phlare/pkg/objstore/client"
41+
"github.com/grafana/phlare/pkg/objstore/providers/filesystem"
3942
"github.com/grafana/phlare/pkg/openapiv2"
4043
phlarecontext "github.com/grafana/phlare/pkg/phlare/context"
4144
"github.com/grafana/phlare/pkg/querier"
45+
"github.com/grafana/phlare/pkg/usagestats"
4246
"github.com/grafana/phlare/pkg/util"
4347
"github.com/grafana/phlare/pkg/util/build"
4448
)
@@ -55,6 +59,7 @@ const (
5559
Querier string = "querier"
5660
GRPCGateway string = "grpc-gateway"
5761
Storage string = "storage"
62+
UsageReport string = "usage-stats"
5863

5964
// RuntimeConfig string = "runtime-config"
6065
// Overrides string = "overrides"
@@ -70,9 +75,10 @@ const (
7075
// IndexGateway string = "index-gateway"
7176
// IndexGatewayRing string = "index-gateway-ring"
7277
// QueryScheduler string = "query-scheduler"
73-
// UsageReport string = "usage-report"
7478
)
7579

80+
var objectStoreTypeStats = usagestats.NewString("store_object_type")
81+
7682
func (f *Phlare) initQuerier() (services.Service, error) {
7783
q, err := querier.New(f.Cfg.Querier, f.ring, nil, f.logger, f.auth)
7884
if err != nil {
@@ -138,6 +144,7 @@ func (f *Phlare) initMemberlistKV() (services.Service, error) {
138144
f.Cfg.MemberlistKV.MetricsRegisterer = f.reg
139145
f.Cfg.MemberlistKV.Codecs = []codec.Codec{
140146
ring.GetCodec(),
147+
usagestats.JSONCodec,
141148
}
142149

143150
dnsProviderReg := prometheus.WrapRegistererWithPrefix(
@@ -166,6 +173,7 @@ func (f *Phlare) initRing() (_ services.Service, err error) {
166173
}
167174

168175
func (f *Phlare) initStorage() (_ services.Service, err error) {
176+
objectStoreTypeStats.Set(f.Cfg.Storage.Bucket.Backend)
169177
if cfg := f.Cfg.Storage.Bucket; cfg.Backend != "filesystem" {
170178
b, err := objstoreclient.NewBucket(
171179
f.context(),
@@ -178,6 +186,10 @@ func (f *Phlare) initStorage() (_ services.Service, err error) {
178186
f.storageBucket = b
179187
}
180188

189+
if f.Cfg.Target.String() != All && f.storageBucket == nil {
190+
return nil, errors.New("storage bucket configuration is required when running in microservices mode")
191+
}
192+
181193
return nil, nil
182194
}
183195

@@ -267,6 +279,39 @@ func (f *Phlare) initServer() (services.Service, error) {
267279
return s, nil
268280
}
269281

282+
func (f *Phlare) initUsageReport() (services.Service, error) {
283+
if !f.Cfg.Analytics.Enabled {
284+
return nil, nil
285+
}
286+
f.Cfg.Analytics.Leader = false
287+
// ingester is the only component that can be a leader
288+
if f.isModuleActive(Ingester) {
289+
f.Cfg.Analytics.Leader = true
290+
}
291+
292+
usagestats.Target(f.Cfg.Target.String())
293+
294+
var b objstore.Bucket
295+
if f.storageBucket == nil {
296+
if err := os.MkdirAll(f.Cfg.PhlareDB.DataPath, 0o777); err != nil {
297+
return nil, fmt.Errorf("mkdir %s: %w", f.Cfg.PhlareDB.DataPath, err)
298+
}
299+
fs, err := filesystem.NewBucket(f.Cfg.PhlareDB.DataPath)
300+
if err != nil {
301+
return nil, err
302+
}
303+
b = fs
304+
}
305+
306+
ur, err := usagestats.NewReporter(f.Cfg.Analytics, f.Cfg.Ingester.LifecyclerConfig.RingConfig.KVStore, b, f.logger, f.reg)
307+
if err != nil {
308+
level.Info(f.logger).Log("msg", "failed to initialize usage report", "err", err)
309+
return nil, nil
310+
}
311+
f.usageReport = ur
312+
return ur, nil
313+
}
314+
270315
type statusService struct {
271316
commonv1.UnimplementedStatusServiceServer
272317
configYaml string
@@ -360,6 +405,32 @@ func (f *Phlare) statusService() commonv1.StatusServiceServer {
360405
}
361406
}
362407

408+
func (f *Phlare) isModuleActive(m string) bool {
409+
for _, target := range f.Cfg.Target {
410+
if target == m {
411+
return true
412+
}
413+
if f.recursiveIsModuleActive(target, m) {
414+
return true
415+
}
416+
}
417+
return false
418+
}
419+
420+
func (f *Phlare) recursiveIsModuleActive(target, m string) bool {
421+
if targetDeps, ok := f.deps[target]; ok {
422+
for _, dep := range targetDeps {
423+
if dep == m {
424+
return true
425+
}
426+
if f.recursiveIsModuleActive(dep, m) {
427+
return true
428+
}
429+
}
430+
}
431+
return false
432+
}
433+
363434
// NewServerService constructs service from Server component.
364435
// servicesToWaitFor is called when server is stopping, and should return all
365436
// services that need to terminate before server actually stops.

pkg/phlare/phlare.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242
"github.com/grafana/phlare/pkg/querier"
4343
"github.com/grafana/phlare/pkg/tenant"
4444
"github.com/grafana/phlare/pkg/tracing"
45+
"github.com/grafana/phlare/pkg/usagestats"
4546
"github.com/grafana/phlare/pkg/util"
4647
)
4748

@@ -58,8 +59,10 @@ type Config struct {
5859

5960
Storage StorageConfig `yaml:"storage"`
6061

61-
MultitenancyEnabled bool `yaml:"multitenancy_enabled,omitempty"`
62-
ConfigFile string
62+
MultitenancyEnabled bool `yaml:"multitenancy_enabled,omitempty"`
63+
Analytics usagestats.Config `yaml:"analytics"`
64+
65+
ConfigFile string `yaml:"-"`
6366
}
6467

6568
func newDefaultConfig() *Config {
@@ -98,6 +101,7 @@ func (c *Config) RegisterFlagsWithContext(ctx context.Context, f *flag.FlagSet)
98101
c.PhlareDB.RegisterFlags(f)
99102
c.Tracing.RegisterFlags(f)
100103
c.Storage.RegisterFlagsWithContext(ctx, f)
104+
c.Analytics.RegisterFlags(f)
101105
}
102106

103107
// registerServerFlagsWithChangedDefaultValues registers *Config.Server flags, but overrides some defaults set by the weaveworks package.
@@ -175,6 +179,7 @@ type Phlare struct {
175179
ring *ring.Ring
176180
agent *agent.Agent
177181
pusherClient pushv1connect.PusherServiceClient
182+
usageReport *usagestats.Reporter
178183

179184
storageBucket objstore.Bucket
180185

@@ -185,6 +190,7 @@ type Phlare struct {
185190

186191
func New(cfg Config) (*Phlare, error) {
187192
logger := initLogger(&cfg.Server)
193+
usagestats.Edition("oss")
188194

189195
phlare := &Phlare{
190196
Cfg: cfg,
@@ -234,15 +240,17 @@ func (f *Phlare) setupModuleManager() error {
234240
mm.RegisterModule(Distributor, f.initDistributor)
235241
mm.RegisterModule(Querier, f.initQuerier)
236242
mm.RegisterModule(Agent, f.initAgent)
243+
mm.RegisterModule(UsageReport, f.initUsageReport)
237244
mm.RegisterModule(All, nil)
238245

239246
// Add dependencies
240247
deps := map[string][]string{
241248
All: {Agent, Ingester, Distributor, Querier},
242-
Distributor: {Ring, Server},
243-
Querier: {Ring, Server},
249+
UsageReport: {Storage, MemberlistKV},
250+
Distributor: {Ring, Server, UsageReport},
251+
Querier: {Ring, Server, UsageReport},
244252
Agent: {Server},
245-
Ingester: {Server, MemberlistKV, Storage},
253+
Ingester: {Server, MemberlistKV, Storage, UsageReport},
246254
Ring: {Server, MemberlistKV},
247255
MemberlistKV: {Server},
248256
Server: {GRPCGateway},

0 commit comments

Comments
 (0)