From 288747aade70e29be9d57c665ce390db5dade734 Mon Sep 17 00:00:00 2001 From: grandwizard28 Date: Tue, 14 Jan 2025 19:57:51 +0530 Subject: [PATCH] feat(factory): embrace the factory pattern --- ee/query-service/app/server.go | 24 ++--- ee/query-service/main.go | 20 +++- pkg/cache/config.go | 17 +-- pkg/cache/provider/memory/memory.go | 101 ++++++++++++++++++ .../memory/memory_test.go | 63 ++++++----- .../{strategy => provider}/redis/redis.go | 16 +-- .../redis/redis_test.go | 0 pkg/cache/strategy/memory/memory.go | 96 ----------------- pkg/config/conf.go | 7 -- pkg/config/config.go | 39 ++----- pkg/factory/config.go | 37 +++++++ pkg/factory/name.go | 38 +++++++ pkg/factory/named.go | 64 +++++++++++ pkg/factory/provider.go | 48 +++++++++ pkg/factory/setting.go | 19 ++++ pkg/instrumentation/instrumentation.go | 45 ++++++-- pkg/query-service/app/server.go | 22 ++-- pkg/query-service/main.go | 20 +++- pkg/query-service/utils/testutils.go | 32 ++++-- pkg/signoz/config.go | 17 ++- pkg/signoz/provider.go | 47 ++++++++ pkg/signoz/signoz.go | 48 ++++----- pkg/sqlstore/config.go | 19 ++-- pkg/sqlstore/migration.go | 42 -------- .../migrations/000_add_data_migrations.go | 11 +- .../migrations/001_add_organization.go | 11 +- .../migrations/002_add_preferences.go | 11 +- pkg/sqlstore/migrations/003_add_dashboards.go | 11 +- .../migrations/004_add_saved_views.go | 11 +- pkg/sqlstore/migrations/005_add_agents.go | 11 +- pkg/sqlstore/migrations/006_add_pipelines.go | 11 +- .../migrations/007_add_integrations.go | 11 +- pkg/sqlstore/migrations/migrations.go | 28 +++-- pkg/sqlstore/provider/provider.go | 17 --- .../sqlite/{provider.go => sqlite.go} | 15 ++- pkg/sqlstore/sqlstore.go | 29 +++-- pkg/web/config.go | 24 ++--- pkg/web/config_test.go | 3 +- pkg/web/noop/noop.go | 20 ---- pkg/web/provider/noop/noop.go | 26 +++++ pkg/web/{ => provider}/router/router.go | 31 +++--- pkg/web/{ => provider}/router/router_test.go | 7 +- .../{ => provider}/router/testdata/index.html | 0 43 files changed, 718 insertions(+), 451 deletions(-) create mode 100644 pkg/cache/provider/memory/memory.go rename pkg/cache/{strategy => provider}/memory/memory_test.go (78%) rename pkg/cache/{strategy => provider}/redis/redis.go (90%) rename pkg/cache/{strategy => provider}/redis/redis_test.go (100%) delete mode 100644 pkg/cache/strategy/memory/memory.go create mode 100644 pkg/factory/config.go create mode 100644 pkg/factory/name.go create mode 100644 pkg/factory/named.go create mode 100644 pkg/factory/provider.go create mode 100644 pkg/factory/setting.go create mode 100644 pkg/signoz/provider.go delete mode 100644 pkg/sqlstore/migration.go delete mode 100644 pkg/sqlstore/provider/provider.go rename pkg/sqlstore/provider/sqlite/{provider.go => sqlite.go} (65%) delete mode 100644 pkg/web/noop/noop.go create mode 100644 pkg/web/provider/noop/noop.go rename pkg/web/{ => provider}/router/router.go (70%) rename pkg/web/{ => provider}/router/router_test.go (89%) rename pkg/web/{ => provider}/router/testdata/index.html (100%) diff --git a/ee/query-service/app/server.go b/ee/query-service/app/server.go index 2236284103..b5848999b4 100644 --- a/ee/query-service/app/server.go +++ b/ee/query-service/app/server.go @@ -111,14 +111,14 @@ func (s Server) HealthCheckStatus() chan healthcheck.Status { // NewServer creates and initializes Server func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signoz.SigNoz) (*Server, error) { - modelDao, err := dao.InitDao(signoz.SqlStore.Provider().SqlxDB()) + modelDao, err := dao.InitDao(signoz.SQLStore.SQLxDB()) if err != nil { return nil, err } - baseexplorer.InitWithDB(signoz.SqlStore.Provider().SqlxDB()) - preferences.InitDB(signoz.SqlStore.Provider().SqlxDB()) - dashboards.InitDB(signoz.SqlStore.Provider().SqlxDB()) + baseexplorer.InitWithDB(signoz.SQLStore.SQLxDB()) + preferences.InitDB(signoz.SQLStore.SQLxDB()) + dashboards.InitDB(signoz.SQLStore.SQLxDB()) gatewayProxy, err := gateway.NewProxy(serverOptions.GatewayUrl, gateway.RoutePrefix) if err != nil { @@ -126,7 +126,7 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo } // initiate license manager - lm, err := licensepkg.StartManager("sqlite", signoz.SqlStore.Provider().SqlxDB()) + lm, err := licensepkg.StartManager("sqlite", signoz.SQLStore.SQLxDB()) if err != nil { return nil, err } @@ -140,7 +140,7 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo if storage == "clickhouse" { zap.L().Info("Using ClickHouse as datastore ...") qb := db.NewDataConnector( - signoz.SqlStore.Provider().SqlxDB(), + signoz.SQLStore.SQLxDB(), serverOptions.PromConfigPath, lm, serverOptions.MaxIdleConns, @@ -176,7 +176,7 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo rm, err := makeRulesManager(serverOptions.PromConfigPath, baseconst.GetAlertManagerApiPrefix(), serverOptions.RuleRepoURL, - signoz.SqlStore.Provider().SqlxDB(), + signoz.SQLStore.SQLxDB(), reader, c, serverOptions.DisableRules, @@ -197,16 +197,16 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo }() // initiate opamp - _ = opAmpModel.InitDB(signoz.SqlStore.Provider().SqlxDB()) + _ = opAmpModel.InitDB(signoz.SQLStore.SQLxDB()) - integrationsController, err := integrations.NewController(signoz.SqlStore.Provider().SqlxDB()) + integrationsController, err := integrations.NewController(signoz.SQLStore.SQLxDB()) if err != nil { return nil, fmt.Errorf( "couldn't create integrations controller: %w", err, ) } - cloudIntegrationsController, err := cloudintegrations.NewController(signoz.SqlStore.Provider().SqlxDB()) + cloudIntegrationsController, err := cloudintegrations.NewController(signoz.SQLStore.SQLxDB()) if err != nil { return nil, fmt.Errorf( "couldn't create cloud provider integrations controller: %w", err, @@ -215,7 +215,7 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo // ingestion pipelines manager logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController( - signoz.SqlStore.Provider().SqlxDB(), integrationsController.GetPipelinesForInstalledIntegrations, + signoz.SQLStore.SQLxDB(), integrationsController.GetPipelinesForInstalledIntegrations, ) if err != nil { return nil, err @@ -223,7 +223,7 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo // initiate agent config handler agentConfMgr, err := agentConf.Initiate(&agentConf.ManagerOptions{ - DB: signoz.SqlStore.Provider().SqlxDB(), + DB: signoz.SQLStore.SQLxDB(), AgentFeatures: []agentConf.AgentFeature{logParsingPipelineController}, }) if err != nil { diff --git a/ee/query-service/main.go b/ee/query-service/main.go index 010b42d805..163be92ccb 100644 --- a/ee/query-service/main.go +++ b/ee/query-service/main.go @@ -16,10 +16,12 @@ import ( "go.signoz.io/signoz/pkg/config" signozconfig "go.signoz.io/signoz/pkg/config" "go.signoz.io/signoz/pkg/config/provider/envprovider" + "go.signoz.io/signoz/pkg/instrumentation" "go.signoz.io/signoz/pkg/query-service/auth" baseconst "go.signoz.io/signoz/pkg/query-service/constants" "go.signoz.io/signoz/pkg/query-service/version" "go.signoz.io/signoz/pkg/signoz" + pkgversion "go.signoz.io/signoz/pkg/version" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -143,7 +145,23 @@ func main() { zap.L().Fatal("Failed to create config", zap.Error(err)) } - signoz, err := signoz.New(config) + instrumentation, err := instrumentation.New(context.Background(), pkgversion.Build{}, instrumentation.Config{ + Logs: instrumentation.LogsConfig{ + Enabled: false, + Level: zapcore.InfoLevel, + }, + Traces: instrumentation.TracesConfig{ + Enabled: false, + }, + Metrics: instrumentation.MetricsConfig{ + Enabled: false, + }, + }) + if err != nil { + zap.L().Fatal("Failed to create instrumentation", zap.Error(err)) + } + + signoz, err := signoz.New(context.Background(), instrumentation, config, signoz.NewProviderFactories()) if err != nil { zap.L().Fatal("Failed to create signoz struct", zap.Error(err)) } diff --git a/pkg/cache/config.go b/pkg/cache/config.go index b206867c2c..ad80b6275a 100644 --- a/pkg/cache/config.go +++ b/pkg/cache/config.go @@ -4,12 +4,9 @@ import ( "time" go_cache "github.com/patrickmn/go-cache" - "go.signoz.io/signoz/pkg/config" + "go.signoz.io/signoz/pkg/factory" ) -// Config satisfies the confmap.Config interface -var _ config.Config = (*Config)(nil) - type Memory struct { TTL time.Duration `mapstructure:"ttl"` CleanupInterval time.Duration `mapstructure:"cleanupInterval"` @@ -28,11 +25,11 @@ type Config struct { Redis Redis `mapstructure:"redis"` } -func NewConfigFactory() config.ConfigFactory { - return config.NewConfigFactory(newConfig) +func NewConfigFactory() factory.ConfigFactory { + return factory.NewConfigFactory(factory.MustNewName("cache"), newConfig) } -func newConfig() config.Config { +func newConfig() factory.Config { return &Config{ Provider: "memory", Memory: Memory{ @@ -49,10 +46,6 @@ func newConfig() config.Config { } -func (c *Config) Key() string { - return "cache" -} - -func (c *Config) Validate() error { +func (c Config) Validate() error { return nil } diff --git a/pkg/cache/provider/memory/memory.go b/pkg/cache/provider/memory/memory.go new file mode 100644 index 0000000000..2b497d5569 --- /dev/null +++ b/pkg/cache/provider/memory/memory.go @@ -0,0 +1,101 @@ +package memory + +import ( + "context" + "fmt" + "reflect" + "time" + + gocache "github.com/patrickmn/go-cache" + "go.signoz.io/signoz/pkg/cache" + "go.signoz.io/signoz/pkg/factory" +) + +type memory struct { + cc *gocache.Cache +} + +func NewFactory() factory.ProviderFactory[cache.Cache, cache.Config] { + return factory.NewProviderFactory(factory.MustNewName("memory"), New) +} + +func New(ctx context.Context, settings factory.ProviderSettings, config cache.Config) (cache.Cache, error) { + return &memory{cc: gocache.New(config.Memory.TTL, config.Memory.CleanupInterval)}, nil +} + +// Connect does nothing +func (c *memory) Connect(_ context.Context) error { + return nil +} + +// Store stores the data in the cache +func (c *memory) Store(_ context.Context, cacheKey string, data cache.CacheableEntity, ttl time.Duration) error { + // check if the data being passed is a pointer and is not nil + rv := reflect.ValueOf(data) + if rv.Kind() != reflect.Pointer || rv.IsNil() { + return cache.WrapCacheableEntityErrors(reflect.TypeOf(data), "inmemory") + } + + c.cc.Set(cacheKey, data, ttl) + return nil +} + +// Retrieve retrieves the data from the cache +func (c *memory) Retrieve(_ context.Context, cacheKey string, dest cache.CacheableEntity, allowExpired bool) (cache.RetrieveStatus, error) { + // check if the destination being passed is a pointer and is not nil + dstv := reflect.ValueOf(dest) + if dstv.Kind() != reflect.Pointer || dstv.IsNil() { + return cache.RetrieveStatusError, cache.WrapCacheableEntityErrors(reflect.TypeOf(dest), "inmemory") + } + + // check if the destination value is settable + if !dstv.Elem().CanSet() { + return cache.RetrieveStatusError, fmt.Errorf("destination value is not settable, %s", dstv.Elem()) + } + + data, found := c.cc.Get(cacheKey) + if !found { + return cache.RetrieveStatusKeyMiss, nil + } + + // check the type compatbility between the src and dest + srcv := reflect.ValueOf(data) + if !srcv.Type().AssignableTo(dstv.Type()) { + return cache.RetrieveStatusError, fmt.Errorf("src type is not assignable to dst type") + } + + // set the value to from src to dest + dstv.Elem().Set(srcv.Elem()) + return cache.RetrieveStatusHit, nil +} + +// SetTTL sets the TTL for the cache entry +func (c *memory) SetTTL(_ context.Context, cacheKey string, ttl time.Duration) { + item, found := c.cc.Get(cacheKey) + if !found { + return + } + c.cc.Replace(cacheKey, item, ttl) +} + +// Remove removes the cache entry +func (c *memory) Remove(_ context.Context, cacheKey string) { + c.cc.Delete(cacheKey) +} + +// BulkRemove removes the cache entries +func (c *memory) BulkRemove(_ context.Context, cacheKeys []string) { + for _, cacheKey := range cacheKeys { + c.cc.Delete(cacheKey) + } +} + +// Close does nothing +func (c *memory) Close(_ context.Context) error { + return nil +} + +// Configuration returns the cache configuration +func (c *memory) Configuration() *cache.Memory { + return nil +} diff --git a/pkg/cache/strategy/memory/memory_test.go b/pkg/cache/provider/memory/memory_test.go similarity index 78% rename from pkg/cache/strategy/memory/memory_test.go rename to pkg/cache/provider/memory/memory_test.go index d8434e6b2e..74e622ce5e 100644 --- a/pkg/cache/strategy/memory/memory_test.go +++ b/pkg/cache/provider/memory/memory_test.go @@ -7,18 +7,21 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" _cache "go.signoz.io/signoz/pkg/cache" + "go.signoz.io/signoz/pkg/factory" ) // TestNew tests the New function func TestNew(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) + require.NoError(t, err) assert.NotNil(t, c) - assert.NotNil(t, c.cc) + assert.NotNil(t, c.(*memory).cc) assert.NoError(t, c.Connect(context.Background())) } @@ -53,32 +56,35 @@ func (dce DCacheableEntity) UnmarshalBinary(data []byte) error { // TestStore tests the Store function // this should fail because of nil pointer error func TestStoreWithNilPointer(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) + require.NoError(t, err) var storeCacheableEntity *CacheableEntity assert.Error(t, c.Store(context.Background(), "key", storeCacheableEntity, 10*time.Second)) } // this should fail because of no pointer error func TestStoreWithStruct(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) + require.NoError(t, err) var storeCacheableEntity CacheableEntity assert.Error(t, c.Store(context.Background(), "key", storeCacheableEntity, 10*time.Second)) } func TestStoreWithNonNilPointer(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) + require.NoError(t, err) storeCacheableEntity := &CacheableEntity{ Key: "some-random-key", Value: 1, @@ -89,11 +95,12 @@ func TestStoreWithNonNilPointer(t *testing.T) { // TestRetrieve tests the Retrieve function func TestRetrieveWithNilPointer(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) + require.NoError(t, err) storeCacheableEntity := &CacheableEntity{ Key: "some-random-key", Value: 1, @@ -109,11 +116,12 @@ func TestRetrieveWithNilPointer(t *testing.T) { } func TestRetrieveWitNonPointer(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) + require.NoError(t, err) storeCacheableEntity := &CacheableEntity{ Key: "some-random-key", Value: 1, @@ -129,11 +137,12 @@ func TestRetrieveWitNonPointer(t *testing.T) { } func TestRetrieveWithDifferentTypes(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) + require.NoError(t, err) storeCacheableEntity := &CacheableEntity{ Key: "some-random-key", Value: 1, @@ -148,11 +157,8 @@ func TestRetrieveWithDifferentTypes(t *testing.T) { } func TestRetrieveWithSameTypes(t *testing.T) { - opts := &_cache.Memory{ - TTL: 10 * time.Second, - CleanupInterval: 10 * time.Second, - } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: _cache.Memory{TTL: 10 * time.Second, CleanupInterval: 10 * time.Second}}) + require.NoError(t, err) storeCacheableEntity := &CacheableEntity{ Key: "some-random-key", Value: 1, @@ -169,7 +175,8 @@ func TestRetrieveWithSameTypes(t *testing.T) { // TestSetTTL tests the SetTTL function func TestSetTTL(t *testing.T) { - c := New(&_cache.Memory{TTL: 10 * time.Second, CleanupInterval: 1 * time.Second}) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: _cache.Memory{TTL: 10 * time.Second, CleanupInterval: 1 * time.Second}}) + require.NoError(t, err) storeCacheableEntity := &CacheableEntity{ Key: "some-random-key", Value: 1, @@ -194,11 +201,11 @@ func TestSetTTL(t *testing.T) { // TestRemove tests the Remove function func TestRemove(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) storeCacheableEntity := &CacheableEntity{ Key: "some-random-key", Value: 1, @@ -216,11 +223,12 @@ func TestRemove(t *testing.T) { // TestBulkRemove tests the BulkRemove function func TestBulkRemove(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) + require.NoError(t, err) storeCacheableEntity := &CacheableEntity{ Key: "some-random-key", Value: 1, @@ -244,11 +252,12 @@ func TestBulkRemove(t *testing.T) { // TestCache tests the cache func TestCache(t *testing.T) { - opts := &_cache.Memory{ + opts := _cache.Memory{ TTL: 10 * time.Second, CleanupInterval: 10 * time.Second, } - c := New(opts) + c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: opts}) + require.NoError(t, err) storeCacheableEntity := &CacheableEntity{ Key: "some-random-key", Value: 1, diff --git a/pkg/cache/strategy/redis/redis.go b/pkg/cache/provider/redis/redis.go similarity index 90% rename from pkg/cache/strategy/redis/redis.go rename to pkg/cache/provider/redis/redis.go index 0309072656..02fa737129 100644 --- a/pkg/cache/strategy/redis/redis.go +++ b/pkg/cache/provider/redis/redis.go @@ -8,16 +8,21 @@ import ( "github.com/go-redis/redis/v8" _cache "go.signoz.io/signoz/pkg/cache" + "go.signoz.io/signoz/pkg/factory" "go.uber.org/zap" ) type cache struct { client *redis.Client - opts *_cache.Redis + opts _cache.Redis } -func New(opts *_cache.Redis) *cache { - return &cache{opts: opts} +func NewFactory() factory.ProviderFactory[_cache.Cache, _cache.Config] { + return factory.NewProviderFactory(factory.MustNewName("redis"), New) +} + +func New(ctx context.Context, settings factory.ProviderSettings, config _cache.Config) (_cache.Cache, error) { + return &cache{opts: config.Redis}, nil } // WithClient creates a new cache with the given client @@ -87,11 +92,6 @@ func (c *cache) GetClient() *redis.Client { return c.client } -// GetOptions returns the options -func (c *cache) GetOptions() *_cache.Redis { - return c.opts -} - // GetTTL returns the TTL for the cache entry func (c *cache) GetTTL(ctx context.Context, cacheKey string) time.Duration { ttl, err := c.client.TTL(ctx, cacheKey).Result() diff --git a/pkg/cache/strategy/redis/redis_test.go b/pkg/cache/provider/redis/redis_test.go similarity index 100% rename from pkg/cache/strategy/redis/redis_test.go rename to pkg/cache/provider/redis/redis_test.go diff --git a/pkg/cache/strategy/memory/memory.go b/pkg/cache/strategy/memory/memory.go deleted file mode 100644 index 5649eecf54..0000000000 --- a/pkg/cache/strategy/memory/memory.go +++ /dev/null @@ -1,96 +0,0 @@ -package memory - -import ( - "context" - "fmt" - "reflect" - "time" - - go_cache "github.com/patrickmn/go-cache" - _cache "go.signoz.io/signoz/pkg/cache" -) - -type cache struct { - cc *go_cache.Cache -} - -func New(opts *_cache.Memory) *cache { - return &cache{cc: go_cache.New(opts.TTL, opts.CleanupInterval)} -} - -// Connect does nothing -func (c *cache) Connect(_ context.Context) error { - return nil -} - -// Store stores the data in the cache -func (c *cache) Store(_ context.Context, cacheKey string, data _cache.CacheableEntity, ttl time.Duration) error { - // check if the data being passed is a pointer and is not nil - rv := reflect.ValueOf(data) - if rv.Kind() != reflect.Pointer || rv.IsNil() { - return _cache.WrapCacheableEntityErrors(reflect.TypeOf(data), "inmemory") - } - - c.cc.Set(cacheKey, data, ttl) - return nil -} - -// Retrieve retrieves the data from the cache -func (c *cache) Retrieve(_ context.Context, cacheKey string, dest _cache.CacheableEntity, allowExpired bool) (_cache.RetrieveStatus, error) { - // check if the destination being passed is a pointer and is not nil - dstv := reflect.ValueOf(dest) - if dstv.Kind() != reflect.Pointer || dstv.IsNil() { - return _cache.RetrieveStatusError, _cache.WrapCacheableEntityErrors(reflect.TypeOf(dest), "inmemory") - } - - // check if the destination value is settable - if !dstv.Elem().CanSet() { - return _cache.RetrieveStatusError, fmt.Errorf("destination value is not settable, %s", dstv.Elem()) - } - - data, found := c.cc.Get(cacheKey) - if !found { - return _cache.RetrieveStatusKeyMiss, nil - } - - // check the type compatbility between the src and dest - srcv := reflect.ValueOf(data) - if !srcv.Type().AssignableTo(dstv.Type()) { - return _cache.RetrieveStatusError, fmt.Errorf("src type is not assignable to dst type") - } - - // set the value to from src to dest - dstv.Elem().Set(srcv.Elem()) - return _cache.RetrieveStatusHit, nil -} - -// SetTTL sets the TTL for the cache entry -func (c *cache) SetTTL(_ context.Context, cacheKey string, ttl time.Duration) { - item, found := c.cc.Get(cacheKey) - if !found { - return - } - c.cc.Replace(cacheKey, item, ttl) -} - -// Remove removes the cache entry -func (c *cache) Remove(_ context.Context, cacheKey string) { - c.cc.Delete(cacheKey) -} - -// BulkRemove removes the cache entries -func (c *cache) BulkRemove(_ context.Context, cacheKeys []string) { - for _, cacheKey := range cacheKeys { - c.cc.Delete(cacheKey) - } -} - -// Close does nothing -func (c *cache) Close(_ context.Context) error { - return nil -} - -// Configuration returns the cache configuration -func (c *cache) Configuration() *_cache.Memory { - return nil -} diff --git a/pkg/config/conf.go b/pkg/config/conf.go index 425aa36361..2a66af3418 100644 --- a/pkg/config/conf.go +++ b/pkg/config/conf.go @@ -30,13 +30,6 @@ func (conf *Conf) MergeAt(input *Conf, path string) error { return conf.Koanf.MergeAt(input.Koanf, path) } -// func (conf *Conf) Unmarshal(input any) error { - -// return conf.Koanf.UnmarshalWithConf("", input, koanf.UnmarshalConf{ -// Tag: "mapstructure", -// }) -// } - func (conf *Conf) Unmarshal(path string, input any) error { dc := &mapstructure.DecoderConfig{ TagName: "mapstructure", diff --git a/pkg/config/config.go b/pkg/config/config.go index 87304635a5..1261816ba3 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1,39 +1,12 @@ package config -import "context" +import ( + "context" -// NewConfigFunc is a function that creates a new config. -type NewConfigFunc = func() Config + "go.signoz.io/signoz/pkg/factory" +) -// ConfigFactory is a factory that creates a new config. -type ConfigFactory interface { - New() Config -} - -// NewProviderFactory creates a new provider factory. -func NewConfigFactory(f NewConfigFunc) ConfigFactory { - return &configFactory{f: f} -} - -// configFactory is a factory that implements the ConfigFactory interface. -type configFactory struct { - f NewConfigFunc -} - -// New creates a new provider. -func (factory *configFactory) New() Config { - return factory.f() -} - -// Config is an interface that defines methods for creating and validating configurations. -type Config interface { - // Key returns the name of the root key of the config. - Key() string - // Validate the configuration and returns an error if invalid. - Validate() error -} - -func New(ctx context.Context, resolverConfig ResolverConfig, configFactories []ConfigFactory) (*Conf, error) { +func New(ctx context.Context, resolverConfig ResolverConfig, configFactories []factory.ConfigFactory) (*Conf, error) { // Get the config from the resolver resolver, err := NewResolver(resolverConfig) if err != nil { @@ -49,7 +22,7 @@ func New(ctx context.Context, resolverConfig ResolverConfig, configFactories []C // Set the default configs for _, factory := range configFactories { c := factory.New() - if err := conf.Set(c.Key(), c); err != nil { + if err := conf.Set(factory.Name().String(), c); err != nil { return nil, err } } diff --git a/pkg/factory/config.go b/pkg/factory/config.go new file mode 100644 index 0000000000..e84bc033c0 --- /dev/null +++ b/pkg/factory/config.go @@ -0,0 +1,37 @@ +package factory + +// Config is an interface that defines methods for creating and validating configurations. +type Config interface { + // Validate the configuration and returns an error if invalid. + Validate() error +} + +// NewConfigFunc is a function that creates a new config. +type NewConfigFunc func() Config + +// ConfigFactory is a factory that creates a new config. +type ConfigFactory interface { + Named + New() Config +} + +// configFactory is a factory that implements the ConfigFactory interface. +type configFactory struct { + name Name + newConfigFunc NewConfigFunc +} + +// New creates a new config. +func (factory *configFactory) Name() Name { + return factory.name +} + +// New creates a new config. +func (factory *configFactory) New() Config { + return factory.newConfigFunc() +} + +// Creates a new config factory. +func NewConfigFactory(name Name, f NewConfigFunc) ConfigFactory { + return &configFactory{name: name, newConfigFunc: f} +} diff --git a/pkg/factory/name.go b/pkg/factory/name.go new file mode 100644 index 0000000000..9646fe2c5c --- /dev/null +++ b/pkg/factory/name.go @@ -0,0 +1,38 @@ +package factory + +import ( + "fmt" + "regexp" +) + +var ( + // nameRegex is a regex that matches a valid name. + // It must start with a alphabet, and can only contain alphabets, numbers, underscores or hyphens. + nameRegex = regexp.MustCompile(`^[a-z][a-z0-9_-]{0,30}$`) +) + +type Name struct { + name string +} + +func (n Name) String() string { + return n.name +} + +// NewName creates a new name. +func NewName(name string) (Name, error) { + if !nameRegex.MatchString(name) { + return Name{}, fmt.Errorf("invalid factory name %q", name) + } + return Name{name: name}, nil +} + +// MustNewName creates a new name. +// It panics if the name is invalid. +func MustNewName(name string) Name { + n, err := NewName(name) + if err != nil { + panic(err) + } + return n +} diff --git a/pkg/factory/named.go b/pkg/factory/named.go new file mode 100644 index 0000000000..7bebf4c5fa --- /dev/null +++ b/pkg/factory/named.go @@ -0,0 +1,64 @@ +package factory + +import "fmt" + +// Named is implemented by all types of factories. +type Named interface { + Name() Name +} + +type NamedMap[T Named] struct { + factories map[Name]T + factoriesInOrder []T +} + +func NewNamedMap[T Named](factories ...T) (NamedMap[T], error) { + fmap := make(map[Name]T) + for _, factory := range factories { + if _, ok := fmap[factory.Name()]; ok { + return NamedMap[T]{}, fmt.Errorf("cannot build factory map, duplicate name %q found", factory.Name()) + } + + fmap[factory.Name()] = factory + } + + return NamedMap[T]{factories: fmap, factoriesInOrder: factories}, nil +} + +func MustNewNamedMap[T Named](factories ...T) NamedMap[T] { + nm, err := NewNamedMap(factories...) + if err != nil { + panic(err) + } + return nm +} + +func (n NamedMap[T]) Get(namestr string) (t T, err error) { + name, err := NewName(namestr) + if err != nil { + return + } + + factory, ok := n.factories[name] + if !ok { + err = fmt.Errorf("factory %q not found or not registered", name) + return + } + + t = factory + return +} + +func (n NamedMap[T]) Add(factory T) (err error) { + name := factory.Name() + if _, ok := n.factories[name]; ok { + return fmt.Errorf("factory %q already exists", name) + } + + n.factories[name] = factory + return nil +} + +func (n NamedMap[T]) GetInOrder() []T { + return n.factoriesInOrder +} diff --git a/pkg/factory/provider.go b/pkg/factory/provider.go new file mode 100644 index 0000000000..e035fb5459 --- /dev/null +++ b/pkg/factory/provider.go @@ -0,0 +1,48 @@ +package factory + +import "context" + +type Provider = any + +// NewProviderFunc is a function that creates a new Provider. +type NewProviderFunc[P Provider, C Config] func(context.Context, ProviderSettings, C) (P, error) + +type ProviderFactory[P Provider, C Config] interface { + Named + New(context.Context, ProviderSettings, C) (P, error) +} + +type providerFactory[P Provider, C Config] struct { + name Name + newProviderFunc NewProviderFunc[P, C] +} + +func (factory *providerFactory[P, C]) Name() Name { + return factory.name +} + +func (factory *providerFactory[P, C]) New(ctx context.Context, settings ProviderSettings, config C) (P, error) { + return factory.newProviderFunc(ctx, settings, config) +} + +func NewProviderFactory[P Provider, C Config](name Name, newProviderFunc NewProviderFunc[P, C]) ProviderFactory[P, C] { + return &providerFactory[P, C]{ + name: name, + newProviderFunc: newProviderFunc, + } +} + +func NewFromFactory[P Provider, C Config](ctx context.Context, settings ProviderSettings, config C, factories NamedMap[ProviderFactory[P, C]], key string) (p P, err error) { + providerFactory, err := factories.Get(key) + if err != nil { + return + } + + provider, err := providerFactory.New(ctx, settings, config) + if err != nil { + return + } + + p = provider + return +} diff --git a/pkg/factory/setting.go b/pkg/factory/setting.go new file mode 100644 index 0000000000..dff67c99d1 --- /dev/null +++ b/pkg/factory/setting.go @@ -0,0 +1,19 @@ +package factory + +import ( + sdklog "go.opentelemetry.io/otel/log" + sdkmetric "go.opentelemetry.io/otel/metric" + sdktrace "go.opentelemetry.io/otel/trace" + "go.uber.org/zap" +) + +type ProviderSettings struct { + // LoggerProvider is the otel logger. + LoggerProvider sdklog.LoggerProvider + // ZapLogger is the zap logger. + ZapLogger *zap.Logger + // MeterProvider is the meter provider. + MeterProvider sdkmetric.MeterProvider + // TracerProvider is the tracer provider. + TracerProvider sdktrace.TracerProvider +} diff --git a/pkg/instrumentation/instrumentation.go b/pkg/instrumentation/instrumentation.go index 3f12fc9d63..ecf1395f00 100644 --- a/pkg/instrumentation/instrumentation.go +++ b/pkg/instrumentation/instrumentation.go @@ -14,17 +14,24 @@ import ( "go.uber.org/zap" ) +type Instrumentation interface { + LoggerProvider() sdklog.LoggerProvider + Logger() *zap.Logger + MeterProvider() sdkmetric.MeterProvider + TracerProvider() sdktrace.TracerProvider +} + // Instrumentation holds the core components for application instrumentation. -type Instrumentation struct { - LoggerProvider sdklog.LoggerProvider - Logger *zap.Logger - MeterProvider sdkmetric.MeterProvider - TracerProvider sdktrace.TracerProvider +type instrumentation struct { + loggerProvider sdklog.LoggerProvider + logger *zap.Logger + meterProvider sdkmetric.MeterProvider + tracerProvider sdktrace.TracerProvider } // New creates a new Instrumentation instance with configured providers. // It sets up logging, tracing, and metrics based on the provided configuration. -func New(ctx context.Context, build version.Build, cfg Config) (*Instrumentation, error) { +func New(ctx context.Context, build version.Build, cfg Config) (Instrumentation, error) { // Set default resource attributes if not provided if cfg.Resource.Attributes == nil { cfg.Resource.Attributes = map[string]any{ @@ -70,14 +77,30 @@ func New(ctx context.Context, build version.Build, cfg Config) (*Instrumentation return nil, fmt.Errorf("cannot create meter provider: %w", err) } - return &Instrumentation{ - LoggerProvider: loggerProvider, - TracerProvider: tracerProvider, - MeterProvider: meterProvider, - Logger: newLogger(cfg, loggerProvider), + return &instrumentation{ + loggerProvider: loggerProvider, + tracerProvider: tracerProvider, + meterProvider: meterProvider, + logger: newLogger(cfg, loggerProvider), }, nil } +func (i *instrumentation) LoggerProvider() sdklog.LoggerProvider { + return i.loggerProvider +} + +func (i *instrumentation) Logger() *zap.Logger { + return i.logger +} + +func (i *instrumentation) MeterProvider() sdkmetric.MeterProvider { + return i.meterProvider +} + +func (i *instrumentation) TracerProvider() sdktrace.TracerProvider { + return i.tracerProvider +} + // attributes merges the input attributes with the resource attributes. func attributes(input map[string]any, resource *sdkresource.Resource) map[string]any { output := make(map[string]any) diff --git a/pkg/query-service/app/server.go b/pkg/query-service/app/server.go index 7ff7a6bd7b..6ef79f5fb3 100644 --- a/pkg/query-service/app/server.go +++ b/pkg/query-service/app/server.go @@ -98,12 +98,12 @@ func (s Server) HealthCheckStatus() chan healthcheck.Status { // NewServer creates and initializes Server func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signoz.SigNoz) (*Server, error) { - if err := dao.InitDao(signoz.SqlStore.Provider().SqlxDB()); err != nil { + if err := dao.InitDao(signoz.SQLStore.SQLxDB()); err != nil { return nil, err } - preferences.InitDB(signoz.SqlStore.Provider().SqlxDB()) - dashboards.InitDB(signoz.SqlStore.Provider().SqlxDB()) - explorer.InitWithDB(signoz.SqlStore.Provider().SqlxDB()) + preferences.InitDB(signoz.SQLStore.SQLxDB()) + dashboards.InitDB(signoz.SQLStore.SQLxDB()) + explorer.InitWithDB(signoz.SQLStore.SQLxDB()) // initiate feature manager fm := featureManager.StartManager() @@ -115,7 +115,7 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo if storage == "clickhouse" { zap.L().Info("Using ClickHouse as datastore ...") clickhouseReader := clickhouseReader.NewReader( - signoz.SqlStore.Provider().SqlxDB(), + signoz.SQLStore.SQLxDB(), serverOptions.PromConfigPath, fm, serverOptions.MaxIdleConns, @@ -153,7 +153,7 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo rm, err := makeRulesManager( serverOptions.PromConfigPath, constants.GetAlertManagerApiPrefix(), - serverOptions.RuleRepoURL, signoz.SqlStore.Provider().SqlxDB(), reader, c, serverOptions.DisableRules, fm, serverOptions.UseLogsNewSchema, serverOptions.UseTraceNewSchema) + serverOptions.RuleRepoURL, signoz.SQLStore.SQLxDB(), reader, c, serverOptions.DisableRules, fm, serverOptions.UseLogsNewSchema, serverOptions.UseTraceNewSchema) if err != nil { return nil, err } @@ -170,18 +170,18 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo return nil, err } - integrationsController, err := integrations.NewController(signoz.SqlStore.Provider().SqlxDB()) + integrationsController, err := integrations.NewController(signoz.SQLStore.SQLxDB()) if err != nil { return nil, fmt.Errorf("couldn't create integrations controller: %w", err) } - cloudIntegrationsController, err := cloudintegrations.NewController(signoz.SqlStore.Provider().SqlxDB()) + cloudIntegrationsController, err := cloudintegrations.NewController(signoz.SQLStore.SQLxDB()) if err != nil { return nil, fmt.Errorf("couldn't create cloud provider integrations controller: %w", err) } logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController( - signoz.SqlStore.Provider().SqlxDB(), integrationsController.GetPipelinesForInstalledIntegrations, + signoz.SQLStore.SQLxDB(), integrationsController.GetPipelinesForInstalledIntegrations, ) if err != nil { return nil, err @@ -233,10 +233,10 @@ func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signo s.privateHTTP = privateServer - opAmpModel.InitDB(signoz.SqlStore.Provider().SqlxDB()) + opAmpModel.InitDB(signoz.SQLStore.SQLxDB()) agentConfMgr, err := agentConf.Initiate(&agentConf.ManagerOptions{ - DB: signoz.SqlStore.Provider().SqlxDB(), + DB: signoz.SQLStore.SQLxDB(), AgentFeatures: []agentConf.AgentFeature{ logParsingPipelineController, }, diff --git a/pkg/query-service/main.go b/pkg/query-service/main.go index 1737b9c10e..71fccdb1e9 100644 --- a/pkg/query-service/main.go +++ b/pkg/query-service/main.go @@ -11,11 +11,13 @@ import ( prommodel "github.com/prometheus/common/model" "go.signoz.io/signoz/pkg/config" "go.signoz.io/signoz/pkg/config/provider/envprovider" + "go.signoz.io/signoz/pkg/instrumentation" "go.signoz.io/signoz/pkg/query-service/app" "go.signoz.io/signoz/pkg/query-service/auth" "go.signoz.io/signoz/pkg/query-service/constants" "go.signoz.io/signoz/pkg/query-service/version" "go.signoz.io/signoz/pkg/signoz" + pkgversion "go.signoz.io/signoz/pkg/version" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -86,7 +88,23 @@ func main() { zap.L().Fatal("Failed to create config", zap.Error(err)) } - signoz, err := signoz.New(config) + instrumentation, err := instrumentation.New(context.Background(), pkgversion.Build{}, instrumentation.Config{ + Logs: instrumentation.LogsConfig{ + Enabled: false, + Level: zapcore.InfoLevel, + }, + Traces: instrumentation.TracesConfig{ + Enabled: false, + }, + Metrics: instrumentation.MetricsConfig{ + Enabled: false, + }, + }) + if err != nil { + zap.L().Fatal("Failed to create instrumentation", zap.Error(err)) + } + + signoz, err := signoz.New(context.Background(), instrumentation, config, signoz.NewProviderFactories()) if err != nil { zap.L().Fatal("Failed to create signoz struct", zap.Error(err)) } diff --git a/pkg/query-service/utils/testutils.go b/pkg/query-service/utils/testutils.go index fc5fadc297..2d9e26e585 100644 --- a/pkg/query-service/utils/testutils.go +++ b/pkg/query-service/utils/testutils.go @@ -7,12 +7,12 @@ import ( "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/query-service/app/dashboards" "go.signoz.io/signoz/pkg/query-service/dao" "go.signoz.io/signoz/pkg/sqlstore" "go.signoz.io/signoz/pkg/sqlstore/migrations" - sqlstoreprovider "go.signoz.io/signoz/pkg/sqlstore/provider" - "go.uber.org/zap" + "go.signoz.io/signoz/pkg/sqlstore/provider/sqlite" ) func NewQueryServiceDBForTests(t *testing.T) (testDB *sqlx.DB) { @@ -24,33 +24,47 @@ func NewQueryServiceDBForTests(t *testing.T) (testDB *sqlx.DB) { t.Cleanup(func() { os.Remove(testDBFilePath) }) testDBFile.Close() - sqlStoreProvider, err := sqlstoreprovider.New(sqlstore.Config{ + sqlStoreProvider, err := factory.NewFromFactory(context.Background(), factory.ProviderSettings{}, sqlstore.Config{ Provider: "sqlite", Sqlite: sqlstore.SqliteConfig{ Path: testDBFilePath, }, - }, sqlstore.ProviderConfig{Logger: zap.NewNop()}) + }, factory.MustNewNamedMap(sqlite.NewFactory()), "sqlite") if err != nil { t.Fatalf("could not create sqlite provider: %v", err) } - migrations, err := migrations.New(sqlstore.MigrationConfig{Logger: zap.L()}) + migrations, err := migrations.New(context.Background(), factory.ProviderSettings{}, sqlstore.Config{ + Provider: "sqlite", + Sqlite: sqlstore.SqliteConfig{ + Path: testDBFilePath, + }, + }, factory.MustNewNamedMap( + migrations.NewAddDataMigrationsFactory(), + migrations.NewAddOrganizationFactory(), + migrations.NewAddPreferencesFactory(), + migrations.NewAddDashboardsFactory(), + migrations.NewAddSavedViewsFactory(), + migrations.NewAddAgentsFactory(), + migrations.NewAddPipelinesFactory(), + migrations.NewAddIntegrationsFactory(), + )) if err != nil { t.Fatalf("could not create migrations: %v", err) } - sqlStore := sqlstore.NewSqlStore(sqlStoreProvider, migrations) + sqlStore := sqlstore.NewSQLStore(sqlStoreProvider, migrations) err = sqlStore.Migrate(context.Background()) if err != nil { t.Fatalf("could not run migrations: %v", err) } - err = dao.InitDao(sqlStore.Provider().SqlxDB()) + err = dao.InitDao(sqlStore.SQLxDB()) if err != nil { t.Fatalf("could not init dao: %v", err) } - dashboards.InitDB(sqlStore.Provider().SqlxDB()) + dashboards.InitDB(sqlStore.SQLxDB()) - return sqlStore.Provider().SqlxDB() + return sqlStore.SQLxDB() } diff --git a/pkg/signoz/config.go b/pkg/signoz/config.go index aa0f144749..e11630382f 100644 --- a/pkg/signoz/config.go +++ b/pkg/signoz/config.go @@ -5,6 +5,8 @@ import ( "go.signoz.io/signoz/pkg/cache" "go.signoz.io/signoz/pkg/config" + "go.signoz.io/signoz/pkg/factory" + "go.signoz.io/signoz/pkg/instrumentation" "go.signoz.io/signoz/pkg/sqlstore" "go.signoz.io/signoz/pkg/web" ) @@ -13,14 +15,14 @@ import ( type Config struct { Web web.Config `mapstructure:"web"` Cache cache.Config `mapstructure:"cache"` - SqlStore sqlstore.Config `mapstructure:"sqlstore"` + SQLStore sqlstore.Config `mapstructure:"sqlstore"` } func NewConfig(ctx context.Context, resolverConfig config.ResolverConfig) (Config, error) { - configFactories := []config.ConfigFactory{ + configFactories := []factory.ConfigFactory{ web.NewConfigFactory(), - cache.NewConfigFactory(), sqlstore.NewConfigFactory(), + cache.NewConfigFactory(), } conf, err := config.New(ctx, resolverConfig, configFactories) @@ -35,3 +37,12 @@ func NewConfig(ctx context.Context, resolverConfig config.ResolverConfig) (Confi return config, nil } + +func NewProviderSettings(instrumentation instrumentation.Instrumentation) factory.ProviderSettings { + return factory.ProviderSettings{ + LoggerProvider: instrumentation.LoggerProvider(), + ZapLogger: instrumentation.Logger(), + MeterProvider: instrumentation.MeterProvider(), + TracerProvider: instrumentation.TracerProvider(), + } +} diff --git a/pkg/signoz/provider.go b/pkg/signoz/provider.go new file mode 100644 index 0000000000..cd9061f4c3 --- /dev/null +++ b/pkg/signoz/provider.go @@ -0,0 +1,47 @@ +package signoz + +import ( + "go.signoz.io/signoz/pkg/cache" + "go.signoz.io/signoz/pkg/cache/provider/memory" + "go.signoz.io/signoz/pkg/cache/provider/redis" + "go.signoz.io/signoz/pkg/factory" + "go.signoz.io/signoz/pkg/sqlstore" + "go.signoz.io/signoz/pkg/sqlstore/migrations" + "go.signoz.io/signoz/pkg/sqlstore/provider/sqlite" + "go.signoz.io/signoz/pkg/web" + "go.signoz.io/signoz/pkg/web/provider/noop" + "go.signoz.io/signoz/pkg/web/provider/router" +) + +type ProviderFactories struct { + SQLStoreMigrationFactories factory.NamedMap[factory.ProviderFactory[sqlstore.Migration, sqlstore.Config]] + SQLStoreProviderFactories factory.NamedMap[factory.ProviderFactory[sqlstore.Provider, sqlstore.Config]] + WebProviderFactories factory.NamedMap[factory.ProviderFactory[web.Web, web.Config]] + CacheProviderFactories factory.NamedMap[factory.ProviderFactory[cache.Cache, cache.Config]] +} + +func NewProviderFactories() ProviderFactories { + return ProviderFactories{ + SQLStoreMigrationFactories: factory.MustNewNamedMap( + migrations.NewAddDataMigrationsFactory(), + migrations.NewAddOrganizationFactory(), + migrations.NewAddPreferencesFactory(), + migrations.NewAddDashboardsFactory(), + migrations.NewAddSavedViewsFactory(), + migrations.NewAddAgentsFactory(), + migrations.NewAddPipelinesFactory(), + migrations.NewAddIntegrationsFactory(), + ), + SQLStoreProviderFactories: factory.MustNewNamedMap( + sqlite.NewFactory(), + ), + WebProviderFactories: factory.MustNewNamedMap( + router.NewFactory(), + noop.NewFactory(), + ), + CacheProviderFactories: factory.MustNewNamedMap( + memory.NewFactory(), + redis.NewFactory(), + ), + } +} diff --git a/pkg/signoz/signoz.go b/pkg/signoz/signoz.go index b4298bb0df..4061f53c75 100644 --- a/pkg/signoz/signoz.go +++ b/pkg/signoz/signoz.go @@ -4,58 +4,46 @@ import ( "context" "go.signoz.io/signoz/pkg/cache" - "go.signoz.io/signoz/pkg/cache/strategy/memory" - "go.signoz.io/signoz/pkg/cache/strategy/redis" + "go.signoz.io/signoz/pkg/factory" + "go.signoz.io/signoz/pkg/instrumentation" + "go.signoz.io/signoz/pkg/sqlstore" "go.signoz.io/signoz/pkg/sqlstore/migrations" - sqlstoreprovider "go.signoz.io/signoz/pkg/sqlstore/provider" "go.signoz.io/signoz/pkg/web" - "go.signoz.io/signoz/pkg/web/noop" - "go.signoz.io/signoz/pkg/web/router" - "go.uber.org/zap" ) type SigNoz struct { Cache cache.Cache Web web.Web - SqlStore sqlstore.SqlStore + SQLStore sqlstore.SQLStore } -func New(config Config) (*SigNoz, error) { - var cache cache.Cache - var web web.Web +func New(ctx context.Context, instrumentation instrumentation.Instrumentation, config Config, factories ProviderFactories) (*SigNoz, error) { + providerSettings := NewProviderSettings(instrumentation) - // init for the cache - switch config.Cache.Provider { - case "memory": - cache = memory.New(&config.Cache.Memory) - case "redis": - cache = redis.New(&config.Cache.Redis) + cache, err := factory.NewFromFactory(ctx, providerSettings, config.Cache, factories.CacheProviderFactories, config.Cache.Provider) + if err != nil { + return nil, err } - switch config.Web.Enabled { - case true: - _web, err := router.New(zap.L(), config.Web) - if err != nil { - return nil, err - } - web = _web - case false: - web = noop.New() + web, err := factory.NewFromFactory(ctx, providerSettings, config.Web, factories.WebProviderFactories, config.Web.GetProvider()) + if err != nil { + return nil, err } - sqlStoreProvider, err := sqlstoreprovider.New(config.SqlStore, sqlstore.ProviderConfig{Logger: zap.L()}) + sqlStoreProvider, err := factory.NewFromFactory(ctx, providerSettings, config.SQLStore, factories.SQLStoreProviderFactories, config.SQLStore.Provider) if err != nil { return nil, err } - migrations, err := migrations.New(sqlstore.MigrationConfig{Logger: zap.L()}) + migrations, err := migrations.New(ctx, providerSettings, config.SQLStore, factories.SQLStoreMigrationFactories) if err != nil { return nil, err } - sqlStore := sqlstore.NewSqlStore(sqlStoreProvider, migrations) - err = sqlStore.Migrate(context.Background()) + sqlStore := sqlstore.NewSQLStore(sqlStoreProvider, migrations) + + err = sqlStore.Migrate(ctx) if err != nil { return nil, err } @@ -63,6 +51,6 @@ func New(config Config) (*SigNoz, error) { return &SigNoz{ Cache: cache, Web: web, - SqlStore: sqlStore, + SQLStore: sqlStore, }, nil } diff --git a/pkg/sqlstore/config.go b/pkg/sqlstore/config.go index 126d02fed8..b42d430a82 100644 --- a/pkg/sqlstore/config.go +++ b/pkg/sqlstore/config.go @@ -1,9 +1,8 @@ package sqlstore -import "go.signoz.io/signoz/pkg/config" - -// Config satisfies the confmap.Config interface -var _ config.Config = (*Config)(nil) +import ( + "go.signoz.io/signoz/pkg/factory" +) type Config struct { Provider string `mapstructure:"provider"` @@ -28,11 +27,11 @@ type PostgresConfig struct { Database string `mapstructure:"database"` } -func NewConfigFactory() config.ConfigFactory { - return config.NewConfigFactory(newConfig) +func NewConfigFactory() factory.ConfigFactory { + return factory.NewConfigFactory(factory.MustNewName("sqlstore"), newConfig) } -func newConfig() config.Config { +func newConfig() factory.Config { return &Config{ Provider: "sqlite", Connection: ConnectionConfig{ @@ -45,10 +44,6 @@ func newConfig() config.Config { } -func (c *Config) Key() string { - return "sqlstore" -} - -func (c *Config) Validate() error { +func (c Config) Validate() error { return nil } diff --git a/pkg/sqlstore/migration.go b/pkg/sqlstore/migration.go deleted file mode 100644 index 5aa8dcbda1..0000000000 --- a/pkg/sqlstore/migration.go +++ /dev/null @@ -1,42 +0,0 @@ -package sqlstore - -import ( - "context" - - "github.com/uptrace/bun" - "github.com/uptrace/bun/migrate" - "go.uber.org/zap" -) - -type Migration interface { - Register(*migrate.Migrations) error - Up(context.Context, *bun.DB) error - Down(context.Context, *bun.DB) error -} - -type MigrationConfig struct { - Logger *zap.Logger -} - -// NewMigrationFunc is a function that creates a new migration. -type NewMigrationFunc = func(MigrationConfig) Migration - -// MigrationFactory is a factory that creates a new migration. -type MigrationFactory interface { - New(MigrationConfig) Migration -} - -// NewMigrationFactory creates a new migration factory. -func NewMigrationFactory(f NewMigrationFunc) MigrationFactory { - return &migrationFactory{f: f} -} - -// migrationFactory is a factory that implements the MigrationFactory interface. -type migrationFactory struct { - f NewMigrationFunc -} - -// New creates a new migration. -func (factory *migrationFactory) New(config MigrationConfig) Migration { - return factory.f(config) -} diff --git a/pkg/sqlstore/migrations/000_add_data_migrations.go b/pkg/sqlstore/migrations/000_add_data_migrations.go index 5ba5a30912..a673b0142e 100644 --- a/pkg/sqlstore/migrations/000_add_data_migrations.go +++ b/pkg/sqlstore/migrations/000_add_data_migrations.go @@ -5,19 +5,20 @@ import ( "github.com/uptrace/bun" "github.com/uptrace/bun/migrate" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" ) type addDataMigrations struct { - config sqlstore.MigrationConfig + settings factory.ProviderSettings } -func NewAddDataMigrationsMigrationFactory() sqlstore.MigrationFactory { - return sqlstore.NewMigrationFactory(newAddDataMigrations) +func NewAddDataMigrationsFactory() factory.ProviderFactory[sqlstore.Migration, sqlstore.Config] { + return factory.NewProviderFactory(factory.MustNewName("add_data_migrations"), newAddDataMigrations) } -func newAddDataMigrations(config sqlstore.MigrationConfig) sqlstore.Migration { - return &addDataMigrations{config: config} +func newAddDataMigrations(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.Migration, error) { + return &addDataMigrations{settings: settings}, nil } func (migration *addDataMigrations) Register(migrations *migrate.Migrations) error { diff --git a/pkg/sqlstore/migrations/001_add_organization.go b/pkg/sqlstore/migrations/001_add_organization.go index ce2578582b..a5e02fd5ce 100644 --- a/pkg/sqlstore/migrations/001_add_organization.go +++ b/pkg/sqlstore/migrations/001_add_organization.go @@ -5,19 +5,20 @@ import ( "github.com/uptrace/bun" "github.com/uptrace/bun/migrate" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" ) type addOrganization struct { - config sqlstore.MigrationConfig + settings factory.ProviderSettings } -func NewAddOrganizationMigrationFactory() sqlstore.MigrationFactory { - return sqlstore.NewMigrationFactory(newAddOrganization) +func NewAddOrganizationFactory() factory.ProviderFactory[sqlstore.Migration, sqlstore.Config] { + return factory.NewProviderFactory(factory.MustNewName("add_organization"), newAddOrganization) } -func newAddOrganization(config sqlstore.MigrationConfig) sqlstore.Migration { - return &addOrganization{config: config} +func newAddOrganization(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.Migration, error) { + return &addOrganization{settings: settings}, nil } func (migration *addOrganization) Register(migrations *migrate.Migrations) error { diff --git a/pkg/sqlstore/migrations/002_add_preferences.go b/pkg/sqlstore/migrations/002_add_preferences.go index 8493e0f0cf..40eec63975 100644 --- a/pkg/sqlstore/migrations/002_add_preferences.go +++ b/pkg/sqlstore/migrations/002_add_preferences.go @@ -5,19 +5,20 @@ import ( "github.com/uptrace/bun" "github.com/uptrace/bun/migrate" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" ) type addPreferences struct { - config sqlstore.MigrationConfig + settings factory.ProviderSettings } -func NewAddPreferencesMigrationFactory() sqlstore.MigrationFactory { - return sqlstore.NewMigrationFactory(newAddPreferences) +func NewAddPreferencesFactory() factory.ProviderFactory[sqlstore.Migration, sqlstore.Config] { + return factory.NewProviderFactory(factory.MustNewName("add_preferences"), newAddPreferences) } -func newAddPreferences(config sqlstore.MigrationConfig) sqlstore.Migration { - return &addPreferences{config: config} +func newAddPreferences(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.Migration, error) { + return &addPreferences{settings: settings}, nil } func (migration *addPreferences) Register(migrations *migrate.Migrations) error { diff --git a/pkg/sqlstore/migrations/003_add_dashboards.go b/pkg/sqlstore/migrations/003_add_dashboards.go index 94a7fb3ae7..d883be2f81 100644 --- a/pkg/sqlstore/migrations/003_add_dashboards.go +++ b/pkg/sqlstore/migrations/003_add_dashboards.go @@ -5,19 +5,20 @@ import ( "github.com/uptrace/bun" "github.com/uptrace/bun/migrate" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" ) type addDashboards struct { - config sqlstore.MigrationConfig + settings factory.ProviderSettings } -func NewAddDashboardsMigrationFactory() sqlstore.MigrationFactory { - return sqlstore.NewMigrationFactory(newAddDashboards) +func NewAddDashboardsFactory() factory.ProviderFactory[sqlstore.Migration, sqlstore.Config] { + return factory.NewProviderFactory(factory.MustNewName("add_dashboards"), newAddDashboards) } -func newAddDashboards(config sqlstore.MigrationConfig) sqlstore.Migration { - return &addDashboards{config: config} +func newAddDashboards(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.Migration, error) { + return &addDashboards{settings: settings}, nil } func (migration *addDashboards) Register(migrations *migrate.Migrations) error { diff --git a/pkg/sqlstore/migrations/004_add_saved_views.go b/pkg/sqlstore/migrations/004_add_saved_views.go index 12da27c258..f20bdac125 100644 --- a/pkg/sqlstore/migrations/004_add_saved_views.go +++ b/pkg/sqlstore/migrations/004_add_saved_views.go @@ -5,19 +5,20 @@ import ( "github.com/uptrace/bun" "github.com/uptrace/bun/migrate" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" ) type addSavedViews struct { - config sqlstore.MigrationConfig + settings factory.ProviderSettings } -func NewAddSavedViewsMigrationFactory() sqlstore.MigrationFactory { - return sqlstore.NewMigrationFactory(newAddSavedViews) +func NewAddSavedViewsFactory() factory.ProviderFactory[sqlstore.Migration, sqlstore.Config] { + return factory.NewProviderFactory(factory.MustNewName("add_saved_views"), newAddSavedViews) } -func newAddSavedViews(config sqlstore.MigrationConfig) sqlstore.Migration { - return &addSavedViews{config: config} +func newAddSavedViews(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.Migration, error) { + return &addSavedViews{settings: settings}, nil } func (migration *addSavedViews) Register(migrations *migrate.Migrations) error { diff --git a/pkg/sqlstore/migrations/005_add_agents.go b/pkg/sqlstore/migrations/005_add_agents.go index dc85455c54..f31cbd8958 100644 --- a/pkg/sqlstore/migrations/005_add_agents.go +++ b/pkg/sqlstore/migrations/005_add_agents.go @@ -5,19 +5,20 @@ import ( "github.com/uptrace/bun" "github.com/uptrace/bun/migrate" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" ) type addAgents struct { - config sqlstore.MigrationConfig + settings factory.ProviderSettings } -func NewAddAgentsMigrationFactory() sqlstore.MigrationFactory { - return sqlstore.NewMigrationFactory(newAddAgents) +func NewAddAgentsFactory() factory.ProviderFactory[sqlstore.Migration, sqlstore.Config] { + return factory.NewProviderFactory(factory.MustNewName("add_agents"), newAddAgents) } -func newAddAgents(config sqlstore.MigrationConfig) sqlstore.Migration { - return &addAgents{config: config} +func newAddAgents(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.Migration, error) { + return &addAgents{settings: settings}, nil } func (migration *addAgents) Register(migrations *migrate.Migrations) error { diff --git a/pkg/sqlstore/migrations/006_add_pipelines.go b/pkg/sqlstore/migrations/006_add_pipelines.go index b5f0064d70..cb056346f4 100644 --- a/pkg/sqlstore/migrations/006_add_pipelines.go +++ b/pkg/sqlstore/migrations/006_add_pipelines.go @@ -5,19 +5,20 @@ import ( "github.com/uptrace/bun" "github.com/uptrace/bun/migrate" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" ) type addPipelines struct { - config sqlstore.MigrationConfig + settings factory.ProviderSettings } -func NewAddPipelinesMigrationFactory() sqlstore.MigrationFactory { - return sqlstore.NewMigrationFactory(newAddPipelines) +func NewAddPipelinesFactory() factory.ProviderFactory[sqlstore.Migration, sqlstore.Config] { + return factory.NewProviderFactory(factory.MustNewName("add_pipelines"), newAddPipelines) } -func newAddPipelines(config sqlstore.MigrationConfig) sqlstore.Migration { - return &addPipelines{config: config} +func newAddPipelines(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.Migration, error) { + return &addPipelines{settings: settings}, nil } func (migration *addPipelines) Register(migrations *migrate.Migrations) error { diff --git a/pkg/sqlstore/migrations/007_add_integrations.go b/pkg/sqlstore/migrations/007_add_integrations.go index 8684cdfbf6..750815f2a4 100644 --- a/pkg/sqlstore/migrations/007_add_integrations.go +++ b/pkg/sqlstore/migrations/007_add_integrations.go @@ -5,19 +5,20 @@ import ( "github.com/uptrace/bun" "github.com/uptrace/bun/migrate" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" ) type addIntegrations struct { - config sqlstore.MigrationConfig + settings factory.ProviderSettings } -func NewAddIntegrationsMigrationFactory() sqlstore.MigrationFactory { - return sqlstore.NewMigrationFactory(newAddIntegrations) +func NewAddIntegrationsFactory() factory.ProviderFactory[sqlstore.Migration, sqlstore.Config] { + return factory.NewProviderFactory(factory.MustNewName("add_integrations"), newAddIntegrations) } -func newAddIntegrations(config sqlstore.MigrationConfig) sqlstore.Migration { - return &addIntegrations{config: config} +func newAddIntegrations(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.Migration, error) { + return &addIntegrations{settings: settings}, nil } func (migration *addIntegrations) Register(migrations *migrate.Migrations) error { diff --git a/pkg/sqlstore/migrations/migrations.go b/pkg/sqlstore/migrations/migrations.go index 479e90341c..afe8bfd0d1 100644 --- a/pkg/sqlstore/migrations/migrations.go +++ b/pkg/sqlstore/migrations/migrations.go @@ -8,6 +8,7 @@ import ( "github.com/uptrace/bun" "github.com/uptrace/bun/dialect" "github.com/uptrace/bun/migrate" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" ) @@ -15,24 +16,21 @@ var ( ErrNoExecute = errors.New("no execute") ) -func New(config sqlstore.MigrationConfig) (*migrate.Migrations, error) { +func New( + ctx context.Context, + settings factory.ProviderSettings, + config sqlstore.Config, + factories factory.NamedMap[factory.ProviderFactory[sqlstore.Migration, sqlstore.Config]], +) (*migrate.Migrations, error) { migrations := migrate.NewMigrations() - factories := []sqlstore.MigrationFactory{ - NewAddDataMigrationsMigrationFactory(), - NewAddOrganizationMigrationFactory(), - NewAddPreferencesMigrationFactory(), - NewAddDashboardsMigrationFactory(), - NewAddSavedViewsMigrationFactory(), - NewAddAgentsMigrationFactory(), - NewAddPipelinesMigrationFactory(), - NewAddIntegrationsMigrationFactory(), - } - - for _, factory := range factories { - migration := factory.New(config) + for _, factory := range factories.GetInOrder() { + migration, err := factory.New(ctx, settings, config) + if err != nil { + return nil, err + } - err := migration.Register(migrations) + err = migration.Register(migrations) if err != nil { return nil, err } diff --git a/pkg/sqlstore/provider/provider.go b/pkg/sqlstore/provider/provider.go deleted file mode 100644 index c152935b70..0000000000 --- a/pkg/sqlstore/provider/provider.go +++ /dev/null @@ -1,17 +0,0 @@ -package provider - -import ( - "fmt" - - "go.signoz.io/signoz/pkg/sqlstore" - "go.signoz.io/signoz/pkg/sqlstore/provider/sqlite" -) - -func New(config sqlstore.Config, providerConfig sqlstore.ProviderConfig) (sqlstore.Provider, error) { - switch config.Provider { - case "sqlite": - return sqlite.New(config, providerConfig) - } - - return nil, fmt.Errorf("provider %q not found", config.Provider) -} diff --git a/pkg/sqlstore/provider/sqlite/provider.go b/pkg/sqlstore/provider/sqlite/sqlite.go similarity index 65% rename from pkg/sqlstore/provider/sqlite/provider.go rename to pkg/sqlstore/provider/sqlite/sqlite.go index 28169e5e8d..6c7461138d 100644 --- a/pkg/sqlstore/provider/sqlite/provider.go +++ b/pkg/sqlstore/provider/sqlite/sqlite.go @@ -1,6 +1,7 @@ package sqlite import ( + "context" "database/sql" "fmt" @@ -8,6 +9,7 @@ import ( _ "github.com/mattn/go-sqlite3" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/sqlitedialect" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/sqlstore" "go.uber.org/zap" ) @@ -18,7 +20,11 @@ type provider struct { sqlxDB *sqlx.DB } -func New(config sqlstore.Config, providerConfig sqlstore.ProviderConfig) (sqlstore.Provider, error) { +func NewFactory() factory.ProviderFactory[sqlstore.Provider, sqlstore.Config] { + return factory.NewProviderFactory(factory.MustNewName("sqlite"), New) +} + +func New(ctx context.Context, settings factory.ProviderSettings, config sqlstore.Config) (sqlstore.Provider, error) { if config.Provider != "sqlite" { return nil, fmt.Errorf("provider %q is not supported by sqlite", config.Provider) } @@ -27,7 +33,8 @@ func New(config sqlstore.Config, providerConfig sqlstore.ProviderConfig) (sqlsto if err != nil { return nil, err } - providerConfig.Logger.Info("connected to sqlite", zap.String("path", config.Sqlite.Path)) + + settings.ZapLogger.Info("connected to sqlite", zap.String("path", config.Sqlite.Path)) // Set connection options sqlDB.SetMaxOpenConns(config.Connection.MaxOpenConns) @@ -47,10 +54,10 @@ func (e *provider) BunDB() *bun.DB { return e.bunDB } -func (e *provider) SqlDB() *sql.DB { +func (e *provider) SQLDB() *sql.DB { return e.sqlDB } -func (e *provider) SqlxDB() *sqlx.DB { +func (e *provider) SQLxDB() *sqlx.DB { return e.sqlxDB } diff --git a/pkg/sqlstore/sqlstore.go b/pkg/sqlstore/sqlstore.go index d5010a24ae..775484a201 100644 --- a/pkg/sqlstore/sqlstore.go +++ b/pkg/sqlstore/sqlstore.go @@ -8,23 +8,24 @@ import ( "github.com/jmoiron/sqlx" "github.com/uptrace/bun" "github.com/uptrace/bun/migrate" - "go.uber.org/zap" ) -type SqlStore interface { - Provider() Provider +type SQLStore interface { + Provider Migrate(context.Context) error Rollback(context.Context) error } -type ProviderConfig struct { - Logger *zap.Logger +type Migration interface { + Register(*migrate.Migrations) error + Up(context.Context, *bun.DB) error + Down(context.Context, *bun.DB) error } type Provider interface { - SqlDB() *sql.DB + SQLDB() *sql.DB BunDB() *bun.DB - SqlxDB() *sqlx.DB + SQLxDB() *sqlx.DB } type sqlStore struct { @@ -32,7 +33,7 @@ type sqlStore struct { migrator *migrate.Migrator } -func NewSqlStore(provider Provider, migrations *migrate.Migrations) *sqlStore { +func NewSQLStore(provider Provider, migrations *migrate.Migrations) SQLStore { migrator := migrate.NewMigrator( provider.BunDB(), migrations, @@ -92,6 +93,14 @@ func (sqlstore *sqlStore) Rollback(ctx context.Context) error { return nil } -func (sqlstore *sqlStore) Provider() Provider { - return sqlstore.provider +func (sqlstore *sqlStore) BunDB() *bun.DB { + return sqlstore.provider.BunDB() +} + +func (sqlstore *sqlStore) SQLDB() *sql.DB { + return sqlstore.provider.SQLDB() +} + +func (sqlstore *sqlStore) SQLxDB() *sqlx.DB { + return sqlstore.provider.SQLxDB() } diff --git a/pkg/web/config.go b/pkg/web/config.go index eca9bba39f..06b0c2364c 100644 --- a/pkg/web/config.go +++ b/pkg/web/config.go @@ -1,12 +1,9 @@ package web import ( - "go.signoz.io/signoz/pkg/config" + "go.signoz.io/signoz/pkg/factory" ) -// Config satisfies the confmap.Config interface -var _ config.Config = (*Config)(nil) - // Config holds the configuration for web. type Config struct { // Whether the web package is enabled. @@ -18,23 +15,26 @@ type Config struct { Directory string `mapstructure:"directory"` } -func NewConfigFactory() config.ConfigFactory { - return config.NewConfigFactory(newConfig) +func NewConfigFactory() factory.ConfigFactory { + return factory.NewConfigFactory(factory.MustNewName("web"), newConfig) } -func newConfig() config.Config { +func newConfig() factory.Config { return &Config{ Enabled: true, Prefix: "/", Directory: "/etc/signoz/web", } - } -func (c *Config) Key() string { - return "web" +func (c Config) Validate() error { + return nil } -func (c *Config) Validate() error { - return nil +func (c Config) GetProvider() string { + if c.Enabled { + return "router" + } + + return "noop" } diff --git a/pkg/web/config_test.go b/pkg/web/config_test.go index 463df55065..89caf0ab44 100644 --- a/pkg/web/config_test.go +++ b/pkg/web/config_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "go.signoz.io/signoz/pkg/config" "go.signoz.io/signoz/pkg/config/provider/envprovider" + "go.signoz.io/signoz/pkg/factory" ) func TestNewWithEnvProvider(t *testing.T) { @@ -22,7 +23,7 @@ func TestNewWithEnvProvider(t *testing.T) { envprovider.NewFactory(), }, }, - []config.ConfigFactory{ + []factory.ConfigFactory{ NewConfigFactory(), }, ) diff --git a/pkg/web/noop/noop.go b/pkg/web/noop/noop.go deleted file mode 100644 index ad58a2eac1..0000000000 --- a/pkg/web/noop/noop.go +++ /dev/null @@ -1,20 +0,0 @@ -package noop - -import ( - "net/http" - - "github.com/gorilla/mux" - "go.signoz.io/signoz/pkg/web" -) - -type noop struct{} - -func New() web.Web { - return &noop{} -} - -func (n *noop) AddToRouter(router *mux.Router) error { - return nil -} - -func (n *noop) ServeHTTP(w http.ResponseWriter, r *http.Request) {} diff --git a/pkg/web/provider/noop/noop.go b/pkg/web/provider/noop/noop.go new file mode 100644 index 0000000000..62470c89da --- /dev/null +++ b/pkg/web/provider/noop/noop.go @@ -0,0 +1,26 @@ +package noop + +import ( + "context" + "net/http" + + "github.com/gorilla/mux" + "go.signoz.io/signoz/pkg/factory" + "go.signoz.io/signoz/pkg/web" +) + +type noop struct{} + +func NewFactory() factory.ProviderFactory[web.Web, web.Config] { + return factory.NewProviderFactory(factory.MustNewName("noop"), New) +} + +func New(ctx context.Context, settings factory.ProviderSettings, config web.Config) (web.Web, error) { + return &noop{}, nil +} + +func (n *noop) AddToRouter(router *mux.Router) error { + return nil +} + +func (n *noop) ServeHTTP(w http.ResponseWriter, r *http.Request) {} diff --git a/pkg/web/router/router.go b/pkg/web/provider/router/router.go similarity index 70% rename from pkg/web/router/router.go rename to pkg/web/provider/router/router.go index f96e99777b..1ef7e41e5e 100644 --- a/pkg/web/router/router.go +++ b/pkg/web/provider/router/router.go @@ -1,6 +1,7 @@ package router import ( + "context" "fmt" "net/http" "os" @@ -8,9 +9,9 @@ import ( "time" "github.com/gorilla/mux" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/http/middleware" "go.signoz.io/signoz/pkg/web" - "go.uber.org/zap" ) var _ web.Web = (*router)(nil) @@ -20,16 +21,19 @@ const ( ) type router struct { - logger *zap.Logger - cfg web.Config + config web.Config } -func New(logger *zap.Logger, cfg web.Config) (web.Web, error) { - if logger == nil { +func NewFactory() factory.ProviderFactory[web.Web, web.Config] { + return factory.NewProviderFactory(factory.MustNewName("router"), New) +} + +func New(ctx context.Context, settings factory.ProviderSettings, config web.Config) (web.Web, error) { + if settings.ZapLogger == nil { return nil, fmt.Errorf("cannot build web, logger is required") } - fi, err := os.Stat(cfg.Directory) + fi, err := os.Stat(config.Directory) if err != nil { return nil, fmt.Errorf("cannot access web directory: %w", err) } @@ -39,7 +43,7 @@ func New(logger *zap.Logger, cfg web.Config) (web.Web, error) { return nil, fmt.Errorf("web directory is not a directory") } - fi, err = os.Stat(filepath.Join(cfg.Directory, indexFileName)) + fi, err = os.Stat(filepath.Join(config.Directory, indexFileName)) if err != nil { return nil, fmt.Errorf("cannot access %q in web directory: %w", indexFileName, err) } @@ -49,17 +53,16 @@ func New(logger *zap.Logger, cfg web.Config) (web.Web, error) { } return &router{ - logger: logger.Named("go.signoz.io/pkg/web"), - cfg: cfg, + config: config, }, nil } func (web *router) AddToRouter(router *mux.Router) error { cache := middleware.NewCache(7 * 24 * time.Hour) - err := router.PathPrefix(web.cfg.Prefix). + err := router.PathPrefix(web.config.Prefix). Handler( http.StripPrefix( - web.cfg.Prefix, + web.config.Prefix, cache.Wrap(http.HandlerFunc(web.ServeHTTP)), ), ).GetError() @@ -72,13 +75,13 @@ func (web *router) AddToRouter(router *mux.Router) error { func (web *router) ServeHTTP(rw http.ResponseWriter, req *http.Request) { // Join internally call path.Clean to prevent directory traversal - path := filepath.Join(web.cfg.Directory, req.URL.Path) + path := filepath.Join(web.config.Directory, req.URL.Path) // check whether a file exists or is a directory at the given path fi, err := os.Stat(path) if os.IsNotExist(err) || fi.IsDir() { // file does not exist or path is a directory, serve index.html - http.ServeFile(rw, req, filepath.Join(web.cfg.Directory, indexFileName)) + http.ServeFile(rw, req, filepath.Join(web.config.Directory, indexFileName)) return } @@ -91,5 +94,5 @@ func (web *router) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } // otherwise, use http.FileServer to serve the static file - http.FileServer(http.Dir(web.cfg.Directory)).ServeHTTP(rw, req) + http.FileServer(http.Dir(web.config.Directory)).ServeHTTP(rw, req) } diff --git a/pkg/web/router/router_test.go b/pkg/web/provider/router/router_test.go similarity index 89% rename from pkg/web/router/router_test.go rename to pkg/web/provider/router/router_test.go index d5259b0b3b..abb689aa69 100644 --- a/pkg/web/router/router_test.go +++ b/pkg/web/provider/router/router_test.go @@ -1,6 +1,7 @@ package router import ( + "context" "io" "net" "net/http" @@ -11,8 +12,8 @@ import ( "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.signoz.io/signoz/pkg/factory" "go.signoz.io/signoz/pkg/web" - "go.uber.org/zap" ) func TestServeHttpWithoutPrefix(t *testing.T) { @@ -23,7 +24,7 @@ func TestServeHttpWithoutPrefix(t *testing.T) { expected, err := io.ReadAll(fi) require.NoError(t, err) - web, err := New(zap.NewNop(), web.Config{Prefix: "/", Directory: filepath.Join("testdata")}) + web, err := New(context.Background(), factory.ProviderSettings{}, web.Config{Prefix: "/", Directory: filepath.Join("testdata")}) require.NoError(t, err) router := mux.NewRouter() @@ -88,7 +89,7 @@ func TestServeHttpWithPrefix(t *testing.T) { expected, err := io.ReadAll(fi) require.NoError(t, err) - web, err := New(zap.NewNop(), web.Config{Prefix: "/web", Directory: filepath.Join("testdata")}) + web, err := New(context.Background(), factory.ProviderSettings{}, web.Config{Prefix: "/web", Directory: filepath.Join("testdata")}) require.NoError(t, err) router := mux.NewRouter() diff --git a/pkg/web/router/testdata/index.html b/pkg/web/provider/router/testdata/index.html similarity index 100% rename from pkg/web/router/testdata/index.html rename to pkg/web/provider/router/testdata/index.html