Skip to content

Commit 4262bfd

Browse files
authored
Merge pull request #2093 from jzelinskie/spicedbinfo
metrics: spicedb_environment_info from telemetry
2 parents a39d5ca + bc90945 commit 4262bfd

File tree

3 files changed

+64
-17
lines changed

3 files changed

+64
-17
lines changed

internal/telemetry/metrics.go

+40-17
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,10 @@ import (
1717
log "github.com/authzed/spicedb/internal/logging"
1818
"github.com/authzed/spicedb/internal/middleware/usagemetrics"
1919
"github.com/authzed/spicedb/pkg/datastore"
20+
"github.com/authzed/spicedb/pkg/promutil"
2021
)
2122

22-
// RegisterTelemetryCollector registers a collector for the various pieces of
23-
// data required by SpiceDB telemetry.
24-
func RegisterTelemetryCollector(datastoreEngine string, ds datastore.Datastore) (*prometheus.Registry, error) {
25-
registry := prometheus.NewRegistry()
26-
27-
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
28-
defer cancel()
29-
23+
func SpiceDBClusterInfoCollector(ctx context.Context, subsystem, dsEngine string, ds datastore.Datastore) (promutil.CollectorFunc, error) {
3024
nodeID, err := os.Hostname()
3125
if err != nil {
3226
return nil, fmt.Errorf("unable to get hostname: %w", err)
@@ -43,10 +37,9 @@ func RegisterTelemetryCollector(datastoreEngine string, ds datastore.Datastore)
4337
return nil, fmt.Errorf("failed to read BuildInfo")
4438
}
4539

46-
if err := registry.Register(&collector{
47-
ds: ds,
48-
infoDesc: prometheus.NewDesc(
49-
prometheus.BuildFQName("spicedb", "telemetry", "info"),
40+
return func(ch chan<- prometheus.Metric) {
41+
ch <- prometheus.MustNewConstMetric(prometheus.NewDesc(
42+
prometheus.BuildFQName("spicedb", subsystem, "info"),
5043
"Information about the SpiceDB environment.",
5144
nil,
5245
prometheus.Labels{
@@ -57,9 +50,42 @@ func RegisterTelemetryCollector(datastoreEngine string, ds datastore.Datastore)
5750
"arch": runtime.GOARCH,
5851
"go": buildInfo.GoVersion,
5952
"vcpu": strconv.Itoa(runtime.NumCPU()),
60-
"ds_engine": datastoreEngine,
53+
"ds_engine": dsEngine,
6154
},
62-
),
55+
), prometheus.GaugeValue, 1)
56+
}, nil
57+
}
58+
59+
// RegisterTelemetryCollector registers a collector for the various pieces of
60+
// data required by SpiceDB telemetry.
61+
func RegisterTelemetryCollector(datastoreEngine string, ds datastore.Datastore) (*prometheus.Registry, error) {
62+
registry := prometheus.NewRegistry()
63+
64+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
65+
defer cancel()
66+
67+
infoCollector, err := SpiceDBClusterInfoCollector(ctx, "telemetry", datastoreEngine, ds)
68+
if err != nil {
69+
return nil, fmt.Errorf("unable create info collector: %w", err)
70+
}
71+
72+
if err := registry.Register(infoCollector); err != nil {
73+
return nil, fmt.Errorf("unable to register telemetry collector: %w", err)
74+
}
75+
76+
nodeID, err := os.Hostname()
77+
if err != nil {
78+
return nil, fmt.Errorf("unable to get hostname: %w", err)
79+
}
80+
81+
dbStats, err := ds.Statistics(ctx)
82+
if err != nil {
83+
return nil, fmt.Errorf("unable to query DB stats: %w", err)
84+
}
85+
clusterID := dbStats.UniqueID
86+
87+
if err := registry.Register(&collector{
88+
ds: ds,
6389
objectDefsDesc: prometheus.NewDesc(
6490
prometheus.BuildFQName("spicedb", "telemetry", "object_definitions_total"),
6591
"Count of the number of objects defined by the schema.",
@@ -96,7 +122,6 @@ func RegisterTelemetryCollector(datastoreEngine string, ds datastore.Datastore)
96122

97123
type collector struct {
98124
ds datastore.Datastore
99-
infoDesc *prometheus.Desc
100125
objectDefsDesc *prometheus.Desc
101126
relationshipsDesc *prometheus.Desc
102127
dispatchedDesc *prometheus.Desc
@@ -105,7 +130,6 @@ type collector struct {
105130
var _ prometheus.Collector = &collector{}
106131

107132
func (c *collector) Describe(ch chan<- *prometheus.Desc) {
108-
ch <- c.infoDesc
109133
ch <- c.objectDefsDesc
110134
ch <- c.relationshipsDesc
111135
ch <- c.dispatchedDesc
@@ -120,7 +144,6 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
120144
log.Warn().Err(err).Msg("unable to collect datastore statistics")
121145
}
122146

123-
ch <- prometheus.MustNewConstMetric(c.infoDesc, prometheus.GaugeValue, 1)
124147
ch <- prometheus.MustNewConstMetric(c.objectDefsDesc, prometheus.GaugeValue, float64(len(dsStats.ObjectTypeStatistics)))
125148
ch <- prometheus.MustNewConstMetric(c.relationshipsDesc, prometheus.GaugeValue, float64(dsStats.EstimatedRelationshipCount))
126149

pkg/cmd/server/server.go

+9
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,15 @@ func (c *Config) Complete(ctx context.Context) (RunnableServer, error) {
459459
closeables.AddCloser(gatewayCloser)
460460
closeables.AddWithoutError(gatewayServer.Close)
461461

462+
infoCollector, err := telemetry.SpiceDBClusterInfoCollector(ctx, "environment", c.DatastoreConfig.Engine, ds)
463+
if err != nil {
464+
log.Warn().Err(err).Msg("unable to initialize info collector")
465+
} else {
466+
if err := prometheus.Register(infoCollector); err != nil {
467+
log.Warn().Err(err).Msg("unable to initialize info collector")
468+
}
469+
}
470+
462471
var telemetryRegistry *prometheus.Registry
463472

464473
reporter := telemetry.DisabledReporter

pkg/promutil/promutil.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package promutil
2+
3+
import "github.com/prometheus/client_golang/prometheus"
4+
5+
var _ prometheus.Collector = (CollectorFunc)(nil)
6+
7+
// CollectorFunc is a convenient way to implement a Prometheus Collector
8+
// without interface boilerplate.
9+
//
10+
// This implementation relies on prometheus.DescribeByCollect; familiarize
11+
// yourself with that documentation before using.
12+
type CollectorFunc func(ch chan<- prometheus.Metric)
13+
14+
func (c CollectorFunc) Collect(ch chan<- prometheus.Metric) { c(ch) }
15+
func (c CollectorFunc) Describe(ch chan<- *prometheus.Desc) { prometheus.DescribeByCollect(c, ch) }

0 commit comments

Comments
 (0)