mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-17 15:36:48 +00:00
feat(licensing): add analytics (#8252)
This commit is contained in:
parent
d236b6ce1e
commit
59ff7ed1e1
@ -6,11 +6,13 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/ee/licensing/licensingstore/sqllicensingstore"
|
"github.com/SigNoz/signoz/ee/licensing/licensingstore/sqllicensingstore"
|
||||||
|
"github.com/SigNoz/signoz/pkg/analytics"
|
||||||
"github.com/SigNoz/signoz/pkg/errors"
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
"github.com/SigNoz/signoz/pkg/licensing"
|
"github.com/SigNoz/signoz/pkg/licensing"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types/analyticstypes"
|
||||||
"github.com/SigNoz/signoz/pkg/types/licensetypes"
|
"github.com/SigNoz/signoz/pkg/types/licensetypes"
|
||||||
"github.com/SigNoz/signoz/pkg/valuer"
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
"github.com/SigNoz/signoz/pkg/zeus"
|
"github.com/SigNoz/signoz/pkg/zeus"
|
||||||
@ -23,16 +25,17 @@ type provider struct {
|
|||||||
config licensing.Config
|
config licensing.Config
|
||||||
settings factory.ScopedProviderSettings
|
settings factory.ScopedProviderSettings
|
||||||
orgGetter organization.Getter
|
orgGetter organization.Getter
|
||||||
|
analytics analytics.Analytics
|
||||||
stopChan chan struct{}
|
stopChan chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProviderFactory(store sqlstore.SQLStore, zeus zeus.Zeus, orgGetter organization.Getter) factory.ProviderFactory[licensing.Licensing, licensing.Config] {
|
func NewProviderFactory(store sqlstore.SQLStore, zeus zeus.Zeus, orgGetter organization.Getter, analytics analytics.Analytics) factory.ProviderFactory[licensing.Licensing, licensing.Config] {
|
||||||
return factory.NewProviderFactory(factory.MustNewName("http"), func(ctx context.Context, providerSettings factory.ProviderSettings, config licensing.Config) (licensing.Licensing, error) {
|
return factory.NewProviderFactory(factory.MustNewName("http"), func(ctx context.Context, providerSettings factory.ProviderSettings, config licensing.Config) (licensing.Licensing, error) {
|
||||||
return New(ctx, providerSettings, config, store, zeus, orgGetter)
|
return New(ctx, providerSettings, config, store, zeus, orgGetter, analytics)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, ps factory.ProviderSettings, config licensing.Config, sqlstore sqlstore.SQLStore, zeus zeus.Zeus, orgGetter organization.Getter) (licensing.Licensing, error) {
|
func New(ctx context.Context, ps factory.ProviderSettings, config licensing.Config, sqlstore sqlstore.SQLStore, zeus zeus.Zeus, orgGetter organization.Getter, analytics analytics.Analytics) (licensing.Licensing, error) {
|
||||||
settings := factory.NewScopedProviderSettings(ps, "github.com/SigNoz/signoz/ee/licensing/httplicensing")
|
settings := factory.NewScopedProviderSettings(ps, "github.com/SigNoz/signoz/ee/licensing/httplicensing")
|
||||||
licensestore := sqllicensingstore.New(sqlstore)
|
licensestore := sqllicensingstore.New(sqlstore)
|
||||||
return &provider{
|
return &provider{
|
||||||
@ -42,6 +45,7 @@ func New(ctx context.Context, ps factory.ProviderSettings, config licensing.Conf
|
|||||||
settings: settings,
|
settings: settings,
|
||||||
orgGetter: orgGetter,
|
orgGetter: orgGetter,
|
||||||
stopChan: make(chan struct{}),
|
stopChan: make(chan struct{}),
|
||||||
|
analytics: analytics,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +163,25 @@ func (provider *provider) Refresh(ctx context.Context, organizationID valuer.UUI
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stats := licensetypes.NewStatsFromLicense(activeLicense)
|
||||||
|
provider.analytics.Send(ctx,
|
||||||
|
analyticstypes.Track{
|
||||||
|
UserId: "stats_" + organizationID.String(),
|
||||||
|
Event: "License Updated",
|
||||||
|
Properties: analyticstypes.NewPropertiesFromMap(stats),
|
||||||
|
Context: &analyticstypes.Context{
|
||||||
|
Extra: map[string]interface{}{
|
||||||
|
analyticstypes.KeyGroupID: organizationID.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
analyticstypes.Group{
|
||||||
|
UserId: "stats_" + organizationID.String(),
|
||||||
|
GroupId: organizationID.String(),
|
||||||
|
Traits: analyticstypes.NewTraitsFromMap(stats),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/ee/sqlstore/postgressqlstore"
|
"github.com/SigNoz/signoz/ee/sqlstore/postgressqlstore"
|
||||||
"github.com/SigNoz/signoz/ee/zeus"
|
"github.com/SigNoz/signoz/ee/zeus"
|
||||||
"github.com/SigNoz/signoz/ee/zeus/httpzeus"
|
"github.com/SigNoz/signoz/ee/zeus/httpzeus"
|
||||||
|
"github.com/SigNoz/signoz/pkg/analytics"
|
||||||
"github.com/SigNoz/signoz/pkg/config"
|
"github.com/SigNoz/signoz/pkg/config"
|
||||||
"github.com/SigNoz/signoz/pkg/config/envprovider"
|
"github.com/SigNoz/signoz/pkg/config/envprovider"
|
||||||
"github.com/SigNoz/signoz/pkg/config/fileprovider"
|
"github.com/SigNoz/signoz/pkg/config/fileprovider"
|
||||||
@ -134,8 +135,8 @@ func main() {
|
|||||||
zeus.Config(),
|
zeus.Config(),
|
||||||
httpzeus.NewProviderFactory(),
|
httpzeus.NewProviderFactory(),
|
||||||
licensing.Config(24*time.Hour, 3),
|
licensing.Config(24*time.Hour, 3),
|
||||||
func(sqlstore sqlstore.SQLStore, zeus pkgzeus.Zeus, orgGetter organization.Getter) factory.ProviderFactory[pkglicensing.Licensing, pkglicensing.Config] {
|
func(sqlstore sqlstore.SQLStore, zeus pkgzeus.Zeus, orgGetter organization.Getter, analytics analytics.Analytics) factory.ProviderFactory[pkglicensing.Licensing, pkglicensing.Config] {
|
||||||
return httplicensing.NewProviderFactory(sqlstore, zeus, orgGetter)
|
return httplicensing.NewProviderFactory(sqlstore, zeus, orgGetter, analytics)
|
||||||
},
|
},
|
||||||
signoz.NewEmailingProviderFactories(),
|
signoz.NewEmailingProviderFactories(),
|
||||||
signoz.NewCacheProviderFactories(),
|
signoz.NewCacheProviderFactories(),
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/analytics"
|
||||||
"github.com/SigNoz/signoz/pkg/config"
|
"github.com/SigNoz/signoz/pkg/config"
|
||||||
"github.com/SigNoz/signoz/pkg/config/envprovider"
|
"github.com/SigNoz/signoz/pkg/config/envprovider"
|
||||||
"github.com/SigNoz/signoz/pkg/config/fileprovider"
|
"github.com/SigNoz/signoz/pkg/config/fileprovider"
|
||||||
@ -122,7 +123,7 @@ func main() {
|
|||||||
zeus.Config{},
|
zeus.Config{},
|
||||||
noopzeus.NewProviderFactory(),
|
noopzeus.NewProviderFactory(),
|
||||||
licensing.Config{},
|
licensing.Config{},
|
||||||
func(_ sqlstore.SQLStore, _ zeus.Zeus, _ organization.Getter) factory.ProviderFactory[licensing.Licensing, licensing.Config] {
|
func(_ sqlstore.SQLStore, _ zeus.Zeus, _ organization.Getter, _ analytics.Analytics) factory.ProviderFactory[licensing.Licensing, licensing.Config] {
|
||||||
return nooplicensing.NewFactory()
|
return nooplicensing.NewFactory()
|
||||||
},
|
},
|
||||||
signoz.NewEmailingProviderFactories(),
|
signoz.NewEmailingProviderFactories(),
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/analytics"
|
||||||
"github.com/SigNoz/signoz/pkg/cache"
|
"github.com/SigNoz/signoz/pkg/cache"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing"
|
"github.com/SigNoz/signoz/pkg/emailing"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
@ -54,7 +55,7 @@ func New(
|
|||||||
zeusConfig zeus.Config,
|
zeusConfig zeus.Config,
|
||||||
zeusProviderFactory factory.ProviderFactory[zeus.Zeus, zeus.Config],
|
zeusProviderFactory factory.ProviderFactory[zeus.Zeus, zeus.Config],
|
||||||
licenseConfig licensing.Config,
|
licenseConfig licensing.Config,
|
||||||
licenseProviderFactory func(sqlstore.SQLStore, zeus.Zeus, organization.Getter) factory.ProviderFactory[licensing.Licensing, licensing.Config],
|
licenseProviderFactory func(sqlstore.SQLStore, zeus.Zeus, organization.Getter, analytics.Analytics) factory.ProviderFactory[licensing.Licensing, licensing.Config],
|
||||||
emailingProviderFactories factory.NamedMap[factory.ProviderFactory[emailing.Emailing, emailing.Config]],
|
emailingProviderFactories factory.NamedMap[factory.ProviderFactory[emailing.Emailing, emailing.Config]],
|
||||||
cacheProviderFactories factory.NamedMap[factory.ProviderFactory[cache.Cache, cache.Config]],
|
cacheProviderFactories factory.NamedMap[factory.ProviderFactory[cache.Cache, cache.Config]],
|
||||||
webProviderFactories factory.NamedMap[factory.ProviderFactory[web.Web, web.Config]],
|
webProviderFactories factory.NamedMap[factory.ProviderFactory[web.Web, web.Config]],
|
||||||
@ -235,7 +236,7 @@ func New(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
licensingProviderFactory := licenseProviderFactory(sqlstore, zeus, orgGetter)
|
licensingProviderFactory := licenseProviderFactory(sqlstore, zeus, orgGetter, analytics)
|
||||||
licensing, err := licensingProviderFactory.New(
|
licensing, err := licensingProviderFactory.New(
|
||||||
ctx,
|
ctx,
|
||||||
providerSettings,
|
providerSettings,
|
||||||
|
|||||||
@ -32,6 +32,8 @@ type License struct {
|
|||||||
PlanName valuer.String
|
PlanName valuer.String
|
||||||
Features []*Feature
|
Features []*Feature
|
||||||
Status valuer.String
|
Status valuer.String
|
||||||
|
State string
|
||||||
|
FreeUntil time.Time
|
||||||
ValidFrom int64
|
ValidFrom int64
|
||||||
ValidUntil int64
|
ValidUntil int64
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
@ -165,6 +167,21 @@ func NewLicense(data []byte, organizationID valuer.UUID) (*License, error) {
|
|||||||
planName = PlanNameBasic
|
planName = PlanNameBasic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state, err := extractKeyFromMapStringInterface[string](licenseData, "state")
|
||||||
|
if err != nil {
|
||||||
|
state = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
freeUntilStr, err := extractKeyFromMapStringInterface[string](licenseData, "free_until")
|
||||||
|
if err != nil {
|
||||||
|
freeUntilStr = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
freeUntil, err := time.Parse(time.RFC3339, freeUntilStr)
|
||||||
|
if err != nil {
|
||||||
|
freeUntil = time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
featuresFromZeus := make([]*Feature, 0)
|
featuresFromZeus := make([]*Feature, 0)
|
||||||
if _features, ok := licenseData["features"]; ok {
|
if _features, ok := licenseData["features"]; ok {
|
||||||
featuresData, err := json.Marshal(_features)
|
featuresData, err := json.Marshal(_features)
|
||||||
@ -224,6 +241,8 @@ func NewLicense(data []byte, organizationID valuer.UUID) (*License, error) {
|
|||||||
ValidFrom: validFrom,
|
ValidFrom: validFrom,
|
||||||
ValidUntil: validUntil,
|
ValidUntil: validUntil,
|
||||||
Status: status,
|
Status: status,
|
||||||
|
State: state,
|
||||||
|
FreeUntil: freeUntil,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
UpdatedAt: time.Now(),
|
UpdatedAt: time.Now(),
|
||||||
LastValidatedAt: time.Now(),
|
LastValidatedAt: time.Now(),
|
||||||
@ -306,6 +325,21 @@ func NewLicenseFromStorableLicense(storableLicense *StorableLicense) (*License,
|
|||||||
}
|
}
|
||||||
validUntil := int64(_validUntil)
|
validUntil := int64(_validUntil)
|
||||||
|
|
||||||
|
state, err := extractKeyFromMapStringInterface[string](storableLicense.Data, "state")
|
||||||
|
if err != nil {
|
||||||
|
state = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
freeUntilStr, err := extractKeyFromMapStringInterface[string](storableLicense.Data, "free_until")
|
||||||
|
if err != nil {
|
||||||
|
freeUntilStr = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
freeUntil, err := time.Parse(time.RFC3339, freeUntilStr)
|
||||||
|
if err != nil {
|
||||||
|
freeUntil = time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
return &License{
|
return &License{
|
||||||
ID: storableLicense.ID,
|
ID: storableLicense.ID,
|
||||||
Key: storableLicense.Key,
|
Key: storableLicense.Key,
|
||||||
@ -315,6 +349,8 @@ func NewLicenseFromStorableLicense(storableLicense *StorableLicense) (*License,
|
|||||||
ValidFrom: validFrom,
|
ValidFrom: validFrom,
|
||||||
ValidUntil: validUntil,
|
ValidUntil: validUntil,
|
||||||
Status: status,
|
Status: status,
|
||||||
|
State: state,
|
||||||
|
FreeUntil: freeUntil,
|
||||||
CreatedAt: storableLicense.CreatedAt,
|
CreatedAt: storableLicense.CreatedAt,
|
||||||
UpdatedAt: storableLicense.UpdatedAt,
|
UpdatedAt: storableLicense.UpdatedAt,
|
||||||
LastValidatedAt: storableLicense.LastValidatedAt,
|
LastValidatedAt: storableLicense.LastValidatedAt,
|
||||||
@ -325,8 +361,10 @@ func NewLicenseFromStorableLicense(storableLicense *StorableLicense) (*License,
|
|||||||
|
|
||||||
func NewStatsFromLicense(license *License) map[string]any {
|
func NewStatsFromLicense(license *License) map[string]any {
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"license.plan": license.PlanName.StringValue(),
|
"license.id": license.ID.StringValue(),
|
||||||
"license.id": license.ID.StringValue(),
|
"license.plan.name": license.PlanName.StringValue(),
|
||||||
|
"license.state.name": license.State,
|
||||||
|
"license.free_until.time": license.FreeUntil.UTC(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -74,7 +74,7 @@ func TestNewLicenseV3(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Parse the entire license properly",
|
name: "Parse the entire license properly",
|
||||||
data: []byte(`{"id":"0196f794-ff30-7bee-a5f4-ef5ad315715e","key":"does-not-matter-key","category":"FREE","status":"ACTIVE","plan":{"name":"ENTERPRISE"},"valid_from": 1730899309,"valid_until": -1}`),
|
data: []byte(`{"id":"0196f794-ff30-7bee-a5f4-ef5ad315715e","key":"does-not-matter-key","category":"FREE","status":"ACTIVE","plan":{"name":"ENTERPRISE"},"valid_from": 1730899309,"valid_until": -1,"state":"test","free_until":"2025-05-16T11:17:48.124202Z"}`),
|
||||||
pass: true,
|
pass: true,
|
||||||
expected: &License{
|
expected: &License{
|
||||||
ID: valuer.MustNewUUID("0196f794-ff30-7bee-a5f4-ef5ad315715e"),
|
ID: valuer.MustNewUUID("0196f794-ff30-7bee-a5f4-ef5ad315715e"),
|
||||||
@ -87,11 +87,15 @@ func TestNewLicenseV3(t *testing.T) {
|
|||||||
"status": "ACTIVE",
|
"status": "ACTIVE",
|
||||||
"valid_from": float64(1730899309),
|
"valid_from": float64(1730899309),
|
||||||
"valid_until": float64(-1),
|
"valid_until": float64(-1),
|
||||||
|
"state": "test",
|
||||||
|
"free_until": "2025-05-16T11:17:48.124202Z",
|
||||||
},
|
},
|
||||||
PlanName: PlanNameEnterprise,
|
PlanName: PlanNameEnterprise,
|
||||||
ValidFrom: 1730899309,
|
ValidFrom: 1730899309,
|
||||||
ValidUntil: -1,
|
ValidUntil: -1,
|
||||||
Status: valuer.NewString("ACTIVE"),
|
Status: valuer.NewString("ACTIVE"),
|
||||||
|
State: "test",
|
||||||
|
FreeUntil: time.Date(2025, 5, 16, 11, 17, 48, 124202000, time.UTC),
|
||||||
Features: make([]*Feature, 0),
|
Features: make([]*Feature, 0),
|
||||||
OrganizationID: valuer.MustNewUUID("0196f794-ff30-7bee-a5f4-ef5ad315715e"),
|
OrganizationID: valuer.MustNewUUID("0196f794-ff30-7bee-a5f4-ef5ad315715e"),
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user