Compare commits

..

3 Commits

Author SHA1 Message Date
grandwizard28
060edb8492 feat(.): initialize all factories 2025-01-17 21:04:37 +05:30
grandwizard28
43414275b5 fix(tests): fix provider tests for routerweb 2025-01-17 20:21:12 +05:30
grandwizard28
66a0830dc7 feat(config): have web and cache implement the new config 2025-01-17 20:12:06 +05:30
29 changed files with 360 additions and 193 deletions

View File

@@ -82,7 +82,6 @@ type ServerOptions struct {
GatewayUrl string
UseLogsNewSchema bool
UseTraceNewSchema bool
SkipWebFrontend bool
}
// Server runs HTTP api service
@@ -396,11 +395,9 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
handler = handlers.CompressHandler(handler)
if !s.serverOptions.SkipWebFrontend {
err := web.AddToRouter(r)
if err != nil {
return nil, err
}
err := web.AddToRouter(r)
if err != nil {
return nil, err
}
return &http.Server{

View File

@@ -10,17 +10,24 @@ import (
"syscall"
"time"
"go.opentelemetry.io/collector/confmap"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.signoz.io/signoz/ee/query-service/app"
signozconfig "go.signoz.io/signoz/pkg/config"
"go.signoz.io/signoz/pkg/confmap/provider/signozenvprovider"
"go.signoz.io/signoz/pkg/cache/memorycache"
"go.signoz.io/signoz/pkg/cache/rediscache"
"go.signoz.io/signoz/pkg/config"
"go.signoz.io/signoz/pkg/config/envprovider"
"go.signoz.io/signoz/pkg/config/fileprovider"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/query-service/auth"
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
"go.signoz.io/signoz/pkg/query-service/migrate"
"go.signoz.io/signoz/pkg/query-service/version"
"go.signoz.io/signoz/pkg/signoz"
"go.signoz.io/signoz/pkg/sqlmigration"
"go.signoz.io/signoz/pkg/sqlstore/sqlitesqlstore"
"go.signoz.io/signoz/pkg/web/noopweb"
"go.signoz.io/signoz/pkg/web/routerweb"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
@@ -108,7 +115,6 @@ func main() {
var dialTimeout time.Duration
var gatewayUrl string
var useLicensesV3 bool
var skipWebFrontend bool
flag.BoolVar(&useLogsNewSchema, "use-logs-new-schema", false, "use logs_v2 schema for logs")
flag.BoolVar(&useTraceNewSchema, "use-trace-new-schema", false, "use new schema for traces")
@@ -126,7 +132,6 @@ func main() {
flag.StringVar(&cluster, "cluster", "cluster", "(cluster name - defaults to 'cluster')")
flag.StringVar(&gatewayUrl, "gateway-url", "", "(url to the gateway)")
flag.BoolVar(&useLicensesV3, "use-licenses-v3", false, "use licenses_v3 schema for licenses")
flag.BoolVar(&skipWebFrontend, "skip-web-frontend", false, "skip web frontend")
flag.Parse()
loggerMgr := initZapLog(enableQueryServiceLogOTLPExport)
@@ -136,19 +141,40 @@ func main() {
version.PrintVersion()
config, err := signozconfig.New(context.Background(), signozconfig.ProviderSettings{
ResolverSettings: confmap.ResolverSettings{
URIs: []string{"signozenv:"},
ProviderFactories: []confmap.ProviderFactory{
signozenvprovider.NewFactory(),
},
config, err := signoz.NewConfig(context.Background(), config.ResolverConfig{
Uris: []string{"env:"},
ProviderFactories: []config.ProviderFactory{
envprovider.NewFactory(),
fileprovider.NewFactory(),
},
})
if err != nil {
zap.L().Fatal("Failed to create config", zap.Error(err))
}
signoz, err := signoz.New(config, skipWebFrontend)
signoz, err := signoz.New(context.Background(), config, signoz.ProviderConfig{
CacheProviderFactories: factory.MustNewNamedMap(
memorycache.NewFactory(),
rediscache.NewFactory(),
),
WebProviderFactories: factory.MustNewNamedMap(
routerweb.NewFactory(),
noopweb.NewFactory(),
),
SQLStoreProviderFactories: factory.MustNewNamedMap(
sqlitesqlstore.NewFactory(),
),
SQLMigrationProviderFactories: factory.MustNewNamedMap(
sqlmigration.NewAddDataMigrationsFactory(),
sqlmigration.NewAddOrganizationFactory(),
sqlmigration.NewAddPreferencesFactory(),
sqlmigration.NewAddDashboardsFactory(),
sqlmigration.NewAddSavedViewsFactory(),
sqlmigration.NewAddAgentsFactory(),
sqlmigration.NewAddPipelinesFactory(),
sqlmigration.NewAddIntegrationsFactory(),
),
})
if err != nil {
zap.L().Fatal("Failed to create signoz struct", zap.Error(err))
}
@@ -171,7 +197,6 @@ func main() {
GatewayUrl: gatewayUrl,
UseLogsNewSchema: useLogsNewSchema,
UseTraceNewSchema: useTraceNewSchema,
SkipWebFrontend: skipWebFrontend,
}
// Read the jwt secret key

14
pkg/cache/config.go vendored
View File

@@ -4,12 +4,9 @@ import (
"time"
go_cache "github.com/patrickmn/go-cache"
"go.signoz.io/signoz/pkg/confmap"
"go.signoz.io/signoz/pkg/factory"
)
// Config satisfies the confmap.Config interface
var _ confmap.Config = (*Config)(nil)
type Memory struct {
TTL time.Duration `mapstructure:"ttl"`
CleanupInterval time.Duration `mapstructure:"cleanupInterval"`
@@ -28,7 +25,11 @@ type Config struct {
Redis Redis `mapstructure:"redis"`
}
func (c *Config) NewWithDefaults() confmap.Config {
func NewConfigFactory() factory.ConfigFactory {
return factory.NewConfigFactory(factory.MustNewName("cache"), newConfig)
}
func newConfig() factory.Config {
return &Config{
Provider: "memory",
Memory: Memory{
@@ -42,8 +43,9 @@ func (c *Config) NewWithDefaults() confmap.Config {
DB: 0,
},
}
}
func (c *Config) Validate() error {
func (c Config) Validate() error {
return nil
}

View File

@@ -7,15 +7,20 @@ import (
"time"
go_cache "github.com/patrickmn/go-cache"
_cache "go.signoz.io/signoz/pkg/cache"
"go.signoz.io/signoz/pkg/cache"
"go.signoz.io/signoz/pkg/factory"
)
type provider struct {
cc *go_cache.Cache
}
func New(opts *_cache.Memory) *provider {
return &provider{cc: go_cache.New(opts.TTL, opts.CleanupInterval)}
func NewFactory() factory.ProviderFactory[cache.Cache, cache.Config] {
return factory.NewProviderFactory(factory.MustNewName("memorycache"), New)
}
func New(ctx context.Context, settings factory.ProviderSettings, config cache.Config) (cache.Cache, error) {
return &provider{cc: go_cache.New(config.Memory.TTL, config.Memory.CleanupInterval)}, nil
}
// Connect does nothing
@@ -24,11 +29,11 @@ func (c *provider) Connect(_ context.Context) error {
}
// Store stores the data in the cache
func (c *provider) Store(_ context.Context, cacheKey string, data _cache.CacheableEntity, ttl time.Duration) error {
func (c *provider) 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")
return cache.WrapCacheableEntityErrors(reflect.TypeOf(data), "inmemory")
}
c.cc.Set(cacheKey, data, ttl)
@@ -36,32 +41,32 @@ func (c *provider) Store(_ context.Context, cacheKey string, data _cache.Cacheab
}
// Retrieve retrieves the data from the cache
func (c *provider) Retrieve(_ context.Context, cacheKey string, dest _cache.CacheableEntity, allowExpired bool) (_cache.RetrieveStatus, error) {
func (c *provider) 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")
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())
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
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")
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
return cache.RetrieveStatusHit, nil
}
// SetTTL sets the TTL for the cache entry
@@ -91,6 +96,6 @@ func (c *provider) Close(_ context.Context) error {
}
// Configuration returns the cache configuration
func (c *provider) Configuration() *_cache.Memory {
func (c *provider) Configuration() *cache.Memory {
return nil
}

View File

@@ -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/providertest"
)
// 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(), providertest.NewSettings(), _cache.Config{Provider: "memory", Memory: opts})
require.NoError(t, err)
assert.NotNil(t, c)
assert.NotNil(t, c.cc)
assert.NotNil(t, c.(*provider).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(), providertest.NewSettings(), _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(), providertest.NewSettings(), _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(), providertest.NewSettings(), _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(), providertest.NewSettings(), _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(), providertest.NewSettings(), _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(), providertest.NewSettings(), _cache.Config{Provider: "memory", Memory: opts})
require.NoError(t, err)
storeCacheableEntity := &CacheableEntity{
Key: "some-random-key",
Value: 1,
@@ -148,11 +157,12 @@ func TestRetrieveWithDifferentTypes(t *testing.T) {
}
func TestRetrieveWithSameTypes(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(), providertest.NewSettings(), _cache.Config{Provider: "memory", Memory: opts})
require.NoError(t, err)
storeCacheableEntity := &CacheableEntity{
Key: "some-random-key",
Value: 1,
@@ -169,7 +179,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(), providertest.NewSettings(), _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 +205,12 @@ 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(), providertest.NewSettings(), _cache.Config{Provider: "memory", Memory: opts})
require.NoError(t, err)
storeCacheableEntity := &CacheableEntity{
Key: "some-random-key",
Value: 1,
@@ -216,11 +228,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(), providertest.NewSettings(), _cache.Config{Provider: "memory", Memory: opts})
require.NoError(t, err)
storeCacheableEntity := &CacheableEntity{
Key: "some-random-key",
Value: 1,
@@ -244,11 +257,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(), providertest.NewSettings(), _cache.Config{Provider: "memory", Memory: opts})
require.NoError(t, err)
storeCacheableEntity := &CacheableEntity{
Key: "some-random-key",
Value: 1,

View File

@@ -7,17 +7,22 @@ import (
"time"
"github.com/go-redis/redis/v8"
_cache "go.signoz.io/signoz/pkg/cache"
"go.signoz.io/signoz/pkg/cache"
"go.signoz.io/signoz/pkg/factory"
"go.uber.org/zap"
)
type provider struct {
client *redis.Client
opts *_cache.Redis
opts cache.Redis
}
func New(opts *_cache.Redis) *provider {
return &provider{opts: opts}
func NewFactory() factory.ProviderFactory[cache.Cache, cache.Config] {
return factory.NewProviderFactory(factory.MustNewName("rediscache"), New)
}
func New(ctx context.Context, settings factory.ProviderSettings, config cache.Config) (cache.Cache, error) {
return &provider{opts: config.Redis}, nil
}
// WithClient creates a new cache with the given client
@@ -36,20 +41,20 @@ func (c *provider) Connect(_ context.Context) error {
}
// Store stores the data in the cache
func (c *provider) Store(ctx context.Context, cacheKey string, data _cache.CacheableEntity, ttl time.Duration) error {
func (c *provider) Store(ctx context.Context, cacheKey string, data cache.CacheableEntity, ttl time.Duration) error {
return c.client.Set(ctx, cacheKey, data, ttl).Err()
}
// Retrieve retrieves the data from the cache
func (c *provider) Retrieve(ctx context.Context, cacheKey string, dest _cache.CacheableEntity, allowExpired bool) (_cache.RetrieveStatus, error) {
func (c *provider) Retrieve(ctx context.Context, cacheKey string, dest cache.CacheableEntity, allowExpired bool) (cache.RetrieveStatus, error) {
err := c.client.Get(ctx, cacheKey).Scan(dest)
if err != nil {
if errors.Is(err, redis.Nil) {
return _cache.RetrieveStatusKeyMiss, nil
return cache.RetrieveStatusKeyMiss, nil
}
return _cache.RetrieveStatusError, err
return cache.RetrieveStatusError, err
}
return _cache.RetrieveStatusHit, nil
return cache.RetrieveStatusHit, nil
}
// SetTTL sets the TTL for the cache entry
@@ -87,11 +92,6 @@ func (c *provider) GetClient() *redis.Client {
return c.client
}
// GetOptions returns the options
func (c *provider) GetOptions() *_cache.Redis {
return c.opts
}
// GetTTL returns the TTL for the cache entry
func (c *provider) GetTTL(ctx context.Context, cacheKey string) time.Duration {
ttl, err := c.client.TTL(ctx, cacheKey).Result()

View File

@@ -25,6 +25,7 @@ func (factory *providerFactory[P, C]) New(ctx context.Context, settings Provider
return factory.newProviderFunc(ctx, settings, config)
}
// NewProviderFactory creates a new provider factory.
func NewProviderFactory[P Provider, C Config](name Name, newProviderFunc NewProviderFunc[P, C]) ProviderFactory[P, C] {
return &providerFactory[P, C]{
name: name,
@@ -32,7 +33,8 @@ func NewProviderFactory[P Provider, C Config](name Name, newProviderFunc NewProv
}
}
func NewFromFactory[P Provider, C Config](ctx context.Context, settings ProviderSettings, config C, factories NamedMap[ProviderFactory[P, C]], key string) (p P, err error) {
// NewProviderFromNamedMap creates a new provider from a factory based on the input key.
func NewProviderFromNamedMap[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

View File

@@ -32,10 +32,10 @@ func TestNewProviderFactoryFromFactory(t *testing.T) {
m := MustNewNamedMap(pf)
assert.Equal(t, MustNewName("p1"), pf.Name())
p, err := NewFromFactory(context.Background(), ProviderSettings{}, pc1{}, m, "p1")
p, err := NewProviderFromNamedMap(context.Background(), ProviderSettings{}, pc1{}, m, "p1")
assert.NoError(t, err)
assert.IsType(t, p1{}, p)
_, err = NewFromFactory(context.Background(), ProviderSettings{}, pc1{}, m, "p2")
_, err = NewProviderFromNamedMap(context.Background(), ProviderSettings{}, pc1{}, m, "p2")
assert.Error(t, err)
}

View File

@@ -0,0 +1,10 @@
package providertest
import (
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/instrumentation/instrumentationtest"
)
func NewSettings() factory.ProviderSettings {
return instrumentationtest.New().ToProviderSettings()
}

View File

@@ -7,24 +7,42 @@ import (
"go.signoz.io/signoz/pkg/config"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/instrumentation"
"go.signoz.io/signoz/pkg/sqlmigration"
"go.signoz.io/signoz/pkg/sqlmigrator"
"go.signoz.io/signoz/pkg/sqlstore"
"go.signoz.io/signoz/pkg/web"
)
// Config defines the entire configuration of signoz.
type ProviderConfig struct {
// Map of all cache provider factories
CacheProviderFactories factory.NamedMap[factory.ProviderFactory[cache.Cache, cache.Config]]
// Map of all web provider factories
WebProviderFactories factory.NamedMap[factory.ProviderFactory[web.Web, web.Config]]
// Map of all sqlstore provider factories
SQLStoreProviderFactories factory.NamedMap[factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config]]
// Map of all sql migration provider factories
SQLMigrationProviderFactories factory.NamedMap[factory.ProviderFactory[sqlmigration.SQLMigration, sqlmigration.Config]]
}
// Config defines the entire input configuration of signoz.
type Config struct {
Instrumentation instrumentation.Config `mapstructure:"instrumentation"`
Web web.Config `mapstructure:"web"`
Cache cache.Config `mapstructure:"cache"`
SQLStore sqlstore.Config `mapstructure:"sqlstore"`
SQLMigrator sqlmigrator.Config `mapstructure:"sqlmigrator"`
}
func NewConfig(ctx context.Context, resolverConfig config.ResolverConfig) (Config, error) {
configFactories := []factory.ConfigFactory{
instrumentation.NewConfigFactory(),
web.NewConfigFactory(),
sqlstore.NewConfigFactory(),
cache.NewConfigFactory(),
sqlstore.NewConfigFactory(),
sqlmigrator.NewConfigFactory(),
}
conf, err := config.New(ctx, resolverConfig, configFactories)

View File

@@ -1,13 +1,14 @@
package signoz
import (
"context"
"go.signoz.io/signoz/pkg/cache"
"go.signoz.io/signoz/pkg/cache/memorycache"
"go.signoz.io/signoz/pkg/cache/rediscache"
"go.signoz.io/signoz/pkg/config"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/instrumentation"
"go.signoz.io/signoz/pkg/version"
"go.signoz.io/signoz/pkg/web"
"go.signoz.io/signoz/pkg/web/routerweb"
"go.uber.org/zap"
)
type SigNoz struct {
@@ -15,19 +16,41 @@ type SigNoz struct {
Web web.Web
}
func New(config config.Config, skipWebFrontend bool) (*SigNoz, error) {
var cache cache.Cache
// init for the cache
switch config.Cache.Provider {
case "memory":
cache = memorycache.New(&config.Cache.Memory)
case "redis":
cache = rediscache.New(&config.Cache.Redis)
func New(
ctx context.Context,
config Config,
providerConfig ProviderConfig,
) (*SigNoz, error) {
// Initialize instrumentation
instrumentation, err := instrumentation.New(ctx, version.Build{}, config.Instrumentation)
if err != nil {
return nil, err
}
web, err := routerweb.New(zap.L(), config.Web)
if err != nil && !skipWebFrontend {
// Get the provider settings from instrumentation
providerSettings := instrumentation.ToProviderSettings()
// Initialize cache from the available cache provider factories
cache, err := factory.NewProviderFromNamedMap(
ctx,
providerSettings,
config.Cache,
providerConfig.CacheProviderFactories,
config.Cache.Provider,
)
if err != nil {
return nil, err
}
// Initialize web from the available web provider factories
web, err := factory.NewProviderFromNamedMap(
ctx,
providerSettings,
config.Web,
providerConfig.WebProviderFactories,
config.Web.Provider(),
)
if err != nil {
return nil, err
}

View File

@@ -1,4 +1,4 @@
package migration
package sqlmigration
import (
"context"
@@ -6,16 +6,15 @@ import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/sqlmigrator"
)
type addDataMigrations struct{}
func NewAddDataMigrationsFactory() factory.ProviderFactory[sqlmigrator.SQLMigration, sqlmigrator.Config] {
func NewAddDataMigrationsFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_data_migrations"), newAddDataMigrations)
}
func newAddDataMigrations(_ context.Context, _ factory.ProviderSettings, _ sqlmigrator.Config) (sqlmigrator.SQLMigration, error) {
func newAddDataMigrations(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
return &addDataMigrations{}, nil
}

View File

@@ -1,4 +1,4 @@
package migration
package sqlmigration
import (
"context"
@@ -6,16 +6,15 @@ import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/sqlmigrator"
)
type addOrganization struct{}
func NewAddOrganizationFactory() factory.ProviderFactory[sqlmigrator.SQLMigration, sqlmigrator.Config] {
func NewAddOrganizationFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_organization"), newAddOrganization)
}
func newAddOrganization(_ context.Context, _ factory.ProviderSettings, _ sqlmigrator.Config) (sqlmigrator.SQLMigration, error) {
func newAddOrganization(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
return &addOrganization{}, nil
}

View File

@@ -1,4 +1,4 @@
package migration
package sqlmigration
import (
"context"
@@ -6,16 +6,15 @@ import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/sqlmigrator"
)
type addPreferences struct{}
func NewAddPreferencesFactory() factory.ProviderFactory[sqlmigrator.SQLMigration, sqlmigrator.Config] {
func NewAddPreferencesFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_preferences"), newAddPreferences)
}
func newAddPreferences(_ context.Context, _ factory.ProviderSettings, _ sqlmigrator.Config) (sqlmigrator.SQLMigration, error) {
func newAddPreferences(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
return &addPreferences{}, nil
}

View File

@@ -1,4 +1,4 @@
package migration
package sqlmigration
import (
"context"
@@ -6,16 +6,15 @@ import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/sqlmigrator"
)
type addDashboards struct{}
func NewAddDashboardsFactory() factory.ProviderFactory[sqlmigrator.SQLMigration, sqlmigrator.Config] {
func NewAddDashboardsFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_dashboards"), newAddDashboards)
}
func newAddDashboards(_ context.Context, _ factory.ProviderSettings, _ sqlmigrator.Config) (sqlmigrator.SQLMigration, error) {
func newAddDashboards(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
return &addDashboards{}, nil
}
@@ -96,8 +95,8 @@ func (migration *addDashboards) Up(ctx context.Context, db *bun.DB) error {
NewAddColumn().
Table("rules").
ColumnExpr("created_at datetime").
Apply(sqlmigrator.WrapIfNotExists(ctx, db, "rules", "created_at")).
Exec(ctx); err != nil && err != sqlmigrator.ErrNoExecute {
Apply(WrapIfNotExists(ctx, db, "rules", "created_at")).
Exec(ctx); err != nil && err != ErrNoExecute {
return err
}
@@ -106,8 +105,8 @@ func (migration *addDashboards) Up(ctx context.Context, db *bun.DB) error {
NewAddColumn().
Table("rules").
ColumnExpr("created_by TEXT").
Apply(sqlmigrator.WrapIfNotExists(ctx, db, "rules", "created_by")).
Exec(ctx); err != nil && err != sqlmigrator.ErrNoExecute {
Apply(WrapIfNotExists(ctx, db, "rules", "created_by")).
Exec(ctx); err != nil && err != ErrNoExecute {
return err
}
@@ -116,8 +115,8 @@ func (migration *addDashboards) Up(ctx context.Context, db *bun.DB) error {
NewAddColumn().
Table("rules").
ColumnExpr("updated_by TEXT").
Apply(sqlmigrator.WrapIfNotExists(ctx, db, "rules", "updated_by")).
Exec(ctx); err != nil && err != sqlmigrator.ErrNoExecute {
Apply(WrapIfNotExists(ctx, db, "rules", "updated_by")).
Exec(ctx); err != nil && err != ErrNoExecute {
return err
}
@@ -126,8 +125,8 @@ func (migration *addDashboards) Up(ctx context.Context, db *bun.DB) error {
NewAddColumn().
Table("dashboards").
ColumnExpr("created_by TEXT").
Apply(sqlmigrator.WrapIfNotExists(ctx, db, "dashboards", "created_by")).
Exec(ctx); err != nil && err != sqlmigrator.ErrNoExecute {
Apply(WrapIfNotExists(ctx, db, "dashboards", "created_by")).
Exec(ctx); err != nil && err != ErrNoExecute {
return err
}
@@ -136,8 +135,8 @@ func (migration *addDashboards) Up(ctx context.Context, db *bun.DB) error {
NewAddColumn().
Table("dashboards").
ColumnExpr("updated_by TEXT").
Apply(sqlmigrator.WrapIfNotExists(ctx, db, "dashboards", "updated_by")).
Exec(ctx); err != nil && err != sqlmigrator.ErrNoExecute {
Apply(WrapIfNotExists(ctx, db, "dashboards", "updated_by")).
Exec(ctx); err != nil && err != ErrNoExecute {
return err
}
@@ -146,8 +145,8 @@ func (migration *addDashboards) Up(ctx context.Context, db *bun.DB) error {
NewAddColumn().
Table("dashboards").
ColumnExpr("locked INTEGER DEFAULT 0").
Apply(sqlmigrator.WrapIfNotExists(ctx, db, "dashboards", "locked")).
Exec(ctx); err != nil && err != sqlmigrator.ErrNoExecute {
Apply(WrapIfNotExists(ctx, db, "dashboards", "locked")).
Exec(ctx); err != nil && err != ErrNoExecute {
return err
}

View File

@@ -1,4 +1,4 @@
package migration
package sqlmigration
import (
"context"
@@ -6,16 +6,15 @@ import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/sqlmigrator"
)
type addSavedViews struct{}
func NewAddSavedViewsFactory() factory.ProviderFactory[sqlmigrator.SQLMigration, sqlmigrator.Config] {
func NewAddSavedViewsFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_saved_views"), newAddSavedViews)
}
func newAddSavedViews(_ context.Context, _ factory.ProviderSettings, _ sqlmigrator.Config) (sqlmigrator.SQLMigration, error) {
func newAddSavedViews(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
return &addSavedViews{}, nil
}

View File

@@ -1,4 +1,4 @@
package migration
package sqlmigration
import (
"context"
@@ -6,16 +6,15 @@ import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/sqlmigrator"
)
type addAgents struct{}
func NewAddAgentsFactory() factory.ProviderFactory[sqlmigrator.SQLMigration, sqlmigrator.Config] {
func NewAddAgentsFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_agents"), newAddAgents)
}
func newAddAgents(_ context.Context, _ factory.ProviderSettings, _ sqlmigrator.Config) (sqlmigrator.SQLMigration, error) {
func newAddAgents(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
return &addAgents{}, nil
}

View File

@@ -1,4 +1,4 @@
package migration
package sqlmigration
import (
"context"
@@ -6,16 +6,15 @@ import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/sqlmigrator"
)
type addPipelines struct{}
func NewAddPipelinesFactory() factory.ProviderFactory[sqlmigrator.SQLMigration, sqlmigrator.Config] {
func NewAddPipelinesFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_pipelines"), newAddPipelines)
}
func newAddPipelines(_ context.Context, _ factory.ProviderSettings, _ sqlmigrator.Config) (sqlmigrator.SQLMigration, error) {
func newAddPipelines(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
return &addPipelines{}, nil
}

View File

@@ -1,4 +1,4 @@
package migration
package sqlmigration
import (
"context"
@@ -6,16 +6,15 @@ import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/sqlmigrator"
)
type addIntegrations struct{}
func NewAddIntegrationsFactory() factory.ProviderFactory[sqlmigrator.SQLMigration, sqlmigrator.Config] {
func NewAddIntegrationsFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_integrations"), newAddIntegrations)
}
func newAddIntegrations(_ context.Context, _ factory.ProviderSettings, _ sqlmigrator.Config) (sqlmigrator.SQLMigration, error) {
func newAddIntegrations(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
return &addIntegrations{}, nil
}

View File

@@ -0,0 +1,19 @@
package sqlmigration
import (
"go.signoz.io/signoz/pkg/factory"
)
type Config struct{}
func NewConfigFactory() factory.ConfigFactory {
return factory.NewConfigFactory(factory.MustNewName("sqlmigration"), newConfig)
}
func newConfig() factory.Config {
return Config{}
}
func (c Config) Validate() error {
return nil
}

View File

@@ -1,4 +1,4 @@
package sqlmigrator
package sqlmigration
import (
"context"
@@ -11,11 +11,22 @@ import (
"go.signoz.io/signoz/pkg/factory"
)
// SQLMigration is the interface for a single migration.
type SQLMigration interface {
// Register registers the migration with the given migrations. Each migration needs to be registered
//in a dedicated `*.go` file so that the correct migration semantics can be detected.
Register(*migrate.Migrations) error
// Up runs the migration.
Up(context.Context, *bun.DB) error
// Down rolls back the migration.
Down(context.Context, *bun.DB) error
}
var (
ErrNoExecute = errors.New("no execute")
)
func NewMigrations(
func New(
ctx context.Context,
settings factory.ProviderSettings,
config Config,
@@ -38,13 +49,13 @@ func NewMigrations(
return migrations, nil
}
func MustNewMigrations(
func MustNew(
ctx context.Context,
settings factory.ProviderSettings,
config Config,
factories factory.NamedMap[factory.ProviderFactory[SQLMigration, Config]],
) *migrate.Migrations {
migrations, err := NewMigrations(ctx, settings, config, factories)
migrations, err := New(ctx, settings, config, factories)
if err != nil {
panic(err)
}

View File

@@ -1,4 +1,4 @@
package sqlmigrator
package sqlmigrationtest
import (
"context"
@@ -6,12 +6,13 @@ import (
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/sqlmigration"
)
type noopMigration struct{}
func NoopMigrationFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("noop"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
func NoopMigrationFactory() factory.ProviderFactory[sqlmigration.SQLMigration, sqlmigration.Config] {
return factory.NewProviderFactory(factory.MustNewName("noop"), func(_ context.Context, _ factory.ProviderSettings, _ sqlmigration.Config) (sqlmigration.SQLMigration, error) {
return &noopMigration{}, nil
})
}

View File

@@ -10,6 +10,8 @@ import (
"github.com/stretchr/testify/require"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/instrumentation/instrumentationtest"
"go.signoz.io/signoz/pkg/sqlmigration"
"go.signoz.io/signoz/pkg/sqlmigration/sqlmigrationtest"
"go.signoz.io/signoz/pkg/sqlstore"
"go.signoz.io/signoz/pkg/sqlstore/sqlstoretest"
)
@@ -33,7 +35,7 @@ func TestMigratorWithSqliteAndNoopMigration(t *testing.T) {
ctx,
providerSettings,
sqlstore,
MustNewMigrations(ctx, providerSettings, migrationConfig, factory.MustNewNamedMap(NoopMigrationFactory())),
sqlmigration.MustNew(ctx, providerSettings, sqlmigration.Config{}, factory.MustNewNamedMap(sqlmigrationtest.NoopMigrationFactory())),
migrationConfig,
)

View File

@@ -2,9 +2,6 @@ package sqlmigrator
import (
"context"
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
)
// SQLMigrator is the interface for the SQLMigrator.
@@ -14,14 +11,3 @@ type SQLMigrator interface {
// Rollback rolls back the database. Rollback acquires a lock on the database and rolls back the migrations.
Rollback(context.Context) error
}
// SQLMigration is the interface for a single migration.
type SQLMigration interface {
// Register registers the migration with the given migrations. Each migration needs to be registered
//in a dedicated `*.go` file so that the correct migration semantics can be detected.
Register(*migrate.Migrations) error
// Up runs the migration.
Up(context.Context, *bun.DB) error
// Down rolls back the migration.
Down(context.Context, *bun.DB) error
}

View File

@@ -1,14 +1,13 @@
package web
import (
"go.signoz.io/signoz/pkg/confmap"
"go.signoz.io/signoz/pkg/factory"
)
// Config satisfies the confmap.Config interface
var _ confmap.Config = (*Config)(nil)
// Config holds the configuration for web.
type Config struct {
// Whether the web package is enabled.
Enabled bool `mapstructure:"enabled"`
// The prefix to serve the files from
Prefix string `mapstructure:"prefix"`
// The directory containing the static build files. The root of this directory should
@@ -16,14 +15,26 @@ type Config struct {
Directory string `mapstructure:"directory"`
}
func (c *Config) NewWithDefaults() confmap.Config {
func NewConfigFactory() factory.ConfigFactory {
return factory.NewConfigFactory(factory.MustNewName("web"), newConfig)
}
func newConfig() factory.Config {
return &Config{
Enabled: true,
Prefix: "/",
Directory: "/etc/signoz/web",
}
}
func (c *Config) Validate() error {
func (c Config) Validate() error {
return nil
}
func (c Config) Provider() string {
if c.Enabled {
return "router"
}
return "noop"
}

45
pkg/web/config_test.go Normal file
View File

@@ -0,0 +1,45 @@
package web
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.signoz.io/signoz/pkg/config"
"go.signoz.io/signoz/pkg/config/envprovider"
"go.signoz.io/signoz/pkg/factory"
)
func TestNewWithEnvProvider(t *testing.T) {
t.Setenv("SIGNOZ_WEB_PREFIX", "/web")
t.Setenv("SIGNOZ_WEB_ENABLED", "false")
conf, err := config.New(
context.Background(),
config.ResolverConfig{
Uris: []string{"env:"},
ProviderFactories: []config.ProviderFactory{
envprovider.NewFactory(),
},
},
[]factory.ConfigFactory{
NewConfigFactory(),
},
)
require.NoError(t, err)
actual := &Config{}
err = conf.Unmarshal("web", actual)
require.NoError(t, err)
def := NewConfigFactory().New().(*Config)
expected := &Config{
Enabled: false,
Prefix: "/web",
Directory: def.Directory,
}
assert.Equal(t, expected, actual)
}

View File

@@ -11,6 +11,10 @@ import (
type provider struct{}
func NewFactory() factory.ProviderFactory[web.Web, web.Config] {
return factory.NewProviderFactory(factory.MustNewName("noopweb"), New)
}
func New(ctx context.Context, settings factory.ProviderSettings, config web.Config) (web.Web, error) {
return &provider{}, nil
}

View File

@@ -1,6 +1,7 @@
package routerweb
import (
"context"
"fmt"
"net/http"
"os"
@@ -8,26 +9,25 @@ 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"
)
const (
indexFileName string = "index.html"
)
type Web struct {
logger *zap.Logger
cfg web.Config
type provider struct {
config web.Config
}
func New(logger *zap.Logger, cfg web.Config) (*Web, error) {
if logger == nil {
return nil, fmt.Errorf("cannot build web, logger is required")
}
func NewFactory() factory.ProviderFactory[web.Web, web.Config] {
return factory.NewProviderFactory(factory.MustNewName("routerweb"), New)
}
fi, err := os.Stat(cfg.Directory)
func New(ctx context.Context, settings factory.ProviderSettings, config web.Config) (web.Web, error) {
fi, err := os.Stat(config.Directory)
if err != nil {
return nil, fmt.Errorf("cannot access web directory: %w", err)
}
@@ -37,7 +37,7 @@ func New(logger *zap.Logger, cfg web.Config) (*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)
}
@@ -46,19 +46,18 @@ func New(logger *zap.Logger, cfg web.Config) (*Web, error) {
return nil, fmt.Errorf("%q does not exist", indexFileName)
}
return &Web{
logger: logger.Named("go.signoz.io/pkg/web"),
cfg: cfg,
return &provider{
config: config,
}, nil
}
func (web *Web) AddToRouter(router *mux.Router) error {
func (provider *provider) AddToRouter(router *mux.Router) error {
cache := middleware.NewCache(7 * 24 * time.Hour)
err := router.PathPrefix(web.cfg.Prefix).
err := router.PathPrefix(provider.config.Prefix).
Handler(
http.StripPrefix(
web.cfg.Prefix,
cache.Wrap(http.HandlerFunc(web.ServeHTTP)),
provider.config.Prefix,
cache.Wrap(http.HandlerFunc(provider.ServeHTTP)),
),
).GetError()
if err != nil {
@@ -68,15 +67,15 @@ func (web *Web) AddToRouter(router *mux.Router) error {
return nil
}
func (web *Web) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
func (provider *provider) 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(provider.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(provider.config.Directory, indexFileName))
return
}
@@ -89,5 +88,5 @@ func (web *Web) 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(provider.config.Directory)).ServeHTTP(rw, req)
}

View File

@@ -1,6 +1,7 @@
package routerweb
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/providertest"
"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(), providertest.NewSettings(), 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(), providertest.NewSettings(), web.Config{Prefix: "/web", Directory: filepath.Join("testdata")})
require.NoError(t, err)
router := mux.NewRouter()