From 02b605d10956314a5c3e484aec2e0a76a9f4af71 Mon Sep 17 00:00:00 2001 From: Vibhu Pandey Date: Mon, 12 May 2025 14:32:13 +0530 Subject: [PATCH] feat(analytics): add analytics package (#7808) - add analytics package --- conf/example.yaml | 6 +++ go.mod | 3 +- go.sum | 6 +-- pkg/analytics/analytics.go | 15 +++++++ pkg/analytics/config.go | 36 ++++++++++++++++ pkg/analytics/noopanalytics/provider.go | 39 +++++++++++++++++ pkg/analytics/segmentanalytics/provider.go | 49 ++++++++++++++++++++++ pkg/query-service/telemetry/telemetry.go | 2 +- pkg/types/analyticstypes/message.go | 21 ++++++++++ 9 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 pkg/analytics/analytics.go create mode 100644 pkg/analytics/config.go create mode 100644 pkg/analytics/noopanalytics/provider.go create mode 100644 pkg/analytics/segmentanalytics/provider.go create mode 100644 pkg/types/analyticstypes/message.go diff --git a/conf/example.yaml b/conf/example.yaml index 2343c26d35..1ee4a2eeea 100644 --- a/conf/example.yaml +++ b/conf/example.yaml @@ -164,3 +164,9 @@ alertmanager: maintenance_interval: 15m # Retention of the notification logs. retention: 120h + + +##################### Analytics ##################### +analytics: + # Whether to enable analytics. + enabled: false diff --git a/go.mod b/go.mod index ab43bb6ee2..6af7b55b7e 100644 --- a/go.mod +++ b/go.mod @@ -48,6 +48,7 @@ require ( github.com/russellhaering/gosaml2 v0.9.0 github.com/russellhaering/goxmldsig v1.2.0 github.com/samber/lo v1.47.0 + github.com/segmentio/analytics-go/v3 v3.2.1 github.com/sethvargo/go-password v0.2.0 github.com/smartystreets/goconvey v1.8.1 github.com/soheilhy/cmux v0.1.5 @@ -74,7 +75,6 @@ require ( golang.org/x/sync v0.14.0 golang.org/x/text v0.25.0 google.golang.org/protobuf v1.36.0 - gopkg.in/segmentio/analytics-go.v3 v3.1.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/apimachinery v0.31.3 @@ -215,7 +215,6 @@ require ( github.com/vjeantet/grok v1.0.1 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.mongodb.org/mongo-driver v1.17.1 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect diff --git a/go.sum b/go.sum index d5c4d29de1..54e526069d 100644 --- a/go.sum +++ b/go.sum @@ -851,6 +851,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y= github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= +github.com/segmentio/analytics-go/v3 v3.2.1 h1:G+f90zxtc1p9G+WigVyTR0xNfOghOGs/PYAlljLOyeg= +github.com/segmentio/analytics-go/v3 v3.2.1/go.mod h1:p8owAF8X+5o27jmvUognuXxdtqvSGtD0ZrfY2kcS9bE= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/backo-go v1.0.1 h1:68RQccglxZeyURy93ASB/2kc9QudzgIDexJ927N++y4= @@ -948,8 +950,6 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= -github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= @@ -1645,8 +1645,6 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U= -gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/telebot.v3 v3.3.8 h1:uVDGjak9l824FN9YARWUHMsiNZnlohAVwUycw21k6t8= gopkg.in/telebot.v3 v3.3.8/go.mod h1:1mlbqcLTVSfK9dx7fdp+Nb5HZsy4LLPtpZTKmwhwtzM= diff --git a/pkg/analytics/analytics.go b/pkg/analytics/analytics.go new file mode 100644 index 0000000000..b31f14cdb5 --- /dev/null +++ b/pkg/analytics/analytics.go @@ -0,0 +1,15 @@ +package analytics + +import ( + "context" + + "github.com/SigNoz/signoz/pkg/factory" + "github.com/SigNoz/signoz/pkg/types/analyticstypes" +) + +type Analytics interface { + factory.Service + + // Sends analytics messages to an analytics backend. + Send(context.Context, ...analyticstypes.Message) +} diff --git a/pkg/analytics/config.go b/pkg/analytics/config.go new file mode 100644 index 0000000000..1bcbdd31c2 --- /dev/null +++ b/pkg/analytics/config.go @@ -0,0 +1,36 @@ +package analytics + +import ( + "fmt" + + "github.com/SigNoz/signoz/pkg/factory" +) + +// This will be set via ldflags at build time. +var ( + key string = "" +) + +type Config struct { + Enabled bool `mapstructure:"enabled"` + Key string `mapstructure:"key"` +} + +func NewConfigFactory() factory.ConfigFactory { + return factory.NewConfigFactory(factory.MustNewName("analytics"), newConfig) +} + +func newConfig() factory.Config { + return Config{ + Enabled: false, + Key: key, + } +} + +func (c Config) Validate() error { + if c.Key != key { + return fmt.Errorf("cannot override key set at build time with key: %s", c.Key) + } + + return nil +} diff --git a/pkg/analytics/noopanalytics/provider.go b/pkg/analytics/noopanalytics/provider.go new file mode 100644 index 0000000000..0e243343e2 --- /dev/null +++ b/pkg/analytics/noopanalytics/provider.go @@ -0,0 +1,39 @@ +package noopanalytics + +import ( + "context" + + "github.com/SigNoz/signoz/pkg/analytics" + "github.com/SigNoz/signoz/pkg/factory" + "github.com/SigNoz/signoz/pkg/types/analyticstypes" +) + +type provider struct { + settings factory.ScopedProviderSettings + startC chan struct{} +} + +func NewProviderFactory() factory.ProviderFactory[analytics.Analytics, analytics.Config] { + return factory.NewProviderFactory(factory.MustNewName("noop"), New) +} + +func New(ctx context.Context, providerSettings factory.ProviderSettings, config analytics.Config) (analytics.Analytics, error) { + settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/analytics/noopanalytics") + + return &provider{ + settings: settings, + startC: make(chan struct{}), + }, nil +} + +func (provider *provider) Start(_ context.Context) error { + <-provider.startC + return nil +} + +func (provider *provider) Send(ctx context.Context, messages ...analyticstypes.Message) {} + +func (provider *provider) Stop(_ context.Context) error { + close(provider.startC) + return nil +} diff --git a/pkg/analytics/segmentanalytics/provider.go b/pkg/analytics/segmentanalytics/provider.go new file mode 100644 index 0000000000..35fbf88206 --- /dev/null +++ b/pkg/analytics/segmentanalytics/provider.go @@ -0,0 +1,49 @@ +package segmentanalytics + +import ( + "context" + + "github.com/SigNoz/signoz/pkg/analytics" + "github.com/SigNoz/signoz/pkg/factory" + "github.com/SigNoz/signoz/pkg/types/analyticstypes" + segment "github.com/segmentio/analytics-go/v3" +) + +type provider struct { + settings factory.ScopedProviderSettings + client segment.Client + startC chan struct{} +} + +func NewProviderFactory() factory.ProviderFactory[analytics.Analytics, analytics.Config] { + return factory.NewProviderFactory(factory.MustNewName("segment"), New) +} + +func New(ctx context.Context, providerSettings factory.ProviderSettings, config analytics.Config) (analytics.Analytics, error) { + settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/analytics/segmentanalytics") + + return &provider{ + settings: settings, + client: segment.New(config.Key), + startC: make(chan struct{}), + }, nil +} + +func (provider *provider) Start(_ context.Context) error { + <-provider.startC + return nil +} + +func (provider *provider) Send(ctx context.Context, messages ...analyticstypes.Message) { + for _, message := range messages { + err := provider.client.Enqueue(message) + if err != nil { + provider.settings.Logger().WarnContext(ctx, "unable to send message to segment", "err", err) + } + } +} + +func (provider *provider) Stop(_ context.Context) error { + close(provider.startC) + return nil +} diff --git a/pkg/query-service/telemetry/telemetry.go b/pkg/query-service/telemetry/telemetry.go index e01f74ec6b..c393bb8aa9 100644 --- a/pkg/query-service/telemetry/telemetry.go +++ b/pkg/query-service/telemetry/telemetry.go @@ -12,8 +12,8 @@ import ( "time" "github.com/go-co-op/gocron" + analytics "github.com/segmentio/analytics-go/v3" "go.uber.org/zap" - "gopkg.in/segmentio/analytics-go.v3" "github.com/SigNoz/signoz/pkg/query-service/constants" "github.com/SigNoz/signoz/pkg/query-service/interfaces" diff --git a/pkg/types/analyticstypes/message.go b/pkg/types/analyticstypes/message.go new file mode 100644 index 0000000000..5f2c4436e3 --- /dev/null +++ b/pkg/types/analyticstypes/message.go @@ -0,0 +1,21 @@ +package analyticstypes + +import ( + segment "github.com/segmentio/analytics-go/v3" +) + +type Message = segment.Message +type Group = segment.Group +type Identify = segment.Identify +type Track = segment.Track +type Traits = segment.Traits +type Properties = segment.Properties +type Context = segment.Context + +func NewTraits() Traits { + return segment.NewTraits() +} + +func NewProperties() Properties { + return segment.NewProperties() +}