mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-22 16:37:31 +00:00
Compare commits
18 Commits
fix/remove
...
pkg/config
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b10a9061ec | ||
|
|
fae0581d83 | ||
|
|
9d6928b3e6 | ||
|
|
baaffd79de | ||
|
|
59c416c222 | ||
|
|
63a7ae586b | ||
|
|
f0cef2d9d5 | ||
|
|
616ada91dd | ||
|
|
aab6a1c914 | ||
|
|
bc708cd891 | ||
|
|
c2a11960c1 | ||
|
|
6d76d56dbd | ||
|
|
1977756591 | ||
|
|
1d9c10a214 | ||
|
|
57a25bf98f | ||
|
|
35c310aa9d | ||
|
|
7c0481de7d | ||
|
|
147cf28024 |
@@ -3,8 +3,36 @@
|
|||||||
# Do not modify this file
|
# Do not modify this file
|
||||||
#
|
#
|
||||||
|
|
||||||
|
##################### Instrumentation #####################
|
||||||
|
instrumentation:
|
||||||
|
logs:
|
||||||
|
level: info
|
||||||
|
enabled: false
|
||||||
|
processors:
|
||||||
|
batch:
|
||||||
|
exporter:
|
||||||
|
otlp:
|
||||||
|
endpoint: localhost:4317
|
||||||
|
traces:
|
||||||
|
enabled: false
|
||||||
|
processors:
|
||||||
|
batch:
|
||||||
|
exporter:
|
||||||
|
otlp:
|
||||||
|
endpoint: localhost:4317
|
||||||
|
metrics:
|
||||||
|
enabled: true
|
||||||
|
readers:
|
||||||
|
pull:
|
||||||
|
exporter:
|
||||||
|
prometheus:
|
||||||
|
host: "0.0.0.0"
|
||||||
|
port: 9090
|
||||||
|
|
||||||
##################### Web #####################
|
##################### Web #####################
|
||||||
web:
|
web:
|
||||||
|
# Whether to enable the web frontend
|
||||||
|
enabled: true
|
||||||
# The prefix to serve web on
|
# The prefix to serve web on
|
||||||
prefix: /
|
prefix: /
|
||||||
# The directory containing the static build files.
|
# The directory containing the static build files.
|
||||||
@@ -29,4 +57,14 @@ cache:
|
|||||||
# The password for authenticating with the Redis server, if required.
|
# The password for authenticating with the Redis server, if required.
|
||||||
password:
|
password:
|
||||||
# The Redis database number to use
|
# The Redis database number to use
|
||||||
db: 0
|
db: 0
|
||||||
|
|
||||||
|
##################### SQLStore #####################
|
||||||
|
sqlstore:
|
||||||
|
# specifies the SQLStore provider to use.
|
||||||
|
provider: sqlite
|
||||||
|
# The maximum number of open connections to the database.
|
||||||
|
max_open_conns: 100
|
||||||
|
sqlite:
|
||||||
|
# The path to the SQLite database file.
|
||||||
|
path: /var/lib/signoz/signoz.db
|
||||||
@@ -64,7 +64,6 @@ import (
|
|||||||
const AppDbEngine = "sqlite"
|
const AppDbEngine = "sqlite"
|
||||||
|
|
||||||
type ServerOptions struct {
|
type ServerOptions struct {
|
||||||
SigNoz *signoz.SigNoz
|
|
||||||
PromConfigPath string
|
PromConfigPath string
|
||||||
SkipTopLvlOpsPath string
|
SkipTopLvlOpsPath string
|
||||||
HTTPHostPort string
|
HTTPHostPort string
|
||||||
@@ -82,7 +81,6 @@ type ServerOptions struct {
|
|||||||
GatewayUrl string
|
GatewayUrl string
|
||||||
UseLogsNewSchema bool
|
UseLogsNewSchema bool
|
||||||
UseTraceNewSchema bool
|
UseTraceNewSchema bool
|
||||||
SkipWebFrontend bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server runs HTTP api service
|
// Server runs HTTP api service
|
||||||
@@ -112,26 +110,15 @@ func (s Server) HealthCheckStatus() chan healthcheck.Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewServer creates and initializes Server
|
// NewServer creates and initializes Server
|
||||||
func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
|
||||||
|
modelDao, err := dao.InitDao(signoz.SQLStore.SQLxDB())
|
||||||
modelDao, err := dao.InitDao("sqlite", baseconst.RELATIONAL_DATASOURCE_PATH)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
baseexplorer.InitWithDSN(baseconst.RELATIONAL_DATASOURCE_PATH)
|
baseexplorer.InitWithDB(signoz.SQLStore.SQLxDB())
|
||||||
|
preferences.InitDB(signoz.SQLStore.SQLxDB())
|
||||||
if err := preferences.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH); err != nil {
|
dashboards.InitDB(signoz.SQLStore.SQLxDB())
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
localDB, err := dashboards.InitDB(baseconst.RELATIONAL_DATASOURCE_PATH)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
localDB.SetMaxOpenConns(10)
|
|
||||||
|
|
||||||
gatewayProxy, err := gateway.NewProxy(serverOptions.GatewayUrl, gateway.RoutePrefix)
|
gatewayProxy, err := gateway.NewProxy(serverOptions.GatewayUrl, gateway.RoutePrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -139,7 +126,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initiate license manager
|
// initiate license manager
|
||||||
lm, err := licensepkg.StartManager("sqlite", localDB)
|
lm, err := licensepkg.StartManager("sqlite", signoz.SQLStore.SQLxDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -153,7 +140,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
if storage == "clickhouse" {
|
if storage == "clickhouse" {
|
||||||
zap.L().Info("Using ClickHouse as datastore ...")
|
zap.L().Info("Using ClickHouse as datastore ...")
|
||||||
qb := db.NewDataConnector(
|
qb := db.NewDataConnector(
|
||||||
localDB,
|
signoz.SQLStore.SQLxDB(),
|
||||||
serverOptions.PromConfigPath,
|
serverOptions.PromConfigPath,
|
||||||
lm,
|
lm,
|
||||||
serverOptions.MaxIdleConns,
|
serverOptions.MaxIdleConns,
|
||||||
@@ -189,7 +176,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
rm, err := makeRulesManager(serverOptions.PromConfigPath,
|
rm, err := makeRulesManager(serverOptions.PromConfigPath,
|
||||||
baseconst.GetAlertManagerApiPrefix(),
|
baseconst.GetAlertManagerApiPrefix(),
|
||||||
serverOptions.RuleRepoURL,
|
serverOptions.RuleRepoURL,
|
||||||
localDB,
|
signoz.SQLStore.SQLxDB(),
|
||||||
reader,
|
reader,
|
||||||
c,
|
c,
|
||||||
serverOptions.DisableRules,
|
serverOptions.DisableRules,
|
||||||
@@ -210,19 +197,16 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// initiate opamp
|
// initiate opamp
|
||||||
_, err = opAmpModel.InitDB(localDB)
|
_ = opAmpModel.InitDB(signoz.SQLStore.SQLxDB())
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
integrationsController, err := integrations.NewController(localDB)
|
integrationsController, err := integrations.NewController(signoz.SQLStore.SQLxDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"couldn't create integrations controller: %w", err,
|
"couldn't create integrations controller: %w", err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cloudIntegrationsController, err := cloudintegrations.NewController(localDB)
|
cloudIntegrationsController, err := cloudintegrations.NewController(signoz.SQLStore.SQLxDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"couldn't create cloud provider integrations controller: %w", err,
|
"couldn't create cloud provider integrations controller: %w", err,
|
||||||
@@ -231,7 +215,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
|
|
||||||
// ingestion pipelines manager
|
// ingestion pipelines manager
|
||||||
logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController(
|
logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController(
|
||||||
localDB, "sqlite", integrationsController.GetPipelinesForInstalledIntegrations,
|
signoz.SQLStore.SQLxDB(), integrationsController.GetPipelinesForInstalledIntegrations,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -239,8 +223,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
|
|
||||||
// initiate agent config handler
|
// initiate agent config handler
|
||||||
agentConfMgr, err := agentConf.Initiate(&agentConf.ManagerOptions{
|
agentConfMgr, err := agentConf.Initiate(&agentConf.ManagerOptions{
|
||||||
DB: localDB,
|
DB: signoz.SQLStore.SQLxDB(),
|
||||||
DBEngine: AppDbEngine,
|
|
||||||
AgentFeatures: []agentConf.AgentFeature{logParsingPipelineController},
|
AgentFeatures: []agentConf.AgentFeature{logParsingPipelineController},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -302,7 +285,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
usageManager: usageManager,
|
usageManager: usageManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
httpServer, err := s.createPublicServer(apiHandler, serverOptions.SigNoz.Web)
|
httpServer, err := s.createPublicServer(apiHandler, signoz.Web)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -351,7 +334,7 @@ func (s *Server) createPrivateServer(apiHandler *api.APIHandler) (*http.Server,
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) createPublicServer(apiHandler *api.APIHandler, web *web.Web) (*http.Server, error) {
|
func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*http.Server, error) {
|
||||||
|
|
||||||
r := baseapp.NewRouter()
|
r := baseapp.NewRouter()
|
||||||
|
|
||||||
@@ -396,11 +379,9 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web *web.Web) (*
|
|||||||
|
|
||||||
handler = handlers.CompressHandler(handler)
|
handler = handlers.CompressHandler(handler)
|
||||||
|
|
||||||
if !s.serverOptions.SkipWebFrontend {
|
err := web.AddToRouter(r)
|
||||||
err := web.AddToRouter(r)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &http.Server{
|
return &http.Server{
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
package dao
|
package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
"go.signoz.io/signoz/ee/query-service/dao/sqlite"
|
"go.signoz.io/signoz/ee/query-service/dao/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitDao(engine, path string) (ModelDao, error) {
|
func InitDao(inputDB *sqlx.DB) (ModelDao, error) {
|
||||||
|
return sqlite.InitDB(inputDB)
|
||||||
switch engine {
|
|
||||||
case "sqlite":
|
|
||||||
return sqlite.InitDB(path)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("qsdb type: %s is not supported in query service", engine)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ func columnExists(db *sqlx.DB, tableName, columnName string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InitDB creates and extends base model DB repository
|
// InitDB creates and extends base model DB repository
|
||||||
func InitDB(dataSourceName string) (*modelDao, error) {
|
func InitDB(inputDB *sqlx.DB) (*modelDao, error) {
|
||||||
dao, err := basedsql.InitDB(dataSourceName)
|
dao, err := basedsql.InitDB(inputDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,86 +3,28 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strconv"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"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"
|
"go.signoz.io/signoz/ee/query-service/app"
|
||||||
|
"go.signoz.io/signoz/pkg/config"
|
||||||
signozconfig "go.signoz.io/signoz/pkg/config"
|
signozconfig "go.signoz.io/signoz/pkg/config"
|
||||||
"go.signoz.io/signoz/pkg/confmap/provider/signozenvprovider"
|
"go.signoz.io/signoz/pkg/config/envprovider"
|
||||||
|
"go.signoz.io/signoz/pkg/instrumentation"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
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/query-service/version"
|
||||||
"go.signoz.io/signoz/pkg/signoz"
|
"go.signoz.io/signoz/pkg/signoz"
|
||||||
"google.golang.org/grpc"
|
pkgversion "go.signoz.io/signoz/pkg/version"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
|
||||||
|
|
||||||
prommodel "github.com/prometheus/common/model"
|
prommodel "github.com/prometheus/common/model"
|
||||||
|
|
||||||
zapotlpencoder "github.com/SigNoz/zap_otlp/zap_otlp_encoder"
|
|
||||||
zapotlpsync "github.com/SigNoz/zap_otlp/zap_otlp_sync"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func initZapLog(enableQueryServiceLogOTLPExport bool) *zap.Logger {
|
|
||||||
config := zap.NewProductionConfig()
|
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
|
||||||
defer stop()
|
|
||||||
|
|
||||||
config.EncoderConfig.EncodeDuration = zapcore.MillisDurationEncoder
|
|
||||||
config.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
|
|
||||||
config.EncoderConfig.TimeKey = "timestamp"
|
|
||||||
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
|
||||||
|
|
||||||
otlpEncoder := zapotlpencoder.NewOTLPEncoder(config.EncoderConfig)
|
|
||||||
consoleEncoder := zapcore.NewJSONEncoder(config.EncoderConfig)
|
|
||||||
defaultLogLevel := zapcore.InfoLevel
|
|
||||||
|
|
||||||
res := resource.NewWithAttributes(
|
|
||||||
semconv.SchemaURL,
|
|
||||||
semconv.ServiceNameKey.String("query-service"),
|
|
||||||
)
|
|
||||||
|
|
||||||
core := zapcore.NewTee(
|
|
||||||
zapcore.NewCore(consoleEncoder, os.Stdout, defaultLogLevel),
|
|
||||||
)
|
|
||||||
|
|
||||||
if enableQueryServiceLogOTLPExport {
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
|
||||||
defer cancel()
|
|
||||||
conn, err := grpc.DialContext(ctx, baseconst.OTLPTarget, grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to establish connection: %v", err)
|
|
||||||
} else {
|
|
||||||
logExportBatchSizeInt, err := strconv.Atoi(baseconst.LogExportBatchSize)
|
|
||||||
if err != nil {
|
|
||||||
logExportBatchSizeInt = 512
|
|
||||||
}
|
|
||||||
ws := zapcore.AddSync(zapotlpsync.NewOtlpSyncer(conn, zapotlpsync.Options{
|
|
||||||
BatchSize: logExportBatchSizeInt,
|
|
||||||
ResourceSchema: semconv.SchemaURL,
|
|
||||||
Resource: res,
|
|
||||||
}))
|
|
||||||
core = zapcore.NewTee(
|
|
||||||
zapcore.NewCore(consoleEncoder, os.Stdout, defaultLogLevel),
|
|
||||||
zapcore.NewCore(otlpEncoder, zapcore.NewMultiWriteSyncer(ws), defaultLogLevel),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel))
|
|
||||||
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
prommodel.NameValidationScheme = prommodel.UTF8Validation
|
prommodel.NameValidationScheme = prommodel.UTF8Validation
|
||||||
}
|
}
|
||||||
@@ -100,7 +42,6 @@ func main() {
|
|||||||
var useLogsNewSchema bool
|
var useLogsNewSchema bool
|
||||||
var useTraceNewSchema bool
|
var useTraceNewSchema bool
|
||||||
var cacheConfigPath, fluxInterval string
|
var cacheConfigPath, fluxInterval string
|
||||||
var enableQueryServiceLogOTLPExport bool
|
|
||||||
var preferSpanMetrics bool
|
var preferSpanMetrics bool
|
||||||
|
|
||||||
var maxIdleConns int
|
var maxIdleConns int
|
||||||
@@ -108,7 +49,6 @@ func main() {
|
|||||||
var dialTimeout time.Duration
|
var dialTimeout time.Duration
|
||||||
var gatewayUrl string
|
var gatewayUrl string
|
||||||
var useLicensesV3 bool
|
var useLicensesV3 bool
|
||||||
var skipWebFrontend bool
|
|
||||||
|
|
||||||
flag.BoolVar(&useLogsNewSchema, "use-logs-new-schema", false, "use logs_v2 schema for logs")
|
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")
|
flag.BoolVar(&useTraceNewSchema, "use-trace-new-schema", false, "use new schema for traces")
|
||||||
@@ -122,39 +62,39 @@ func main() {
|
|||||||
flag.StringVar(&ruleRepoURL, "rules.repo-url", baseconst.AlertHelpPage, "(host address used to build rule link in alert messages)")
|
flag.StringVar(&ruleRepoURL, "rules.repo-url", baseconst.AlertHelpPage, "(host address used to build rule link in alert messages)")
|
||||||
flag.StringVar(&cacheConfigPath, "experimental.cache-config", "", "(cache config to use)")
|
flag.StringVar(&cacheConfigPath, "experimental.cache-config", "", "(cache config to use)")
|
||||||
flag.StringVar(&fluxInterval, "flux-interval", "5m", "(the interval to exclude data from being cached to avoid incorrect cache for data in motion)")
|
flag.StringVar(&fluxInterval, "flux-interval", "5m", "(the interval to exclude data from being cached to avoid incorrect cache for data in motion)")
|
||||||
flag.BoolVar(&enableQueryServiceLogOTLPExport, "enable.query.service.log.otlp.export", false, "(enable query service log otlp export)")
|
|
||||||
flag.StringVar(&cluster, "cluster", "cluster", "(cluster name - defaults to 'cluster')")
|
flag.StringVar(&cluster, "cluster", "cluster", "(cluster name - defaults to 'cluster')")
|
||||||
flag.StringVar(&gatewayUrl, "gateway-url", "", "(url to the gateway)")
|
flag.StringVar(&gatewayUrl, "gateway-url", "", "(url to the gateway)")
|
||||||
flag.BoolVar(&useLicensesV3, "use-licenses-v3", false, "use licenses_v3 schema for licenses")
|
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()
|
flag.Parse()
|
||||||
|
|
||||||
loggerMgr := initZapLog(enableQueryServiceLogOTLPExport)
|
|
||||||
|
|
||||||
zap.ReplaceGlobals(loggerMgr)
|
|
||||||
defer loggerMgr.Sync() // flushes buffer, if any
|
|
||||||
|
|
||||||
version.PrintVersion()
|
version.PrintVersion()
|
||||||
|
|
||||||
config, err := signozconfig.New(context.Background(), signozconfig.ProviderSettings{
|
config, err := signoz.NewConfig(context.Background(), signozconfig.ResolverConfig{
|
||||||
ResolverSettings: confmap.ResolverSettings{
|
Uris: []string{"env:"},
|
||||||
URIs: []string{"signozenv:"},
|
ProviderFactories: []config.ProviderFactory{
|
||||||
ProviderFactories: []confmap.ProviderFactory{
|
envprovider.NewFactory(),
|
||||||
signozenvprovider.NewFactory(),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Fatal("Failed to create config", zap.Error(err))
|
zap.L().Fatal("Failed to create config", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
signoz, err := signoz.New(config, skipWebFrontend)
|
instrumentation, err := instrumentation.New(context.Background(), pkgversion.Build{}, config.Instrumentation)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err, err.Error())
|
||||||
|
zap.L().Fatal("Failed to create instrumentation", zap.Error(err))
|
||||||
|
}
|
||||||
|
defer instrumentation.Stop(context.Background())
|
||||||
|
|
||||||
|
zap.ReplaceGlobals(instrumentation.Logger())
|
||||||
|
defer instrumentation.Logger().Sync() // flushes buffer, if any
|
||||||
|
|
||||||
|
signoz, err := signoz.New(context.Background(), instrumentation, config, signoz.NewProviderFactories())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Fatal("Failed to create signoz struct", zap.Error(err))
|
zap.L().Fatal("Failed to create signoz struct", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
serverOptions := &app.ServerOptions{
|
serverOptions := &app.ServerOptions{
|
||||||
SigNoz: signoz,
|
|
||||||
HTTPHostPort: baseconst.HTTPHostPort,
|
HTTPHostPort: baseconst.HTTPHostPort,
|
||||||
PromConfigPath: promConfigPath,
|
PromConfigPath: promConfigPath,
|
||||||
SkipTopLvlOpsPath: skipTopLvlOpsPath,
|
SkipTopLvlOpsPath: skipTopLvlOpsPath,
|
||||||
@@ -171,7 +111,6 @@ func main() {
|
|||||||
GatewayUrl: gatewayUrl,
|
GatewayUrl: gatewayUrl,
|
||||||
UseLogsNewSchema: useLogsNewSchema,
|
UseLogsNewSchema: useLogsNewSchema,
|
||||||
UseTraceNewSchema: useTraceNewSchema,
|
UseTraceNewSchema: useTraceNewSchema,
|
||||||
SkipWebFrontend: skipWebFrontend,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the jwt secret key
|
// Read the jwt secret key
|
||||||
@@ -183,13 +122,7 @@ func main() {
|
|||||||
zap.L().Info("JWT secret key set successfully.")
|
zap.L().Info("JWT secret key set successfully.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := migrate.Migrate(baseconst.RELATIONAL_DATASOURCE_PATH); err != nil {
|
server, err := app.NewServer(serverOptions, config, signoz)
|
||||||
zap.L().Error("Failed to migrate", zap.Error(err))
|
|
||||||
} else {
|
|
||||||
zap.L().Info("Migration successful")
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := app.NewServer(serverOptions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Fatal("Failed to create server", zap.Error(err))
|
zap.L().Fatal("Failed to create server", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|||||||
20
go.mod
20
go.mod
@@ -9,8 +9,6 @@ require (
|
|||||||
github.com/DATA-DOG/go-sqlmock v1.5.2
|
github.com/DATA-DOG/go-sqlmock v1.5.2
|
||||||
github.com/SigNoz/govaluate v0.0.0-20240203125216-988004ccc7fd
|
github.com/SigNoz/govaluate v0.0.0-20240203125216-988004ccc7fd
|
||||||
github.com/SigNoz/signoz-otel-collector v0.111.16
|
github.com/SigNoz/signoz-otel-collector v0.111.16
|
||||||
github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974
|
|
||||||
github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230822164844-1b861a431974
|
|
||||||
github.com/antonmedv/expr v1.15.3
|
github.com/antonmedv/expr v1.15.3
|
||||||
github.com/auth0/go-jwt-middleware v1.0.1
|
github.com/auth0/go-jwt-middleware v1.0.1
|
||||||
github.com/cespare/xxhash/v2 v2.3.0
|
github.com/cespare/xxhash/v2 v2.3.0
|
||||||
@@ -20,6 +18,7 @@ require (
|
|||||||
github.com/go-kit/log v0.2.1
|
github.com/go-kit/log v0.2.1
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
github.com/go-redis/redismock/v8 v8.11.5
|
github.com/go-redis/redismock/v8 v8.11.5
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.1.0
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/handlers v1.5.1
|
github.com/gorilla/handlers v1.5.1
|
||||||
@@ -29,8 +28,9 @@ require (
|
|||||||
github.com/jmoiron/sqlx v1.3.4
|
github.com/jmoiron/sqlx v1.3.4
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/knadh/koanf v1.5.0
|
github.com/knadh/koanf v1.5.0
|
||||||
|
github.com/knadh/koanf/v2 v2.1.1
|
||||||
github.com/mailru/easyjson v0.7.7
|
github.com/mailru/easyjson v0.7.7
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
github.com/mattn/go-sqlite3 v1.14.24
|
||||||
github.com/oklog/oklog v0.3.2
|
github.com/oklog/oklog v0.3.2
|
||||||
github.com/open-telemetry/opamp-go v0.5.0
|
github.com/open-telemetry/opamp-go v0.5.0
|
||||||
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza v0.111.0
|
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza v0.111.0
|
||||||
@@ -48,6 +48,8 @@ require (
|
|||||||
github.com/soheilhy/cmux v0.1.5
|
github.com/soheilhy/cmux v0.1.5
|
||||||
github.com/srikanthccv/ClickHouse-go-mock v0.9.0
|
github.com/srikanthccv/ClickHouse-go-mock v0.9.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
|
github.com/uptrace/bun v1.2.8
|
||||||
|
github.com/uptrace/bun/dialect/sqlitedialect v1.2.8
|
||||||
go.opentelemetry.io/collector/confmap v1.17.0
|
go.opentelemetry.io/collector/confmap v1.17.0
|
||||||
go.opentelemetry.io/collector/pdata v1.17.0
|
go.opentelemetry.io/collector/pdata v1.17.0
|
||||||
go.opentelemetry.io/collector/processor v0.111.0
|
go.opentelemetry.io/collector/processor v0.111.0
|
||||||
@@ -65,7 +67,6 @@ require (
|
|||||||
golang.org/x/net v0.33.0
|
golang.org/x/net v0.33.0
|
||||||
golang.org/x/oauth2 v0.23.0
|
golang.org/x/oauth2 v0.23.0
|
||||||
golang.org/x/text v0.21.0
|
golang.org/x/text v0.21.0
|
||||||
google.golang.org/grpc v1.67.1
|
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0
|
gopkg.in/segmentio/analytics-go.v3 v3.1.0
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
@@ -99,6 +100,7 @@ require (
|
|||||||
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
|
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/go-faster/city v1.0.1 // indirect
|
github.com/go-faster/city v1.0.1 // indirect
|
||||||
github.com/go-faster/errors v0.7.1 // indirect
|
github.com/go-faster/errors v0.7.1 // indirect
|
||||||
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||||
@@ -106,7 +108,6 @@ require (
|
|||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.1.0 // indirect
|
|
||||||
github.com/goccy/go-json v0.10.3 // indirect
|
github.com/goccy/go-json v0.10.3 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||||
@@ -120,13 +121,13 @@ require (
|
|||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
|
||||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/jonboulle/clockwork v0.4.0 // indirect
|
github.com/jonboulle/clockwork v0.4.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/jpillora/backoff v1.0.0 // indirect
|
github.com/jpillora/backoff v1.0.0 // indirect
|
||||||
github.com/jtolds/gls v4.20.0+incompatible // indirect
|
github.com/jtolds/gls v4.20.0+incompatible // indirect
|
||||||
github.com/klauspost/compress v1.17.10 // indirect
|
github.com/klauspost/compress v1.17.10 // indirect
|
||||||
github.com/knadh/koanf/v2 v2.1.1 // indirect
|
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/leodido/go-syslog/v4 v4.2.0 // indirect
|
github.com/leodido/go-syslog/v4 v4.2.0 // indirect
|
||||||
github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b // indirect
|
github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b // indirect
|
||||||
@@ -151,6 +152,7 @@ require (
|
|||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common/sigv4 v0.1.0 // indirect
|
github.com/prometheus/common/sigv4 v0.1.0 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
|
||||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
github.com/segmentio/asm v1.2.0 // indirect
|
github.com/segmentio/asm v1.2.0 // indirect
|
||||||
github.com/segmentio/backo-go v1.0.1 // indirect
|
github.com/segmentio/backo-go v1.0.1 // indirect
|
||||||
@@ -162,8 +164,11 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
||||||
github.com/tklauser/numcpus v0.7.0 // indirect
|
github.com/tklauser/numcpus v0.7.0 // indirect
|
||||||
|
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
||||||
github.com/valyala/fastjson v1.6.4 // indirect
|
github.com/valyala/fastjson v1.6.4 // indirect
|
||||||
github.com/vjeantet/grok v1.0.1 // indirect
|
github.com/vjeantet/grok v1.0.1 // indirect
|
||||||
|
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||||
|
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
@@ -212,12 +217,13 @@ require (
|
|||||||
go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect
|
go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.29.0 // indirect
|
||||||
golang.org/x/time v0.6.0 // indirect
|
golang.org/x/time v0.6.0 // indirect
|
||||||
gonum.org/v1/gonum v0.15.1 // indirect
|
gonum.org/v1/gonum v0.15.1 // indirect
|
||||||
google.golang.org/api v0.199.0 // indirect
|
google.golang.org/api v0.199.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
|
google.golang.org/grpc v1.67.1 // indirect
|
||||||
k8s.io/client-go v0.31.1 // indirect
|
k8s.io/client-go v0.31.1 // indirect
|
||||||
k8s.io/klog/v2 v2.130.1 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
|
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
|
||||||
|
|||||||
28
go.sum
28
go.sum
@@ -70,12 +70,6 @@ github.com/SigNoz/prometheus v1.12.0 h1:+BXeIHyMOOWWa+xjhJ+x80JFva7r1WzWIfIhQ5PU
|
|||||||
github.com/SigNoz/prometheus v1.12.0/go.mod h1:EqNM27OwmPfqMUk+E+XG1L9rfDFcyXnzzDrg0EPOfxA=
|
github.com/SigNoz/prometheus v1.12.0/go.mod h1:EqNM27OwmPfqMUk+E+XG1L9rfDFcyXnzzDrg0EPOfxA=
|
||||||
github.com/SigNoz/signoz-otel-collector v0.111.16 h1:535uKH5Oux+35EsI+L3C6pnAP/Ye0PTCbVizXoL+VqE=
|
github.com/SigNoz/signoz-otel-collector v0.111.16 h1:535uKH5Oux+35EsI+L3C6pnAP/Ye0PTCbVizXoL+VqE=
|
||||||
github.com/SigNoz/signoz-otel-collector v0.111.16/go.mod h1:HJ4m0LY1MPsuZmuRF7Ixb+bY8rxgRzI0VXzOedESsjg=
|
github.com/SigNoz/signoz-otel-collector v0.111.16/go.mod h1:HJ4m0LY1MPsuZmuRF7Ixb+bY8rxgRzI0VXzOedESsjg=
|
||||||
github.com/SigNoz/zap_otlp v0.1.0 h1:T7rRcFN87GavY8lDGZj0Z3Xv6OhJA6Pj3I9dNPmqvRc=
|
|
||||||
github.com/SigNoz/zap_otlp v0.1.0/go.mod h1:lcHvbDbRgvDnPxo9lDlaL1JK2PyOyouP/C3ynnYIvyo=
|
|
||||||
github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974 h1:PKVgdf83Yw+lZJbFtNGBgqXiXNf3+kOXW2qZ7Ms7OaY=
|
|
||||||
github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974/go.mod h1:fpiHtiboLJpIE5TtkQfiWx6xtnlA+uWmv+N9opETqKY=
|
|
||||||
github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230822164844-1b861a431974 h1:G2JzCrqdeOTtAn4tDFZEg5gCAEYVRXcddG3ZlrFMumo=
|
|
||||||
github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230822164844-1b861a431974/go.mod h1:YtDal1xBRQfPRNo7iSU3W37RGT0jMW7Rnzk6EON3a4M=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
@@ -436,6 +430,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
|
|||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/ionos-cloud/sdk-go/v6 v6.2.1 h1:mxxN+frNVmbFrmmFfXnBC3g2USYJrl6mc1LW2iNYbFY=
|
github.com/ionos-cloud/sdk-go/v6 v6.2.1 h1:mxxN+frNVmbFrmmFfXnBC3g2USYJrl6mc1LW2iNYbFY=
|
||||||
github.com/ionos-cloud/sdk-go/v6 v6.2.1/go.mod h1:SXrO9OGyWjd2rZhAhEpdYN6VUAODzzqRdqA9BCviQtI=
|
github.com/ionos-cloud/sdk-go/v6 v6.2.1/go.mod h1:SXrO9OGyWjd2rZhAhEpdYN6VUAODzzqRdqA9BCviQtI=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
@@ -519,8 +515,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
|||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
@@ -661,6 +657,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
|
|||||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
|
github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
|
||||||
|
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||||
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
|
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
@@ -740,12 +738,22 @@ github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08
|
|||||||
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
|
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
|
||||||
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
|
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
|
||||||
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
|
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
|
||||||
|
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
|
||||||
|
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
|
||||||
|
github.com/uptrace/bun v1.2.8 h1:HEiLvy9wc7ehU5S02+O6NdV5BLz48lL4REPhTkMX3Dg=
|
||||||
|
github.com/uptrace/bun v1.2.8/go.mod h1:JBq0uBKsKqNT0Ccce1IAFZY337Wkf08c6F6qlmfOHE8=
|
||||||
|
github.com/uptrace/bun/dialect/sqlitedialect v1.2.8 h1:Huqw7YhLFTbocbSv8NETYYXqKtwLa6XsciCWtjzWSWU=
|
||||||
|
github.com/uptrace/bun/dialect/sqlitedialect v1.2.8/go.mod h1:ni7h2uwIc5zPhxgmCMTEbefONc4XsVr/ATfz1Q7d3CE=
|
||||||
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
|
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
|
||||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
||||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/vjeantet/grok v1.0.1 h1:2rhIR7J4gThTgcZ1m2JY4TrJZNgjn985U28kT2wQrJ4=
|
github.com/vjeantet/grok v1.0.1 h1:2rhIR7J4gThTgcZ1m2JY4TrJZNgjn985U28kT2wQrJ4=
|
||||||
github.com/vjeantet/grok v1.0.1/go.mod h1:ax1aAchzC6/QMXMcyzHQGZWaW1l195+uMYIkCWPCNIo=
|
github.com/vjeantet/grok v1.0.1/go.mod h1:ax1aAchzC6/QMXMcyzHQGZWaW1l195+uMYIkCWPCNIo=
|
||||||
|
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||||
|
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||||
|
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||||
|
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||||
github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs=
|
github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs=
|
||||||
github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI=
|
github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
@@ -1086,8 +1094,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
|
|||||||
14
pkg/cache/config.go
vendored
14
pkg/cache/config.go
vendored
@@ -4,12 +4,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
go_cache "github.com/patrickmn/go-cache"
|
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 {
|
type Memory struct {
|
||||||
TTL time.Duration `mapstructure:"ttl"`
|
TTL time.Duration `mapstructure:"ttl"`
|
||||||
CleanupInterval time.Duration `mapstructure:"cleanupInterval"`
|
CleanupInterval time.Duration `mapstructure:"cleanupInterval"`
|
||||||
@@ -28,7 +25,11 @@ type Config struct {
|
|||||||
Redis Redis `mapstructure:"redis"`
|
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{
|
return &Config{
|
||||||
Provider: "memory",
|
Provider: "memory",
|
||||||
Memory: Memory{
|
Memory: Memory{
|
||||||
@@ -42,8 +43,9 @@ func (c *Config) NewWithDefaults() confmap.Config {
|
|||||||
DB: 0,
|
DB: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Validate() error {
|
func (c Config) Validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
101
pkg/cache/memorycache/memory.go
vendored
Normal file
101
pkg/cache/memorycache/memory.go
vendored
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package memorycache
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package memory
|
package memorycache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -7,18 +7,21 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
_cache "go.signoz.io/signoz/pkg/cache"
|
_cache "go.signoz.io/signoz/pkg/cache"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestNew tests the New function
|
// TestNew tests the New function
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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)
|
||||||
assert.NotNil(t, c.cc)
|
assert.NotNil(t, c.(*memory).cc)
|
||||||
assert.NoError(t, c.Connect(context.Background()))
|
assert.NoError(t, c.Connect(context.Background()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,32 +56,35 @@ func (dce DCacheableEntity) UnmarshalBinary(data []byte) error {
|
|||||||
// TestStore tests the Store function
|
// TestStore tests the Store function
|
||||||
// this should fail because of nil pointer error
|
// this should fail because of nil pointer error
|
||||||
func TestStoreWithNilPointer(t *testing.T) {
|
func TestStoreWithNilPointer(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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
|
var storeCacheableEntity *CacheableEntity
|
||||||
assert.Error(t, c.Store(context.Background(), "key", storeCacheableEntity, 10*time.Second))
|
assert.Error(t, c.Store(context.Background(), "key", storeCacheableEntity, 10*time.Second))
|
||||||
}
|
}
|
||||||
|
|
||||||
// this should fail because of no pointer error
|
// this should fail because of no pointer error
|
||||||
func TestStoreWithStruct(t *testing.T) {
|
func TestStoreWithStruct(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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
|
var storeCacheableEntity CacheableEntity
|
||||||
assert.Error(t, c.Store(context.Background(), "key", storeCacheableEntity, 10*time.Second))
|
assert.Error(t, c.Store(context.Background(), "key", storeCacheableEntity, 10*time.Second))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStoreWithNonNilPointer(t *testing.T) {
|
func TestStoreWithNonNilPointer(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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{
|
storeCacheableEntity := &CacheableEntity{
|
||||||
Key: "some-random-key",
|
Key: "some-random-key",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
@@ -89,11 +95,12 @@ func TestStoreWithNonNilPointer(t *testing.T) {
|
|||||||
|
|
||||||
// TestRetrieve tests the Retrieve function
|
// TestRetrieve tests the Retrieve function
|
||||||
func TestRetrieveWithNilPointer(t *testing.T) {
|
func TestRetrieveWithNilPointer(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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{
|
storeCacheableEntity := &CacheableEntity{
|
||||||
Key: "some-random-key",
|
Key: "some-random-key",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
@@ -109,11 +116,12 @@ func TestRetrieveWithNilPointer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRetrieveWitNonPointer(t *testing.T) {
|
func TestRetrieveWitNonPointer(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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{
|
storeCacheableEntity := &CacheableEntity{
|
||||||
Key: "some-random-key",
|
Key: "some-random-key",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
@@ -129,11 +137,12 @@ func TestRetrieveWitNonPointer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRetrieveWithDifferentTypes(t *testing.T) {
|
func TestRetrieveWithDifferentTypes(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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{
|
storeCacheableEntity := &CacheableEntity{
|
||||||
Key: "some-random-key",
|
Key: "some-random-key",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
@@ -148,11 +157,8 @@ func TestRetrieveWithDifferentTypes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRetrieveWithSameTypes(t *testing.T) {
|
func TestRetrieveWithSameTypes(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
c, err := New(context.Background(), factory.ProviderSettings{}, _cache.Config{Provider: "memory", Memory: _cache.Memory{TTL: 10 * time.Second, CleanupInterval: 10 * time.Second}})
|
||||||
TTL: 10 * time.Second,
|
require.NoError(t, err)
|
||||||
CleanupInterval: 10 * time.Second,
|
|
||||||
}
|
|
||||||
c := New(opts)
|
|
||||||
storeCacheableEntity := &CacheableEntity{
|
storeCacheableEntity := &CacheableEntity{
|
||||||
Key: "some-random-key",
|
Key: "some-random-key",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
@@ -169,7 +175,8 @@ func TestRetrieveWithSameTypes(t *testing.T) {
|
|||||||
|
|
||||||
// TestSetTTL tests the SetTTL function
|
// TestSetTTL tests the SetTTL function
|
||||||
func TestSetTTL(t *testing.T) {
|
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{
|
storeCacheableEntity := &CacheableEntity{
|
||||||
Key: "some-random-key",
|
Key: "some-random-key",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
@@ -194,11 +201,11 @@ func TestSetTTL(t *testing.T) {
|
|||||||
|
|
||||||
// TestRemove tests the Remove function
|
// TestRemove tests the Remove function
|
||||||
func TestRemove(t *testing.T) {
|
func TestRemove(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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{
|
storeCacheableEntity := &CacheableEntity{
|
||||||
Key: "some-random-key",
|
Key: "some-random-key",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
@@ -216,11 +223,12 @@ func TestRemove(t *testing.T) {
|
|||||||
|
|
||||||
// TestBulkRemove tests the BulkRemove function
|
// TestBulkRemove tests the BulkRemove function
|
||||||
func TestBulkRemove(t *testing.T) {
|
func TestBulkRemove(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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{
|
storeCacheableEntity := &CacheableEntity{
|
||||||
Key: "some-random-key",
|
Key: "some-random-key",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
@@ -244,11 +252,12 @@ func TestBulkRemove(t *testing.T) {
|
|||||||
|
|
||||||
// TestCache tests the cache
|
// TestCache tests the cache
|
||||||
func TestCache(t *testing.T) {
|
func TestCache(t *testing.T) {
|
||||||
opts := &_cache.Memory{
|
opts := _cache.Memory{
|
||||||
TTL: 10 * time.Second,
|
TTL: 10 * time.Second,
|
||||||
CleanupInterval: 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{
|
storeCacheableEntity := &CacheableEntity{
|
||||||
Key: "some-random-key",
|
Key: "some-random-key",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package redis
|
package rediscache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -8,16 +8,21 @@ import (
|
|||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
_cache "go.signoz.io/signoz/pkg/cache"
|
_cache "go.signoz.io/signoz/pkg/cache"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cache struct {
|
type cache struct {
|
||||||
client *redis.Client
|
client *redis.Client
|
||||||
opts *_cache.Redis
|
opts _cache.Redis
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(opts *_cache.Redis) *cache {
|
func NewFactory() factory.ProviderFactory[_cache.Cache, _cache.Config] {
|
||||||
return &cache{opts: opts}
|
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
|
// WithClient creates a new cache with the given client
|
||||||
@@ -87,11 +92,6 @@ func (c *cache) GetClient() *redis.Client {
|
|||||||
return c.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
|
// GetTTL returns the TTL for the cache entry
|
||||||
func (c *cache) GetTTL(ctx context.Context, cacheKey string) time.Duration {
|
func (c *cache) GetTTL(ctx context.Context, cacheKey string) time.Duration {
|
||||||
ttl, err := c.client.TTL(ctx, cacheKey).Result()
|
ttl, err := c.client.TTL(ctx, cacheKey).Result()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package redis
|
package rediscache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
96
pkg/cache/strategy/memory/memory.go
vendored
96
pkg/cache/strategy/memory/memory.go
vendored
@@ -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
|
|
||||||
}
|
|
||||||
90
pkg/config/conf.go
Normal file
90
pkg/config/conf.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-viper/mapstructure/v2"
|
||||||
|
"github.com/knadh/koanf/providers/confmap"
|
||||||
|
"github.com/knadh/koanf/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
KoanfDelimiter string = "::"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Conf is a wrapper around the koanf library.
|
||||||
|
type Conf struct {
|
||||||
|
*koanf.Koanf
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConf creates a new Conf instance.
|
||||||
|
func NewConf() *Conf {
|
||||||
|
return &Conf{koanf.New(KoanfDelimiter)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConfFromMap creates a new Conf instance from a map.
|
||||||
|
func NewConfFromMap(m map[string]any) (*Conf, error) {
|
||||||
|
conf := NewConf()
|
||||||
|
if err := conf.Koanf.Load(confmap.Provider(m, KoanfDelimiter), nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustNewConfFromMap creates a new Conf instance from a map.
|
||||||
|
// It panics if the conf cannot be created.
|
||||||
|
func MustNewConfFromMap(m map[string]any) *Conf {
|
||||||
|
conf, err := NewConfFromMap(m)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge merges the current configuration with the input configuration.
|
||||||
|
func (conf *Conf) Merge(input *Conf) error {
|
||||||
|
return conf.Koanf.Merge(input.Koanf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge merges the current configuration with the input configuration.
|
||||||
|
func (conf *Conf) MergeAt(input *Conf, path string) error {
|
||||||
|
return conf.Koanf.MergeAt(input.Koanf, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals the configuration at the given path into the input.
|
||||||
|
// It uses a WeaklyTypedInput to allow for more flexible unmarshalling.
|
||||||
|
func (conf *Conf) Unmarshal(path string, input any) error {
|
||||||
|
dc := &mapstructure.DecoderConfig{
|
||||||
|
TagName: "mapstructure",
|
||||||
|
WeaklyTypedInput: true,
|
||||||
|
DecodeHook: mapstructure.ComposeDecodeHookFunc(
|
||||||
|
mapstructure.StringToSliceHookFunc(","),
|
||||||
|
mapstructure.StringToTimeDurationHookFunc(),
|
||||||
|
mapstructure.TextUnmarshallerHookFunc(),
|
||||||
|
),
|
||||||
|
Result: input,
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf.Koanf.UnmarshalWithConf(path, input, koanf.UnmarshalConf{Tag: "mapstructure", DecoderConfig: dc})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the configuration at the given key.
|
||||||
|
// It decodes the input into a map as per mapstructure.Decode and then merges it into the configuration.
|
||||||
|
func (conf *Conf) Set(key string, input any) error {
|
||||||
|
m := map[string]any{}
|
||||||
|
err := mapstructure.Decode(input, &m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newConf := NewConf()
|
||||||
|
if err := newConf.Koanf.Load(confmap.Provider(m, KoanfDelimiter), nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conf.Koanf.MergeAt(newConf.Koanf, key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
38
pkg/config/conf_test.go
Normal file
38
pkg/config/conf_test.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfMerge(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
conf *Conf
|
||||||
|
input *Conf
|
||||||
|
expected *Conf
|
||||||
|
pass bool
|
||||||
|
}{
|
||||||
|
{name: "Empty", conf: NewConf(), input: NewConf(), expected: NewConf(), pass: true},
|
||||||
|
{name: "Merge", conf: MustNewConfFromMap(map[string]any{"a": "b"}), input: MustNewConfFromMap(map[string]any{"c": "d"}), expected: MustNewConfFromMap(map[string]any{"a": "b", "c": "d"}), pass: true},
|
||||||
|
{name: "NestedMerge", conf: MustNewConfFromMap(map[string]any{"a": map[string]any{"b": "v1", "c": "v2"}}), input: MustNewConfFromMap(map[string]any{"a": map[string]any{"d": "v1", "e": "v2"}}), expected: MustNewConfFromMap(map[string]any{"a": map[string]any{"b": "v1", "c": "v2", "d": "v1", "e": "v2"}}), pass: true},
|
||||||
|
{name: "Override", conf: MustNewConfFromMap(map[string]any{"a": "b"}), input: MustNewConfFromMap(map[string]any{"a": "c"}), expected: MustNewConfFromMap(map[string]any{"a": "c"}), pass: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
err := tc.conf.Merge(tc.input)
|
||||||
|
if !tc.pass {
|
||||||
|
assert.Error(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tc.expected.Raw(), tc.conf.Raw())
|
||||||
|
assert.Equal(t, tc.expected.Raw(), tc.conf.Raw())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,33 +3,34 @@ package config
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.signoz.io/signoz/pkg/cache"
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
signozconfmap "go.signoz.io/signoz/pkg/confmap"
|
|
||||||
"go.signoz.io/signoz/pkg/instrumentation"
|
|
||||||
"go.signoz.io/signoz/pkg/web"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This map contains the default values of all config structs
|
func New(ctx context.Context, resolverConfig ResolverConfig, configFactories []factory.ConfigFactory) (*Conf, error) {
|
||||||
var (
|
// Get the config from the resolver
|
||||||
defaults = map[string]signozconfmap.Config{
|
resolver, err := NewResolver(resolverConfig)
|
||||||
"instrumentation": &instrumentation.Config{},
|
|
||||||
"web": &web.Config{},
|
|
||||||
"cache": &cache.Config{},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Config defines the entire configuration of signoz.
|
|
||||||
type Config struct {
|
|
||||||
Instrumentation instrumentation.Config `mapstructure:"instrumentation"`
|
|
||||||
Web web.Config `mapstructure:"web"`
|
|
||||||
Cache cache.Config `mapstructure:"cache"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(ctx context.Context, settings ProviderSettings) (*Config, error) {
|
|
||||||
provider, err := NewProvider(settings)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider.Get(ctx)
|
resolvedConf, err := resolver.Do(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
conf := NewConf()
|
||||||
|
// Set the default configs
|
||||||
|
for _, factory := range configFactories {
|
||||||
|
c := factory.New()
|
||||||
|
if err := conf.Set(factory.Name().String(), c); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = conf.Merge(resolvedConf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"go.opentelemetry.io/collector/confmap"
|
|
||||||
"go.signoz.io/signoz/pkg/cache"
|
|
||||||
"go.signoz.io/signoz/pkg/confmap/provider/signozenvprovider"
|
|
||||||
"go.signoz.io/signoz/pkg/web"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNewWithSignozEnvProvider(t *testing.T) {
|
|
||||||
|
|
||||||
t.Setenv("SIGNOZ__WEB__PREFIX", "/web")
|
|
||||||
t.Setenv("SIGNOZ__WEB__DIRECTORY", "/build")
|
|
||||||
t.Setenv("SIGNOZ__CACHE__PROVIDER", "redis")
|
|
||||||
t.Setenv("SIGNOZ__CACHE__REDIS__HOST", "127.0.0.1")
|
|
||||||
|
|
||||||
config, err := New(context.Background(), ProviderSettings{
|
|
||||||
ResolverSettings: confmap.ResolverSettings{
|
|
||||||
URIs: []string{"signozenv:"},
|
|
||||||
ProviderFactories: []confmap.ProviderFactory{
|
|
||||||
signozenvprovider.NewFactory(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expected := &Config{
|
|
||||||
Web: web.Config{
|
|
||||||
Prefix: "/web",
|
|
||||||
Directory: "/build",
|
|
||||||
},
|
|
||||||
Cache: cache.Config{
|
|
||||||
Provider: "redis",
|
|
||||||
Memory: cache.Memory{
|
|
||||||
TTL: time.Duration(-1),
|
|
||||||
CleanupInterval: 1 * time.Minute,
|
|
||||||
},
|
|
||||||
Redis: cache.Redis{
|
|
||||||
Host: "127.0.0.1",
|
|
||||||
Port: 6379,
|
|
||||||
Password: "",
|
|
||||||
DB: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, expected, config)
|
|
||||||
}
|
|
||||||
71
pkg/config/envprovider/provider.go
Normal file
71
pkg/config/envprovider/provider.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package envprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
koanfenv "github.com/knadh/koanf/providers/env"
|
||||||
|
"go.signoz.io/signoz/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
prefix string = "SIGNOZ_"
|
||||||
|
scheme string = "env"
|
||||||
|
)
|
||||||
|
|
||||||
|
type provider struct{}
|
||||||
|
|
||||||
|
func NewFactory() config.ProviderFactory {
|
||||||
|
return config.NewProviderFactory(New)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(config config.ProviderConfig) config.Provider {
|
||||||
|
return &provider{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *provider) Scheme() string {
|
||||||
|
return scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *provider) Get(ctx context.Context, uri config.Uri) (*config.Conf, error) {
|
||||||
|
conf := config.NewConf()
|
||||||
|
err := conf.Load(
|
||||||
|
koanfenv.Provider(
|
||||||
|
prefix,
|
||||||
|
// Do not set this to `_`. The correct delimiter is being set by the custom callback provided below.
|
||||||
|
// Since this had to be passed, using `config.KoanfDelimiter` eliminates any possible side effect.
|
||||||
|
config.KoanfDelimiter,
|
||||||
|
func(s string) string {
|
||||||
|
s = strings.ToLower(strings.TrimPrefix(s, prefix))
|
||||||
|
return provider.cb(s, config.KoanfDelimiter)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
return conf, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *provider) cb(s string, delim string) string {
|
||||||
|
delims := []rune(delim)
|
||||||
|
runes := []rune(s)
|
||||||
|
result := make([]rune, 0, len(runes))
|
||||||
|
|
||||||
|
for i := 0; i < len(runes); i++ {
|
||||||
|
// Check for double underscore pattern
|
||||||
|
if i < len(runes)-1 && runes[i] == '_' && runes[i+1] == '_' {
|
||||||
|
result = append(result, '_')
|
||||||
|
i++ // Skip next underscore
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if runes[i] == '_' {
|
||||||
|
result = append(result, delims...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, runes[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(result)
|
||||||
|
}
|
||||||
78
pkg/config/envprovider/provider_test.go
Normal file
78
pkg/config/envprovider/provider_test.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package envprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.signoz.io/signoz/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetWithStrings(t *testing.T) {
|
||||||
|
t.Setenv("SIGNOZ_K1_K2", "string")
|
||||||
|
t.Setenv("SIGNOZ_K3__K4", "string")
|
||||||
|
t.Setenv("SIGNOZ_K5__K6_K7__K8", "string")
|
||||||
|
t.Setenv("SIGNOZ_K9___K10", "string")
|
||||||
|
t.Setenv("SIGNOZ_K11____K12", "string")
|
||||||
|
expected := map[string]any{
|
||||||
|
"k1::k2": "string",
|
||||||
|
"k3_k4": "string",
|
||||||
|
"k5_k6::k7_k8": "string",
|
||||||
|
"k9_::k10": "string",
|
||||||
|
"k11__k12": "string",
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := New(config.ProviderConfig{})
|
||||||
|
actual, err := provider.Get(context.Background(), config.MustNewUri("env:"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expected, actual.All())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetWithGoTypes(t *testing.T) {
|
||||||
|
t.Setenv("SIGNOZ_BOOL", "true")
|
||||||
|
t.Setenv("SIGNOZ_STRING", "string")
|
||||||
|
t.Setenv("SIGNOZ_INT", "1")
|
||||||
|
t.Setenv("SIGNOZ_SLICE", "[1,2]")
|
||||||
|
expected := map[string]any{
|
||||||
|
"bool": "true",
|
||||||
|
"int": "1",
|
||||||
|
"slice": "[1,2]",
|
||||||
|
"string": "string",
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := New(config.ProviderConfig{})
|
||||||
|
actual, err := provider.Get(context.Background(), config.MustNewUri("env:"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expected, actual.All())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetWithGoTypesWithUnmarshal(t *testing.T) {
|
||||||
|
t.Setenv("SIGNOZ_BOOL", "true")
|
||||||
|
t.Setenv("SIGNOZ_STRING", "string")
|
||||||
|
t.Setenv("SIGNOZ_INT", "1")
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
Bool bool `mapstructure:"bool"`
|
||||||
|
String string `mapstructure:"string"`
|
||||||
|
Int int `mapstructure:"int"`
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := test{
|
||||||
|
Bool: true,
|
||||||
|
String: "string",
|
||||||
|
Int: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := New(config.ProviderConfig{})
|
||||||
|
conf, err := provider.Get(context.Background(), config.MustNewUri("env:"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
actual := test{}
|
||||||
|
err = conf.Unmarshal("", &actual)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
34
pkg/config/fileprovider/provider.go
Normal file
34
pkg/config/fileprovider/provider.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package fileprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
koanfyaml "github.com/knadh/koanf/parsers/yaml"
|
||||||
|
koanffile "github.com/knadh/koanf/providers/file"
|
||||||
|
"go.signoz.io/signoz/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
scheme string = "file"
|
||||||
|
)
|
||||||
|
|
||||||
|
type provider struct{}
|
||||||
|
|
||||||
|
func NewFactory() config.ProviderFactory {
|
||||||
|
return config.NewProviderFactory(New)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(config config.ProviderConfig) config.Provider {
|
||||||
|
return &provider{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *provider) Scheme() string {
|
||||||
|
return scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *provider) Get(ctx context.Context, uri config.Uri) (*config.Conf, error) {
|
||||||
|
conf := config.NewConf()
|
||||||
|
err := conf.Load(koanffile.Provider(uri.Value()), koanfyaml.Parser())
|
||||||
|
|
||||||
|
return conf, err
|
||||||
|
}
|
||||||
68
pkg/config/fileprovider/provider_test.go
Normal file
68
pkg/config/fileprovider/provider_test.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package fileprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.signoz.io/signoz/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetWithStrings(t *testing.T) {
|
||||||
|
expected := map[string]any{
|
||||||
|
"k1::k2": "string",
|
||||||
|
"k3_k4": "string",
|
||||||
|
"k5_k6::k7_k8": "string",
|
||||||
|
"k9_::k10": "string",
|
||||||
|
"k11__k12": "string",
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := New(config.ProviderConfig{})
|
||||||
|
actual, err := provider.Get(context.Background(), config.MustNewUri("file:"+filepath.Join("testdata", "strings.yaml")))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expected, actual.All())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetWithGoTypes(t *testing.T) {
|
||||||
|
expected := map[string]any{
|
||||||
|
"bool": true,
|
||||||
|
"int": 1,
|
||||||
|
"slice": []any{1, 2},
|
||||||
|
"string": "string",
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := New(config.ProviderConfig{})
|
||||||
|
actual, err := provider.Get(context.Background(), config.MustNewUri("file:"+filepath.Join("testdata", "gotypes.yaml")))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expected, actual.All())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetWithGoTypesWithUnmarshal(t *testing.T) {
|
||||||
|
type test struct {
|
||||||
|
Bool bool `mapstructure:"bool"`
|
||||||
|
String string `mapstructure:"string"`
|
||||||
|
Int int `mapstructure:"int"`
|
||||||
|
Slice []any `mapstructure:"slice"`
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := test{
|
||||||
|
Bool: true,
|
||||||
|
String: "string",
|
||||||
|
Int: 1,
|
||||||
|
Slice: []any{1, 2},
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := New(config.ProviderConfig{})
|
||||||
|
conf, err := provider.Get(context.Background(), config.MustNewUri("file:"+filepath.Join("testdata", "gotypes.yaml")))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
actual := test{}
|
||||||
|
err = conf.Unmarshal("", &actual)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
6
pkg/config/fileprovider/testdata/gotypes.yaml
vendored
Normal file
6
pkg/config/fileprovider/testdata/gotypes.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
bool: true
|
||||||
|
string: string
|
||||||
|
int: 1
|
||||||
|
slice:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
8
pkg/config/fileprovider/testdata/strings.yaml
vendored
Normal file
8
pkg/config/fileprovider/testdata/strings.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
k1:
|
||||||
|
k2: string
|
||||||
|
k3_k4: string
|
||||||
|
k5_k6:
|
||||||
|
k7_k8: string
|
||||||
|
k9_:
|
||||||
|
k10: string
|
||||||
|
k11__k12: string
|
||||||
@@ -2,51 +2,38 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/collector/confmap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provides the configuration for signoz.
|
// NewProviderFunc is a function that creates a new provider.
|
||||||
|
type NewProviderFunc = func(ProviderConfig) Provider
|
||||||
|
|
||||||
|
// ProviderFactory is a factory that creates a new provider.
|
||||||
|
type ProviderFactory interface {
|
||||||
|
New(ProviderConfig) Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProviderFactory creates a new provider factory.
|
||||||
|
func NewProviderFactory(f NewProviderFunc) ProviderFactory {
|
||||||
|
return &providerFactory{f: f}
|
||||||
|
}
|
||||||
|
|
||||||
|
// providerFactory is a factory that implements the ProviderFactory interface.
|
||||||
|
type providerFactory struct {
|
||||||
|
f NewProviderFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new provider.
|
||||||
|
func (factory *providerFactory) New(config ProviderConfig) Provider {
|
||||||
|
return factory.f(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProviderConfig is the configuration for a provider.
|
||||||
|
type ProviderConfig struct{}
|
||||||
|
|
||||||
|
// Provider is an interface that represents a provider.
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
// Get returns the configuration, or error otherwise.
|
// Get returns the configuration for the given URI.
|
||||||
Get(ctx context.Context) (*Config, error)
|
Get(context.Context, Uri) (*Conf, error)
|
||||||
}
|
// Scheme returns the scheme of the provider.
|
||||||
|
Scheme() string
|
||||||
type provider struct {
|
|
||||||
resolver *confmap.Resolver
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProviderSettings are the settings to configure the behavior of the Provider.
|
|
||||||
type ProviderSettings struct {
|
|
||||||
// ResolverSettings are the settings to configure the behavior of the confmap.Resolver.
|
|
||||||
ResolverSettings confmap.ResolverSettings
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewProvider returns a new Provider that provides the entire configuration.
|
|
||||||
// See https://github.com/open-telemetry/opentelemetry-collector/blob/main/otelcol/configprovider.go for
|
|
||||||
// more details
|
|
||||||
func NewProvider(settings ProviderSettings) (Provider, error) {
|
|
||||||
resolver, err := confmap.NewResolver(settings.ResolverSettings)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &provider{
|
|
||||||
resolver: resolver,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *provider) Get(ctx context.Context) (*Config, error) {
|
|
||||||
conf, err := provider.resolver.Resolve(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot resolve configuration: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config, err := unmarshal(conf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot unmarshal configuration: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
87
pkg/config/resolver.go
Normal file
87
pkg/config/resolver.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ResolverConfig struct {
|
||||||
|
// Each string or `uri` must follow "<scheme>:<value>" format. This format is compatible with the URI definition
|
||||||
|
// defined at https://datatracker.ietf.org/doc/html/rfc3986".
|
||||||
|
// It is required to have at least one uri.
|
||||||
|
Uris []string
|
||||||
|
|
||||||
|
// ProviderFactories is a slice of Provider factories.
|
||||||
|
// It is required to have at least one factory.
|
||||||
|
ProviderFactories []ProviderFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
type Resolver struct {
|
||||||
|
uris []Uri
|
||||||
|
providers map[string]Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResolver(config ResolverConfig) (*Resolver, error) {
|
||||||
|
if len(config.Uris) == 0 {
|
||||||
|
return nil, errors.New("cannot build resolver, no uris have been provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.ProviderFactories) == 0 {
|
||||||
|
return nil, errors.New("cannot build resolver, no providers have been provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
uris := make([]Uri, len(config.Uris))
|
||||||
|
for i, inputUri := range config.Uris {
|
||||||
|
uri, err := NewUri(inputUri)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
uris[i] = uri
|
||||||
|
}
|
||||||
|
|
||||||
|
providers := make(map[string]Provider, len(config.ProviderFactories))
|
||||||
|
for _, factory := range config.ProviderFactories {
|
||||||
|
provider := factory.New(ProviderConfig{})
|
||||||
|
|
||||||
|
scheme := provider.Scheme()
|
||||||
|
// Check that the scheme is unique.
|
||||||
|
if _, ok := providers[scheme]; ok {
|
||||||
|
return nil, fmt.Errorf("cannot build resolver, duplicate scheme %q found", scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
providers[provider.Scheme()] = provider
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Resolver{
|
||||||
|
uris: uris,
|
||||||
|
providers: providers,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (resolver *Resolver) Do(ctx context.Context) (*Conf, error) {
|
||||||
|
conf := NewConf()
|
||||||
|
|
||||||
|
for _, uri := range resolver.uris {
|
||||||
|
currentConf, err := resolver.get(ctx, uri)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = conf.Merge(currentConf); err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot merge config: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (resolver *Resolver) get(ctx context.Context, uri Uri) (*Conf, error) {
|
||||||
|
provider, ok := resolver.providers[uri.scheme]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("cannot find provider with schema %q", uri.scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.Get(ctx, uri)
|
||||||
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/collector/confmap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// unmarshal converts a confmap.Conf into a Config struct.
|
|
||||||
// It splits the input confmap into a map of key-value pairs, fetches the corresponding
|
|
||||||
// signozconfmap.Config interface by name, merges it with the default config, validates it,
|
|
||||||
// and then creates a new confmap from the parsed map to unmarshal into the Config struct.
|
|
||||||
func unmarshal(conf *confmap.Conf) (*Config, error) {
|
|
||||||
raw := make(map[string]any)
|
|
||||||
if err := conf.Unmarshal(&raw); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed := make(map[string]any)
|
|
||||||
|
|
||||||
// To help the defaults kick in, we need iterate over the default map instead of the raw values
|
|
||||||
for k, v := range defaults {
|
|
||||||
sub, err := conf.Sub(k)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot read config for %q: %w", k, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
d := v.NewWithDefaults()
|
|
||||||
if err := sub.Unmarshal(&d); err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot merge config for %q: %w", k, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = d.Validate()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to validate config for for %q: %w", k, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed[k] = d
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedConf := confmap.NewFromStringMap(parsed)
|
|
||||||
config := new(Config)
|
|
||||||
err := parsedConf.Unmarshal(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot unmarshal config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"go.opentelemetry.io/collector/confmap"
|
|
||||||
"go.signoz.io/signoz/pkg/instrumentation"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUnmarshalForInstrumentation(t *testing.T) {
|
|
||||||
input := confmap.NewFromStringMap(
|
|
||||||
map[string]any{
|
|
||||||
"instrumentation": map[string]any{
|
|
||||||
"logs": map[string]bool{
|
|
||||||
"enabled": true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
expected := &Config{
|
|
||||||
Instrumentation: instrumentation.Config{
|
|
||||||
Logs: instrumentation.LogsConfig{
|
|
||||||
Enabled: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
cfg, err := unmarshal(input)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, expected.Instrumentation, cfg.Instrumentation)
|
|
||||||
}
|
|
||||||
46
pkg/config/uri.go
Normal file
46
pkg/config/uri.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// uriRegex is a regex that matches the URI format. It complies with the URI definition defined at https://datatracker.ietf.org/doc/html/rfc3986.
|
||||||
|
// The format is "<scheme>:<value>".
|
||||||
|
uriRegex = regexp.MustCompile(`(?s:^(?P<Scheme>[A-Za-z][A-Za-z0-9+.-]+):(?P<Value>.*)$)`)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Uri struct {
|
||||||
|
scheme string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUri(input string) (Uri, error) {
|
||||||
|
submatches := uriRegex.FindStringSubmatch(input)
|
||||||
|
|
||||||
|
if len(submatches) != 3 {
|
||||||
|
return Uri{}, fmt.Errorf("invalid uri: %q", input)
|
||||||
|
}
|
||||||
|
return Uri{
|
||||||
|
scheme: submatches[1],
|
||||||
|
value: submatches[2],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustNewUri(input string) Uri {
|
||||||
|
uri, err := NewUri(input)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri
|
||||||
|
}
|
||||||
|
|
||||||
|
func (uri Uri) Scheme() string {
|
||||||
|
return uri.scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (uri Uri) Value() string {
|
||||||
|
return uri.value
|
||||||
|
}
|
||||||
35
pkg/config/uri_test.go
Normal file
35
pkg/config/uri_test.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewUri(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
input string
|
||||||
|
expected Uri
|
||||||
|
pass bool
|
||||||
|
}{
|
||||||
|
{input: "file:/path/1", expected: Uri{scheme: "file", value: "/path/1"}, pass: true},
|
||||||
|
{input: "file:", expected: Uri{scheme: "file", value: ""}, pass: true},
|
||||||
|
{input: "env:", expected: Uri{scheme: "env", value: ""}, pass: true},
|
||||||
|
{input: "scheme", expected: Uri{}, pass: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
uri, err := NewUri(tc.input)
|
||||||
|
if !tc.pass {
|
||||||
|
assert.Error(t, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotPanics(t, func() { MustNewUri(tc.input) })
|
||||||
|
assert.Equal(t, tc.expected, uri)
|
||||||
|
assert.Equal(t, tc.expected.Scheme(), uri.scheme)
|
||||||
|
assert.Equal(t, tc.expected.Value(), uri.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package confmap
|
|
||||||
|
|
||||||
// Config is an interface that defines methods for creating and validating configurations.
|
|
||||||
type Config interface {
|
|
||||||
// New creates a new instance of the configuration with default values.
|
|
||||||
NewWithDefaults() Config
|
|
||||||
// Validate the configuration and returns an error if invalid.
|
|
||||||
Validate() error
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
// Package confmap is a wrapper on top of the confmap defined here:
|
|
||||||
// https://github.com/open-telemetry/opentelemetry-collector/blob/main/otelcol/configprovider.go/
|
|
||||||
package confmap
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
package signozenvprovider
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/collector/confmap"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
schemeName string = "signozenv"
|
|
||||||
envPrefix string = "signoz"
|
|
||||||
separator string = "__"
|
|
||||||
envPrefixWithOneSeparator string = "signoz_"
|
|
||||||
envRegexString string = `^[a-zA-Z][a-zA-Z0-9_]*$`
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
envRegex = regexp.MustCompile(envRegexString)
|
|
||||||
)
|
|
||||||
|
|
||||||
type provider struct {
|
|
||||||
logger *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFactory returns a factory for a confmap.Provider that reads the configuration from the environment.
|
|
||||||
// All variables starting with `SIGNOZ__` are read from the environment.
|
|
||||||
// The separator is `__` (2 underscores) in order to incorporate env variables having keys with a single `_`
|
|
||||||
func NewFactory() confmap.ProviderFactory {
|
|
||||||
return confmap.NewProviderFactory(newProvider)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProvider(settings confmap.ProviderSettings) confmap.Provider {
|
|
||||||
return &provider{
|
|
||||||
logger: settings.Logger,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *provider) Retrieve(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) {
|
|
||||||
if !strings.HasPrefix(uri, schemeName+":") {
|
|
||||||
return nil, fmt.Errorf("%q uri is not supported by %q provider", uri, schemeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and Sort environment variables for consistent output
|
|
||||||
envvars := os.Environ()
|
|
||||||
sort.Strings(envvars)
|
|
||||||
|
|
||||||
// Create a map m containing key value pairs
|
|
||||||
m := make(map[string]any)
|
|
||||||
for _, envvar := range envvars {
|
|
||||||
parts := strings.SplitN(envvar, "=", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
key := strings.ToLower(parts[0])
|
|
||||||
val := parts[1]
|
|
||||||
|
|
||||||
if strings.HasPrefix(key, envPrefixWithOneSeparator) {
|
|
||||||
// Remove the envPrefix from the key
|
|
||||||
key = strings.Replace(key, envPrefix+separator, "", 1)
|
|
||||||
|
|
||||||
// Check whether the resulting key matches with the regex
|
|
||||||
if !envRegex.MatchString(key) {
|
|
||||||
provider.logger.Warn("Configuration references invalid environment variable key", zap.String("key", key))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert key into yaml format
|
|
||||||
key = strings.ToLower(strings.ReplaceAll(key, separator, confmap.KeyDelimiter))
|
|
||||||
m[key] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out, err := yaml.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return confmap.NewRetrievedFromYAML(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*provider) Scheme() string {
|
|
||||||
return schemeName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*provider) Shutdown(context.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package signozenvprovider
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"go.opentelemetry.io/collector/confmap"
|
|
||||||
"go.opentelemetry.io/collector/confmap/confmaptest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func createProvider() confmap.Provider {
|
|
||||||
return NewFactory().Create(confmaptest.NewNopProviderSettings())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateProviderScheme(t *testing.T) {
|
|
||||||
assert.NoError(t, confmaptest.ValidateProviderScheme(createProvider()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRetrieve(t *testing.T) {
|
|
||||||
t.Setenv("SIGNOZ__STORAGE__DSN", "localhost:9000")
|
|
||||||
t.Setenv("SIGNOZ__SIGNOZ_ENABLED", "true")
|
|
||||||
t.Setenv("SIGNOZ__INSTRUMENTATION__LOGS__ENABLED", "true")
|
|
||||||
expected := confmap.NewFromStringMap(map[string]any{
|
|
||||||
"storage::dsn": "localhost:9000",
|
|
||||||
"signoz_enabled": "true",
|
|
||||||
"instrumentation::logs::enabled": "true",
|
|
||||||
})
|
|
||||||
|
|
||||||
signoz := createProvider()
|
|
||||||
retrieved, err := signoz.Retrieve(context.Background(), schemeName+":", nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
actual, err := retrieved.AsConf()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, expected.ToStringMap(), actual.ToStringMap())
|
|
||||||
assert.NoError(t, signoz.Shutdown(context.Background()))
|
|
||||||
}
|
|
||||||
37
pkg/factory/config.go
Normal file
37
pkg/factory/config.go
Normal file
@@ -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}
|
||||||
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
package registry
|
package factorytest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ NamedService = (*httpService)(nil)
|
var _ factory.Service = (*httpService)(nil)
|
||||||
|
|
||||||
type httpService struct {
|
type httpService struct {
|
||||||
Listener net.Listener
|
Listener net.Listener
|
||||||
@@ -14,15 +16,15 @@ type httpService struct {
|
|||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHttpService(name string) (*httpService, error) {
|
func NewHttpService(name string) (*httpService, error) {
|
||||||
return &httpService{
|
return &httpService{
|
||||||
name: name,
|
name: name,
|
||||||
Server: &http.Server{},
|
Server: &http.Server{},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service *httpService) Name() string {
|
func (service *httpService) Name() factory.Name {
|
||||||
return service.name
|
return factory.MustNewName(service.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service *httpService) Start(ctx context.Context) error {
|
func (service *httpService) Start(ctx context.Context) error {
|
||||||
38
pkg/factory/name.go
Normal file
38
pkg/factory/name.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
64
pkg/factory/named.go
Normal file
64
pkg/factory/named.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
48
pkg/factory/provider.go
Normal file
48
pkg/factory/provider.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package registry
|
package factory
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
@@ -8,9 +8,3 @@ type Service interface {
|
|||||||
// Stops a service.
|
// Stops a service.
|
||||||
Stop(context.Context) error
|
Stop(context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type NamedService interface {
|
|
||||||
// Identifier of a service. It should be unique across all services.
|
|
||||||
Name() string
|
|
||||||
Service
|
|
||||||
}
|
|
||||||
58
pkg/factory/setting.go
Normal file
58
pkg/factory/setting.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScopedProviderSettings interface {
|
||||||
|
Logger() sdklog.Logger
|
||||||
|
ZapLogger() *zap.Logger
|
||||||
|
Meter() sdkmetric.Meter
|
||||||
|
Tracer() sdktrace.Tracer
|
||||||
|
}
|
||||||
|
|
||||||
|
type scoped struct {
|
||||||
|
logger sdklog.Logger
|
||||||
|
zapLogger *zap.Logger
|
||||||
|
meter sdkmetric.Meter
|
||||||
|
tracer sdktrace.Tracer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewScopedProviderSettings(settings ProviderSettings, pkgName string) *scoped {
|
||||||
|
return &scoped{
|
||||||
|
logger: settings.LoggerProvider.Logger(pkgName),
|
||||||
|
zapLogger: settings.ZapLogger.Named(pkgName),
|
||||||
|
meter: settings.MeterProvider.Meter(pkgName),
|
||||||
|
tracer: settings.TracerProvider.Tracer(pkgName),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *scoped) Logger() sdklog.Logger {
|
||||||
|
return s.logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *scoped) ZapLogger() *zap.Logger {
|
||||||
|
return s.zapLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *scoped) Meter() sdkmetric.Meter {
|
||||||
|
return s.meter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *scoped) Tracer() sdktrace.Tracer {
|
||||||
|
return s.tracer
|
||||||
|
}
|
||||||
@@ -1,12 +1,5 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
|
||||||
"go.signoz.io/signoz/pkg/confmap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Config satisfies the confmap.Config interface
|
|
||||||
var _ confmap.Config = (*Config)(nil)
|
|
||||||
|
|
||||||
// Config holds the configuration for http.
|
// Config holds the configuration for http.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
//Address specifies the TCP address for the server to listen on, in the form "host:port".
|
//Address specifies the TCP address for the server to listen on, in the form "host:port".
|
||||||
@@ -15,7 +8,7 @@ type Config struct {
|
|||||||
Address string `mapstructure:"address"`
|
Address string `mapstructure:"address"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) NewWithDefaults() confmap.Config {
|
func (c *Config) NewWithDefaults() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
Address: "0.0.0.0:8080",
|
Address: "0.0.0.0:8080",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,21 +6,21 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.signoz.io/signoz/pkg/registry"
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ registry.NamedService = (*Server)(nil)
|
var _ factory.Service = (*Server)(nil)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
srv *http.Server
|
srv *http.Server
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
handler http.Handler
|
handler http.Handler
|
||||||
cfg Config
|
cfg Config
|
||||||
name string
|
name factory.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(logger *zap.Logger, name string, cfg Config, handler http.Handler) (*Server, error) {
|
func New(logger *zap.Logger, name factory.Name, cfg Config, handler http.Handler) (*Server, error) {
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
return nil, fmt.Errorf("cannot build http server, handler is required")
|
return nil, fmt.Errorf("cannot build http server, handler is required")
|
||||||
}
|
}
|
||||||
@@ -29,10 +29,6 @@ func New(logger *zap.Logger, name string, cfg Config, handler http.Handler) (*Se
|
|||||||
return nil, fmt.Errorf("cannot build http server, logger is required")
|
return nil, fmt.Errorf("cannot build http server, logger is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == "" {
|
|
||||||
return nil, fmt.Errorf("cannot build http server, name is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: cfg.Address,
|
Addr: cfg.Address,
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
@@ -50,7 +46,7 @@ func New(logger *zap.Logger, name string, cfg Config, handler http.Handler) (*Se
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) Name() string {
|
func (server *Server) Name() factory.Name {
|
||||||
return server.name
|
return server.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,10 @@ package instrumentation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
contribsdkconfig "go.opentelemetry.io/contrib/config"
|
contribsdkconfig "go.opentelemetry.io/contrib/config"
|
||||||
"go.signoz.io/signoz/pkg/confmap"
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config satisfies the confmap.Config interface
|
|
||||||
var _ confmap.Config = (*Config)(nil)
|
|
||||||
|
|
||||||
// Config holds the configuration for all instrumentation components.
|
// Config holds the configuration for all instrumentation components.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Logs LogsConfig `mapstructure:"logs"`
|
Logs LogsConfig `mapstructure:"logs"`
|
||||||
@@ -24,39 +21,69 @@ type Resource struct {
|
|||||||
|
|
||||||
// LogsConfig holds the configuration for the logging component.
|
// LogsConfig holds the configuration for the logging component.
|
||||||
type LogsConfig struct {
|
type LogsConfig struct {
|
||||||
Enabled bool `mapstructure:"enabled"`
|
Enabled bool `mapstructure:"enabled"`
|
||||||
Level zapcore.Level `mapstructure:"level"`
|
Level zapcore.Level `mapstructure:"level"`
|
||||||
contribsdkconfig.LoggerProvider `mapstructure:",squash"`
|
Processors LogsProcessors `mapstructure:"processors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogsProcessors struct {
|
||||||
|
Batch contribsdkconfig.BatchLogRecordProcessor `mapstructure:"batch"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TracesConfig holds the configuration for the tracing component.
|
// TracesConfig holds the configuration for the tracing component.
|
||||||
type TracesConfig struct {
|
type TracesConfig struct {
|
||||||
Enabled bool `mapstructure:"enabled"`
|
Enabled bool `mapstructure:"enabled"`
|
||||||
contribsdkconfig.TracerProvider `mapstructure:",squash"`
|
Processors TracesProcessors `mapstructure:"processors"`
|
||||||
|
Sampler contribsdkconfig.Sampler `mapstructure:"sampler"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TracesProcessors struct {
|
||||||
|
Batch contribsdkconfig.BatchSpanProcessor `mapstructure:"batch"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetricsConfig holds the configuration for the metrics component.
|
// MetricsConfig holds the configuration for the metrics component.
|
||||||
type MetricsConfig struct {
|
type MetricsConfig struct {
|
||||||
Enabled bool `mapstructure:"enabled"`
|
Enabled bool `mapstructure:"enabled"`
|
||||||
contribsdkconfig.MeterProvider `mapstructure:",squash"`
|
Readers MetricsReaders `mapstructure:"readers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) NewWithDefaults() confmap.Config {
|
type MetricsReaders struct {
|
||||||
return &Config{
|
Pull contribsdkconfig.PullMetricReader `mapstructure:"pull"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfigFactory() factory.ConfigFactory {
|
||||||
|
return factory.NewConfigFactory(factory.MustNewName("instrumentation"), newConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConfig() factory.Config {
|
||||||
|
host := "0.0.0.0"
|
||||||
|
port := 9090
|
||||||
|
|
||||||
|
return Config{
|
||||||
Logs: LogsConfig{
|
Logs: LogsConfig{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
Level: zapcore.InfoLevel,
|
Level: zapcore.DebugLevel,
|
||||||
},
|
},
|
||||||
Traces: TracesConfig{
|
Traces: TracesConfig{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
},
|
},
|
||||||
Metrics: MetricsConfig{
|
Metrics: MetricsConfig{
|
||||||
Enabled: false,
|
Enabled: true,
|
||||||
|
Readers: MetricsReaders{
|
||||||
|
Pull: contribsdkconfig.PullMetricReader{
|
||||||
|
Exporter: contribsdkconfig.MetricExporter{
|
||||||
|
Prometheus: &contribsdkconfig.Prometheus{
|
||||||
|
Host: &host,
|
||||||
|
Port: &port,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Validate() error {
|
func (c Config) Validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package instrumentation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
contribsdkconfig "go.opentelemetry.io/contrib/config"
|
contribsdkconfig "go.opentelemetry.io/contrib/config"
|
||||||
sdklog "go.opentelemetry.io/otel/log"
|
sdklog "go.opentelemetry.io/otel/log"
|
||||||
@@ -10,21 +9,31 @@ import (
|
|||||||
sdkresource "go.opentelemetry.io/otel/sdk/resource"
|
sdkresource "go.opentelemetry.io/otel/sdk/resource"
|
||||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||||
sdktrace "go.opentelemetry.io/otel/trace"
|
sdktrace "go.opentelemetry.io/otel/trace"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
"go.signoz.io/signoz/pkg/version"
|
"go.signoz.io/signoz/pkg/version"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Instrumentation holds the core components for application instrumentation.
|
var _ factory.Service = (*SDK)(nil)
|
||||||
type Instrumentation struct {
|
var _ Instrumentation = (*SDK)(nil)
|
||||||
LoggerProvider sdklog.LoggerProvider
|
|
||||||
Logger *zap.Logger
|
type Instrumentation interface {
|
||||||
MeterProvider sdkmetric.MeterProvider
|
LoggerProvider() sdklog.LoggerProvider
|
||||||
TracerProvider sdktrace.TracerProvider
|
Logger() *zap.Logger
|
||||||
|
MeterProvider() sdkmetric.MeterProvider
|
||||||
|
TracerProvider() sdktrace.TracerProvider
|
||||||
|
ToProviderSettings() factory.ProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
// SDK holds the core components for application instrumentation.
|
||||||
|
type SDK struct {
|
||||||
|
sdk contribsdkconfig.SDK
|
||||||
|
logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Instrumentation instance with configured providers.
|
// New creates a new Instrumentation instance with configured providers.
|
||||||
// It sets up logging, tracing, and metrics based on the provided configuration.
|
// 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) (*SDK, error) {
|
||||||
// Set default resource attributes if not provided
|
// Set default resource attributes if not provided
|
||||||
if cfg.Resource.Attributes == nil {
|
if cfg.Resource.Attributes == nil {
|
||||||
cfg.Resource.Attributes = map[string]any{
|
cfg.Resource.Attributes = map[string]any{
|
||||||
@@ -55,29 +64,86 @@ func New(ctx context.Context, build version.Build, cfg Config) (*Instrumentation
|
|||||||
SchemaUrl: &sch,
|
SchemaUrl: &sch,
|
||||||
}
|
}
|
||||||
|
|
||||||
loggerProvider, err := newLoggerProvider(ctx, cfg, configResource)
|
var loggerProvider *contribsdkconfig.LoggerProvider
|
||||||
if err != nil {
|
if cfg.Logs.Enabled {
|
||||||
return nil, fmt.Errorf("cannot create logger provider: %w", err)
|
loggerProvider = &contribsdkconfig.LoggerProvider{
|
||||||
|
Processors: []contribsdkconfig.LogRecordProcessor{
|
||||||
|
{Batch: &cfg.Logs.Processors.Batch},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracerProvider, err := newTracerProvider(ctx, cfg, configResource)
|
var tracerProvider *contribsdkconfig.TracerProvider
|
||||||
if err != nil {
|
if cfg.Traces.Enabled {
|
||||||
return nil, fmt.Errorf("cannot create tracer provider: %w", err)
|
tracerProvider = &contribsdkconfig.TracerProvider{
|
||||||
|
Processors: []contribsdkconfig.SpanProcessor{
|
||||||
|
{Batch: &cfg.Traces.Processors.Batch},
|
||||||
|
},
|
||||||
|
Sampler: &cfg.Traces.Sampler,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
meterProvider, err := newMeterProvider(ctx, cfg, configResource)
|
var meterProvider *contribsdkconfig.MeterProvider
|
||||||
if err != nil {
|
if cfg.Metrics.Enabled {
|
||||||
return nil, fmt.Errorf("cannot create meter provider: %w", err)
|
meterProvider = &contribsdkconfig.MeterProvider{
|
||||||
|
Readers: []contribsdkconfig.MetricReader{
|
||||||
|
{Pull: &cfg.Metrics.Readers.Pull},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Instrumentation{
|
sdk, err := contribsdkconfig.NewSDK(
|
||||||
LoggerProvider: loggerProvider,
|
contribsdkconfig.WithContext(ctx),
|
||||||
TracerProvider: tracerProvider,
|
contribsdkconfig.WithOpenTelemetryConfiguration(contribsdkconfig.OpenTelemetryConfiguration{
|
||||||
MeterProvider: meterProvider,
|
LoggerProvider: loggerProvider,
|
||||||
Logger: newLogger(cfg, loggerProvider),
|
TracerProvider: tracerProvider,
|
||||||
|
MeterProvider: meterProvider,
|
||||||
|
Resource: &configResource,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SDK{
|
||||||
|
sdk: sdk,
|
||||||
|
logger: newLogger(cfg, sdk.LoggerProvider()),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *SDK) Start(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *SDK) Stop(ctx context.Context) error {
|
||||||
|
return i.sdk.Shutdown(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *SDK) LoggerProvider() sdklog.LoggerProvider {
|
||||||
|
return i.sdk.LoggerProvider()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *SDK) Logger() *zap.Logger {
|
||||||
|
return i.logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *SDK) MeterProvider() sdkmetric.MeterProvider {
|
||||||
|
return i.sdk.MeterProvider()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *SDK) TracerProvider() sdktrace.TracerProvider {
|
||||||
|
return i.sdk.TracerProvider()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *SDK) ToProviderSettings() factory.ProviderSettings {
|
||||||
|
return factory.ProviderSettings{
|
||||||
|
LoggerProvider: i.LoggerProvider(),
|
||||||
|
ZapLogger: i.Logger(),
|
||||||
|
MeterProvider: i.MeterProvider(),
|
||||||
|
TracerProvider: i.TracerProvider(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// attributes merges the input attributes with the resource attributes.
|
// attributes merges the input attributes with the resource attributes.
|
||||||
func attributes(input map[string]any, resource *sdkresource.Resource) map[string]any {
|
func attributes(input map[string]any, resource *sdkresource.Resource) map[string]any {
|
||||||
output := make(map[string]any)
|
output := make(map[string]any)
|
||||||
|
|||||||
54
pkg/instrumentation/instrumentationtest/instrumentation.go
Normal file
54
pkg/instrumentation/instrumentationtest/instrumentation.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package instrumentationtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdklog "go.opentelemetry.io/otel/log"
|
||||||
|
nooplog "go.opentelemetry.io/otel/log/noop"
|
||||||
|
sdkmetric "go.opentelemetry.io/otel/metric"
|
||||||
|
noopmetric "go.opentelemetry.io/otel/metric/noop"
|
||||||
|
sdktrace "go.opentelemetry.io/otel/trace"
|
||||||
|
nooptrace "go.opentelemetry.io/otel/trace/noop"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/instrumentation"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type noopInstrumentation struct {
|
||||||
|
logger *zap.Logger
|
||||||
|
loggerProvider sdklog.LoggerProvider
|
||||||
|
meterProvider sdkmetric.MeterProvider
|
||||||
|
tracerProvider sdktrace.TracerProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() instrumentation.Instrumentation {
|
||||||
|
return &noopInstrumentation{
|
||||||
|
logger: zap.NewNop(),
|
||||||
|
loggerProvider: nooplog.NewLoggerProvider(),
|
||||||
|
meterProvider: noopmetric.NewMeterProvider(),
|
||||||
|
tracerProvider: nooptrace.NewTracerProvider(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *noopInstrumentation) LoggerProvider() sdklog.LoggerProvider {
|
||||||
|
return i.loggerProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *noopInstrumentation) Logger() *zap.Logger {
|
||||||
|
return i.logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *noopInstrumentation) MeterProvider() sdkmetric.MeterProvider {
|
||||||
|
return i.meterProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *noopInstrumentation) TracerProvider() sdktrace.TracerProvider {
|
||||||
|
return i.tracerProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *noopInstrumentation) ToProviderSettings() factory.ProviderSettings {
|
||||||
|
return factory.ProviderSettings{
|
||||||
|
LoggerProvider: i.LoggerProvider(),
|
||||||
|
ZapLogger: i.Logger(),
|
||||||
|
MeterProvider: i.MeterProvider(),
|
||||||
|
TracerProvider: i.TracerProvider(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,38 +1,14 @@
|
|||||||
package instrumentation
|
package instrumentation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"go.opentelemetry.io/contrib/bridges/otelzap"
|
"go.opentelemetry.io/contrib/bridges/otelzap"
|
||||||
contribsdkconfig "go.opentelemetry.io/contrib/config"
|
|
||||||
sdklog "go.opentelemetry.io/otel/log"
|
sdklog "go.opentelemetry.io/otel/log"
|
||||||
nooplog "go.opentelemetry.io/otel/log/noop"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
|
|
||||||
// newLoggerProvider creates a new logger provider based on the configuration.
|
|
||||||
// If logging is disabled, it returns a no-op logger provider.
|
|
||||||
func newLoggerProvider(ctx context.Context, cfg Config, cfgResource contribsdkconfig.Resource) (sdklog.LoggerProvider, error) {
|
|
||||||
if !cfg.Logs.Enabled {
|
|
||||||
return nooplog.NewLoggerProvider(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
sdk, err := contribsdkconfig.NewSDK(
|
|
||||||
contribsdkconfig.WithContext(ctx),
|
|
||||||
contribsdkconfig.WithOpenTelemetryConfiguration(contribsdkconfig.OpenTelemetryConfiguration{
|
|
||||||
LoggerProvider: &cfg.Logs.LoggerProvider,
|
|
||||||
Resource: &cfgResource,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sdk.LoggerProvider(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newLogger creates a new Zap logger with the configured level and output.
|
// newLogger creates a new Zap logger with the configured level and output.
|
||||||
// It combines a JSON encoder for stdout and an OpenTelemetry bridge.
|
// It combines a JSON encoder for stdout and an OpenTelemetry bridge.
|
||||||
func newLogger(cfg Config, provider sdklog.LoggerProvider) *zap.Logger {
|
func newLogger(cfg Config, provider sdklog.LoggerProvider) *zap.Logger {
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
package instrumentation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
contribsdkconfig "go.opentelemetry.io/contrib/config"
|
|
||||||
sdkmetric "go.opentelemetry.io/otel/metric"
|
|
||||||
noopmetric "go.opentelemetry.io/otel/metric/noop"
|
|
||||||
)
|
|
||||||
|
|
||||||
// newMeterProvider creates a new meter provider based on the configuration.
|
|
||||||
// If metrics are disabled, it returns a no-op meter provider.
|
|
||||||
func newMeterProvider(ctx context.Context, cfg Config, cfgResource contribsdkconfig.Resource) (sdkmetric.MeterProvider, error) {
|
|
||||||
if !cfg.Metrics.Enabled {
|
|
||||||
return noopmetric.NewMeterProvider(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
sdk, err := contribsdkconfig.NewSDK(
|
|
||||||
contribsdkconfig.WithContext(ctx),
|
|
||||||
contribsdkconfig.WithOpenTelemetryConfiguration(contribsdkconfig.OpenTelemetryConfiguration{
|
|
||||||
MeterProvider: &cfg.Metrics.MeterProvider,
|
|
||||||
Resource: &cfgResource,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sdk.MeterProvider(), nil
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package instrumentation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
contribsdkconfig "go.opentelemetry.io/contrib/config"
|
|
||||||
sdktrace "go.opentelemetry.io/otel/trace"
|
|
||||||
nooptrace "go.opentelemetry.io/otel/trace/noop"
|
|
||||||
)
|
|
||||||
|
|
||||||
// newTracerProvider creates a new tracer provider based on the configuration.
|
|
||||||
// If tracing is disabled, it returns a no-op tracer provider.
|
|
||||||
func newTracerProvider(ctx context.Context, cfg Config, cfgResource contribsdkconfig.Resource) (sdktrace.TracerProvider, error) {
|
|
||||||
if !cfg.Traces.Enabled {
|
|
||||||
return nooptrace.NewTracerProvider(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
sdk, err := contribsdkconfig.NewSDK(
|
|
||||||
contribsdkconfig.WithContext(ctx),
|
|
||||||
contribsdkconfig.WithOpenTelemetryConfiguration(contribsdkconfig.OpenTelemetryConfiguration{
|
|
||||||
TracerProvider: &cfg.Traces.TracerProvider,
|
|
||||||
Resource: &cfgResource,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sdk.TracerProvider(), nil
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.signoz.io/signoz/pkg/query-service/agentConf/sqlite"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
@@ -19,15 +18,6 @@ type Repo struct {
|
|||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repo) initDB(engine string) error {
|
|
||||||
switch engine {
|
|
||||||
case "sqlite3", "sqlite":
|
|
||||||
return sqlite.InitDB(r.db)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported db")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repo) GetConfigHistory(
|
func (r *Repo) GetConfigHistory(
|
||||||
ctx context.Context, typ ElementTypeDef, limit int,
|
ctx context.Context, typ ElementTypeDef, limit int,
|
||||||
) ([]ConfigVersion, *model.ApiError) {
|
) ([]ConfigVersion, *model.ApiError) {
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ type Manager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ManagerOptions struct {
|
type ManagerOptions struct {
|
||||||
DB *sqlx.DB
|
DB *sqlx.DB
|
||||||
DBEngine string
|
|
||||||
|
|
||||||
// When acting as opamp.AgentConfigProvider, agent conf recommendations are
|
// When acting as opamp.AgentConfigProvider, agent conf recommendations are
|
||||||
// applied to the base conf in the order the features have been specified here.
|
// applied to the base conf in the order the features have been specified here.
|
||||||
@@ -66,10 +65,6 @@ func Initiate(options *ManagerOptions) (*Manager, error) {
|
|||||||
configSubscribers: map[string]func(){},
|
configSubscribers: map[string]func(){},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := m.initDB(options.DBEngine)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not init agentConf db")
|
|
||||||
}
|
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
package sqlite
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
)
|
|
||||||
|
|
||||||
func InitDB(db *sqlx.DB) error {
|
|
||||||
var err error
|
|
||||||
if db == nil {
|
|
||||||
return fmt.Errorf("invalid db connection")
|
|
||||||
}
|
|
||||||
|
|
||||||
table_schema := `CREATE TABLE IF NOT EXISTS agent_config_versions(
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
created_by TEXT,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_by TEXT,
|
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
version INTEGER DEFAULT 1,
|
|
||||||
active int,
|
|
||||||
is_valid int,
|
|
||||||
disabled int,
|
|
||||||
element_type VARCHAR(120) NOT NULL,
|
|
||||||
deploy_status VARCHAR(80) NOT NULL DEFAULT 'DIRTY',
|
|
||||||
deploy_sequence INTEGER,
|
|
||||||
deploy_result TEXT,
|
|
||||||
last_hash TEXT,
|
|
||||||
last_config TEXT,
|
|
||||||
UNIQUE(element_type, version)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS agent_config_versions_u1
|
|
||||||
ON agent_config_versions(element_type, version);
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS agent_config_versions_nu1
|
|
||||||
ON agent_config_versions(last_hash);
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS agent_config_elements(
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
created_by TEXT,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_by TEXT,
|
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
element_id TEXT NOT NULL,
|
|
||||||
element_type VARCHAR(120) NOT NULL,
|
|
||||||
version_id TEXT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS agent_config_elements_u1
|
|
||||||
ON agent_config_elements(version_id, element_id, element_type);
|
|
||||||
|
|
||||||
`
|
|
||||||
|
|
||||||
_, err = db.Exec(table_schema)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "Error in creating agent config tables")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
func TestRegenerateConnectionUrlWithUpdatedConfig(t *testing.T) {
|
func TestRegenerateConnectionUrlWithUpdatedConfig(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
testDB, _ := utils.NewTestSqliteDB(t)
|
testDB := utils.NewQueryServiceDBForTests(t)
|
||||||
controller, err := NewController(testDB)
|
controller, err := NewController(testDB)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ func TestRegenerateConnectionUrlWithUpdatedConfig(t *testing.T) {
|
|||||||
|
|
||||||
func TestAgentCheckIns(t *testing.T) {
|
func TestAgentCheckIns(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
testDB, _ := utils.NewTestSqliteDB(t)
|
testDB := utils.NewQueryServiceDBForTests(t)
|
||||||
controller, err := NewController(testDB)
|
controller, err := NewController(testDB)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ func TestAgentCheckIns(t *testing.T) {
|
|||||||
|
|
||||||
func TestCantDisconnectNonExistentAccount(t *testing.T) {
|
func TestCantDisconnectNonExistentAccount(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
testDB, _ := utils.NewTestSqliteDB(t)
|
testDB := utils.NewQueryServiceDBForTests(t)
|
||||||
controller, err := NewController(testDB)
|
controller, err := NewController(testDB)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
|
|||||||
@@ -37,42 +37,11 @@ type cloudProviderAccountsRepository interface {
|
|||||||
func newCloudProviderAccountsRepository(db *sqlx.DB) (
|
func newCloudProviderAccountsRepository(db *sqlx.DB) (
|
||||||
*cloudProviderAccountsSQLRepository, error,
|
*cloudProviderAccountsSQLRepository, error,
|
||||||
) {
|
) {
|
||||||
if err := InitSqliteDBIfNeeded(db); err != nil {
|
|
||||||
return nil, fmt.Errorf("could not init sqlite DB for cloudintegrations: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cloudProviderAccountsSQLRepository{
|
return &cloudProviderAccountsSQLRepository{
|
||||||
db: db,
|
db: db,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitSqliteDBIfNeeded(db *sqlx.DB) error {
|
|
||||||
if db == nil {
|
|
||||||
return fmt.Errorf("db is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
createTablesStatements := `
|
|
||||||
CREATE TABLE IF NOT EXISTS cloud_integrations_accounts(
|
|
||||||
cloud_provider TEXT NOT NULL,
|
|
||||||
id TEXT NOT NULL,
|
|
||||||
config_json TEXT,
|
|
||||||
cloud_account_id TEXT,
|
|
||||||
last_agent_report_json TEXT,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
||||||
removed_at TIMESTAMP,
|
|
||||||
UNIQUE(cloud_provider, id)
|
|
||||||
)
|
|
||||||
`
|
|
||||||
_, err := db.Exec(createTablesStatements)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"could not ensure cloud provider integrations schema in sqlite DB: %w", err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type cloudProviderAccountsSQLRepository struct {
|
type cloudProviderAccountsSQLRepository struct {
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,126 +35,10 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// InitDB sets up setting up the connection pool global variable.
|
// InitDB sets up setting up the connection pool global variable.
|
||||||
func InitDB(dataSourceName string) (*sqlx.DB, error) {
|
// @deprecated
|
||||||
var err error
|
func InitDB(inputDB *sqlx.DB) {
|
||||||
|
db = inputDB
|
||||||
db, err = sqlx.Open("sqlite3", dataSourceName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
table_schema := `CREATE TABLE IF NOT EXISTS dashboards (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
uuid TEXT NOT NULL UNIQUE,
|
|
||||||
created_at datetime NOT NULL,
|
|
||||||
updated_at datetime NOT NULL,
|
|
||||||
data TEXT NOT NULL
|
|
||||||
);`
|
|
||||||
|
|
||||||
_, err = db.Exec(table_schema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error in creating dashboard table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
table_schema = `CREATE TABLE IF NOT EXISTS rules (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
updated_at datetime NOT NULL,
|
|
||||||
deleted INTEGER DEFAULT 0,
|
|
||||||
data TEXT NOT NULL
|
|
||||||
);`
|
|
||||||
|
|
||||||
_, err = db.Exec(table_schema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error in creating rules table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
table_schema = `CREATE TABLE IF NOT EXISTS notification_channels (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
created_at datetime NOT NULL,
|
|
||||||
updated_at datetime NOT NULL,
|
|
||||||
name TEXT NOT NULL UNIQUE,
|
|
||||||
type TEXT NOT NULL,
|
|
||||||
deleted INTEGER DEFAULT 0,
|
|
||||||
data TEXT NOT NULL
|
|
||||||
);`
|
|
||||||
|
|
||||||
_, err = db.Exec(table_schema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error in creating notification_channles table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
tableSchema := `CREATE TABLE IF NOT EXISTS planned_maintenance (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
description TEXT,
|
|
||||||
alert_ids TEXT,
|
|
||||||
schedule TEXT NOT NULL,
|
|
||||||
created_at datetime NOT NULL,
|
|
||||||
created_by TEXT NOT NULL,
|
|
||||||
updated_at datetime NOT NULL,
|
|
||||||
updated_by TEXT NOT NULL
|
|
||||||
);`
|
|
||||||
_, err = db.Exec(tableSchema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error in creating planned_maintenance table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
table_schema = `CREATE TABLE IF NOT EXISTS ttl_status (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
transaction_id TEXT NOT NULL,
|
|
||||||
created_at datetime NOT NULL,
|
|
||||||
updated_at datetime NOT NULL,
|
|
||||||
table_name TEXT NOT NULL,
|
|
||||||
ttl INTEGER DEFAULT 0,
|
|
||||||
cold_storage_ttl INTEGER DEFAULT 0,
|
|
||||||
status TEXT NOT NULL
|
|
||||||
);`
|
|
||||||
|
|
||||||
_, err = db.Exec(table_schema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error in creating ttl_status table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// sqlite does not support "IF NOT EXISTS"
|
|
||||||
createdAt := `ALTER TABLE rules ADD COLUMN created_at datetime;`
|
|
||||||
_, err = db.Exec(createdAt)
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "duplicate column name") {
|
|
||||||
return nil, fmt.Errorf("error in adding column created_at to rules table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
createdBy := `ALTER TABLE rules ADD COLUMN created_by TEXT;`
|
|
||||||
_, err = db.Exec(createdBy)
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "duplicate column name") {
|
|
||||||
return nil, fmt.Errorf("error in adding column created_by to rules table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedBy := `ALTER TABLE rules ADD COLUMN updated_by TEXT;`
|
|
||||||
_, err = db.Exec(updatedBy)
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "duplicate column name") {
|
|
||||||
return nil, fmt.Errorf("error in adding column updated_by to rules table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
createdBy = `ALTER TABLE dashboards ADD COLUMN created_by TEXT;`
|
|
||||||
_, err = db.Exec(createdBy)
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "duplicate column name") {
|
|
||||||
return nil, fmt.Errorf("error in adding column created_by to dashboards table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedBy = `ALTER TABLE dashboards ADD COLUMN updated_by TEXT;`
|
|
||||||
_, err = db.Exec(updatedBy)
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "duplicate column name") {
|
|
||||||
return nil, fmt.Errorf("error in adding column updated_by to dashboards table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
locked := `ALTER TABLE dashboards ADD COLUMN locked INTEGER DEFAULT 0;`
|
|
||||||
_, err = db.Exec(locked)
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "duplicate column name") {
|
|
||||||
return nil, fmt.Errorf("error in adding column locked to dashboards table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
telemetry.GetInstance().SetDashboardsInfoCallback(GetDashboardsInfo)
|
telemetry.GetInstance().SetDashboardsInfoCallback(GetDashboardsInfo)
|
||||||
|
|
||||||
return db, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Dashboard struct {
|
type Dashboard struct {
|
||||||
|
|||||||
@@ -33,41 +33,9 @@ type SavedView struct {
|
|||||||
ExtraData string `json:"extra_data" db:"extra_data"`
|
ExtraData string `json:"extra_data" db:"extra_data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitWithDSN sets up setting up the connection pool global variable.
|
|
||||||
func InitWithDSN(dataSourceName string) (*sqlx.DB, error) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
db, err = sqlx.Open("sqlite3", dataSourceName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tableSchema := `CREATE TABLE IF NOT EXISTS saved_views (
|
|
||||||
uuid TEXT PRIMARY KEY,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
category TEXT NOT NULL,
|
|
||||||
created_at datetime NOT NULL,
|
|
||||||
created_by TEXT,
|
|
||||||
updated_at datetime NOT NULL,
|
|
||||||
updated_by TEXT,
|
|
||||||
source_page TEXT NOT NULL,
|
|
||||||
tags TEXT,
|
|
||||||
data TEXT NOT NULL,
|
|
||||||
extra_data TEXT
|
|
||||||
);`
|
|
||||||
|
|
||||||
_, err = db.Exec(tableSchema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error in creating saved views table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
telemetry.GetInstance().SetSavedViewsInfoCallback(GetSavedViewsInfo)
|
|
||||||
|
|
||||||
return db, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitWithDB(sqlDB *sqlx.DB) {
|
func InitWithDB(sqlDB *sqlx.DB) {
|
||||||
db = sqlDB
|
db = sqlDB
|
||||||
|
telemetry.GetInstance().SetSavedViewsInfoCallback(GetSavedViewsInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetViews() ([]*v3.SavedView, error) {
|
func GetViews() ([]*v3.SavedView, error) {
|
||||||
|
|||||||
@@ -123,12 +123,7 @@ type Manager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewManager(db *sqlx.DB) (*Manager, error) {
|
func NewManager(db *sqlx.DB) (*Manager, error) {
|
||||||
iiRepo, err := NewInstalledIntegrationsSqliteRepo(db)
|
iiRepo := NewInstalledIntegrationsSqliteRepo(db)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"could not init sqlite DB for installed integrations: %w", err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Manager{
|
return &Manager{
|
||||||
availableIntegrationsRepo: &BuiltInIntegrations{},
|
availableIntegrationsRepo: &BuiltInIntegrations{},
|
||||||
|
|||||||
@@ -9,45 +9,14 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitSqliteDBIfNeeded(db *sqlx.DB) error {
|
|
||||||
if db == nil {
|
|
||||||
return fmt.Errorf("db is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
createTablesStatements := `
|
|
||||||
CREATE TABLE IF NOT EXISTS integrations_installed(
|
|
||||||
integration_id TEXT PRIMARY KEY,
|
|
||||||
config_json TEXT,
|
|
||||||
installed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
)
|
|
||||||
`
|
|
||||||
_, err := db.Exec(createTablesStatements)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"could not ensure integrations schema in sqlite DB: %w", err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstalledIntegrationsSqliteRepo struct {
|
type InstalledIntegrationsSqliteRepo struct {
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInstalledIntegrationsSqliteRepo(db *sqlx.DB) (
|
func NewInstalledIntegrationsSqliteRepo(db *sqlx.DB) *InstalledIntegrationsSqliteRepo {
|
||||||
*InstalledIntegrationsSqliteRepo, error,
|
|
||||||
) {
|
|
||||||
err := InitSqliteDBIfNeeded(db)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"couldn't ensure sqlite schema for installed integrations: %w", err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &InstalledIntegrationsSqliteRepo{
|
return &InstalledIntegrationsSqliteRepo{
|
||||||
db: db,
|
db: db,
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *InstalledIntegrationsSqliteRepo) list(
|
func (r *InstalledIntegrationsSqliteRepo) list(
|
||||||
|
|||||||
@@ -15,11 +15,7 @@ import (
|
|||||||
|
|
||||||
func NewTestIntegrationsManager(t *testing.T) *Manager {
|
func NewTestIntegrationsManager(t *testing.T) *Manager {
|
||||||
testDB := utils.NewQueryServiceDBForTests(t)
|
testDB := utils.NewQueryServiceDBForTests(t)
|
||||||
|
installedIntegrationsRepo := NewInstalledIntegrationsSqliteRepo(testDB)
|
||||||
installedIntegrationsRepo, err := NewInstalledIntegrationsSqliteRepo(testDB)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not init sqlite DB for installed integrations: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Manager{
|
return &Manager{
|
||||||
availableIntegrationsRepo: &TestAvailableIntegrationsRepo{},
|
availableIntegrationsRepo: &TestAvailableIntegrationsRepo{},
|
||||||
|
|||||||
@@ -27,15 +27,13 @@ type LogParsingPipelineController struct {
|
|||||||
|
|
||||||
func NewLogParsingPipelinesController(
|
func NewLogParsingPipelinesController(
|
||||||
db *sqlx.DB,
|
db *sqlx.DB,
|
||||||
engine string,
|
|
||||||
getIntegrationPipelines func(context.Context) ([]Pipeline, *model.ApiError),
|
getIntegrationPipelines func(context.Context) ([]Pipeline, *model.ApiError),
|
||||||
) (*LogParsingPipelineController, error) {
|
) (*LogParsingPipelineController, error) {
|
||||||
repo := NewRepo(db)
|
repo := NewRepo(db)
|
||||||
err := repo.InitDB(engine)
|
|
||||||
return &LogParsingPipelineController{
|
return &LogParsingPipelineController{
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
GetIntegrationPipelines: getIntegrationPipelines,
|
GetIntegrationPipelines: getIntegrationPipelines,
|
||||||
}, err
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PipelinesResponse is used to prepare http response for pipelines config related requests
|
// PipelinesResponse is used to prepare http response for pipelines config related requests
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline/sqlite"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -29,15 +28,6 @@ func NewRepo(db *sqlx.DB) Repo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repo) InitDB(engine string) error {
|
|
||||||
switch engine {
|
|
||||||
case "sqlite3", "sqlite":
|
|
||||||
return sqlite.InitDB(r.db)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported db")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insertPipeline stores a given postable pipeline to database
|
// insertPipeline stores a given postable pipeline to database
|
||||||
func (r *Repo) insertPipeline(
|
func (r *Repo) insertPipeline(
|
||||||
ctx context.Context, postable *PostablePipeline,
|
ctx context.Context, postable *PostablePipeline,
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
package sqlite
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
)
|
|
||||||
|
|
||||||
func InitDB(db *sqlx.DB) error {
|
|
||||||
var err error
|
|
||||||
if db == nil {
|
|
||||||
return fmt.Errorf("invalid db connection")
|
|
||||||
}
|
|
||||||
|
|
||||||
table_schema := `CREATE TABLE IF NOT EXISTS pipelines(
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
order_id INTEGER,
|
|
||||||
enabled BOOLEAN,
|
|
||||||
created_by TEXT,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
name VARCHAR(400) NOT NULL,
|
|
||||||
alias VARCHAR(20) NOT NULL,
|
|
||||||
description TEXT,
|
|
||||||
filter TEXT NOT NULL,
|
|
||||||
config_json TEXT
|
|
||||||
);
|
|
||||||
`
|
|
||||||
_, err = db.Exec(table_schema)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "Error in creating pipelines table")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -166,10 +166,7 @@ type testbed struct {
|
|||||||
|
|
||||||
func newTestbed(t *testing.T) *testbed {
|
func newTestbed(t *testing.T) *testbed {
|
||||||
testDB := utils.NewQueryServiceDBForTests(t)
|
testDB := utils.NewQueryServiceDBForTests(t)
|
||||||
_, err := model.InitDB(testDB)
|
model.InitDB(testDB)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not init opamp model: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
testConfigProvider := NewMockAgentConfigProvider()
|
testConfigProvider := NewMockAgentConfigProvider()
|
||||||
opampServer := InitializeServer(nil, testConfigProvider)
|
opampServer := InitializeServer(nil, testConfigProvider)
|
||||||
|
|||||||
@@ -30,28 +30,15 @@ func (a *Agents) Count() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the database and create schema if needed
|
// Initialize the database and create schema if needed
|
||||||
func InitDB(qsDB *sqlx.DB) (*sqlx.DB, error) {
|
func InitDB(qsDB *sqlx.DB) *sqlx.DB {
|
||||||
db = qsDB
|
db = qsDB
|
||||||
|
|
||||||
tableSchema := `CREATE TABLE IF NOT EXISTS agents (
|
|
||||||
agent_id TEXT PRIMARY KEY UNIQUE,
|
|
||||||
started_at datetime NOT NULL,
|
|
||||||
terminated_at datetime,
|
|
||||||
current_status TEXT NOT NULL,
|
|
||||||
effective_config TEXT NOT NULL
|
|
||||||
);`
|
|
||||||
|
|
||||||
_, err := db.Exec(tableSchema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error in creating agents table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
AllAgents = Agents{
|
AllAgents = Agents{
|
||||||
agentsById: make(map[string]*Agent),
|
agentsById: make(map[string]*Agent),
|
||||||
connections: make(map[types.Connection]map[string]bool),
|
connections: make(map[types.Connection]map[string]bool),
|
||||||
mux: sync.RWMutex{},
|
mux: sync.RWMutex{},
|
||||||
}
|
}
|
||||||
return db, nil
|
|
||||||
|
return qsDB
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveConnection removes the connection all Agent instances associated with the
|
// RemoveConnection removes the connection all Agent instances associated with the
|
||||||
|
|||||||
@@ -203,53 +203,8 @@ type UpdatePreference struct {
|
|||||||
|
|
||||||
var db *sqlx.DB
|
var db *sqlx.DB
|
||||||
|
|
||||||
func InitDB(datasourceName string) error {
|
func InitDB(inputDB *sqlx.DB) {
|
||||||
var err error
|
db = inputDB
|
||||||
db, err = sqlx.Open("sqlite3", datasourceName)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the user preference table
|
|
||||||
tableSchema := `
|
|
||||||
PRAGMA foreign_keys = ON;
|
|
||||||
CREATE TABLE IF NOT EXISTS user_preference(
|
|
||||||
preference_id TEXT NOT NULL,
|
|
||||||
preference_value TEXT,
|
|
||||||
user_id TEXT NOT NULL,
|
|
||||||
PRIMARY KEY (preference_id,user_id),
|
|
||||||
FOREIGN KEY (user_id)
|
|
||||||
REFERENCES users(id)
|
|
||||||
ON UPDATE CASCADE
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);`
|
|
||||||
|
|
||||||
_, err = db.Exec(tableSchema)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error in creating user_preference table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the org preference table
|
|
||||||
tableSchema = `
|
|
||||||
PRAGMA foreign_keys = ON;
|
|
||||||
CREATE TABLE IF NOT EXISTS org_preference(
|
|
||||||
preference_id TEXT NOT NULL,
|
|
||||||
preference_value TEXT,
|
|
||||||
org_id TEXT NOT NULL,
|
|
||||||
PRIMARY KEY (preference_id,org_id),
|
|
||||||
FOREIGN KEY (org_id)
|
|
||||||
REFERENCES organizations(id)
|
|
||||||
ON UPDATE CASCADE
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);`
|
|
||||||
|
|
||||||
_, err = db.Exec(tableSchema)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error in creating org_preference table: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// org preference functions
|
// org preference functions
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/app/clickhouseReader"
|
"go.signoz.io/signoz/pkg/query-service/app/clickhouseReader"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/cloudintegrations"
|
"go.signoz.io/signoz/pkg/query-service/app/cloudintegrations"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/dashboards"
|
"go.signoz.io/signoz/pkg/query-service/app/dashboards"
|
||||||
|
"go.signoz.io/signoz/pkg/query-service/app/explorer"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/integrations"
|
"go.signoz.io/signoz/pkg/query-service/app/integrations"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
"go.signoz.io/signoz/pkg/query-service/app/opamp"
|
||||||
@@ -35,8 +36,8 @@ import (
|
|||||||
"go.signoz.io/signoz/pkg/query-service/common"
|
"go.signoz.io/signoz/pkg/query-service/common"
|
||||||
"go.signoz.io/signoz/pkg/query-service/migrate"
|
"go.signoz.io/signoz/pkg/query-service/migrate"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
|
"go.signoz.io/signoz/pkg/signoz"
|
||||||
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/explorer"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
"go.signoz.io/signoz/pkg/query-service/cache"
|
"go.signoz.io/signoz/pkg/query-service/cache"
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
@@ -96,24 +97,13 @@ func (s Server) HealthCheckStatus() chan healthcheck.Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewServer creates and initializes Server
|
// NewServer creates and initializes Server
|
||||||
func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
func NewServer(serverOptions *ServerOptions, config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
|
||||||
|
if err := dao.InitDao(signoz.SQLStore.SQLxDB()); err != nil {
|
||||||
if err := dao.InitDao("sqlite", constants.RELATIONAL_DATASOURCE_PATH); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
preferences.InitDB(signoz.SQLStore.SQLxDB())
|
||||||
if err := preferences.InitDB(constants.RELATIONAL_DATASOURCE_PATH); err != nil {
|
dashboards.InitDB(signoz.SQLStore.SQLxDB())
|
||||||
return nil, err
|
explorer.InitWithDB(signoz.SQLStore.SQLxDB())
|
||||||
}
|
|
||||||
|
|
||||||
localDB, err := dashboards.InitDB(constants.RELATIONAL_DATASOURCE_PATH)
|
|
||||||
explorer.InitWithDSN(constants.RELATIONAL_DATASOURCE_PATH)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
localDB.SetMaxOpenConns(10)
|
|
||||||
|
|
||||||
// initiate feature manager
|
// initiate feature manager
|
||||||
fm := featureManager.StartManager()
|
fm := featureManager.StartManager()
|
||||||
@@ -125,7 +115,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
if storage == "clickhouse" {
|
if storage == "clickhouse" {
|
||||||
zap.L().Info("Using ClickHouse as datastore ...")
|
zap.L().Info("Using ClickHouse as datastore ...")
|
||||||
clickhouseReader := clickhouseReader.NewReader(
|
clickhouseReader := clickhouseReader.NewReader(
|
||||||
localDB,
|
signoz.SQLStore.SQLxDB(),
|
||||||
serverOptions.PromConfigPath,
|
serverOptions.PromConfigPath,
|
||||||
fm,
|
fm,
|
||||||
serverOptions.MaxIdleConns,
|
serverOptions.MaxIdleConns,
|
||||||
@@ -140,7 +130,9 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("storage type: %s is not supported in query service", storage)
|
return nil, fmt.Errorf("storage type: %s is not supported in query service", storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
skipConfig := &model.SkipConfig{}
|
skipConfig := &model.SkipConfig{}
|
||||||
|
var err error
|
||||||
if serverOptions.SkipTopLvlOpsPath != "" {
|
if serverOptions.SkipTopLvlOpsPath != "" {
|
||||||
// read skip config
|
// read skip config
|
||||||
skipConfig, err = model.ReadSkipConfig(serverOptions.SkipTopLvlOpsPath)
|
skipConfig, err = model.ReadSkipConfig(serverOptions.SkipTopLvlOpsPath)
|
||||||
@@ -161,7 +153,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
rm, err := makeRulesManager(
|
rm, err := makeRulesManager(
|
||||||
serverOptions.PromConfigPath,
|
serverOptions.PromConfigPath,
|
||||||
constants.GetAlertManagerApiPrefix(),
|
constants.GetAlertManagerApiPrefix(),
|
||||||
serverOptions.RuleRepoURL, localDB, 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -178,18 +170,18 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
integrationsController, err := integrations.NewController(localDB)
|
integrationsController, err := integrations.NewController(signoz.SQLStore.SQLxDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("couldn't create integrations controller: %w", err)
|
return nil, fmt.Errorf("couldn't create integrations controller: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cloudIntegrationsController, err := cloudintegrations.NewController(localDB)
|
cloudIntegrationsController, err := cloudintegrations.NewController(signoz.SQLStore.SQLxDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("couldn't create cloud provider integrations controller: %w", err)
|
return nil, fmt.Errorf("couldn't create cloud provider integrations controller: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController(
|
logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController(
|
||||||
localDB, "sqlite", integrationsController.GetPipelinesForInstalledIntegrations,
|
signoz.SQLStore.SQLxDB(), integrationsController.GetPipelinesForInstalledIntegrations,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -241,14 +233,10 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
|
|
||||||
s.privateHTTP = privateServer
|
s.privateHTTP = privateServer
|
||||||
|
|
||||||
_, err = opAmpModel.InitDB(localDB)
|
opAmpModel.InitDB(signoz.SQLStore.SQLxDB())
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
agentConfMgr, err := agentConf.Initiate(&agentConf.ManagerOptions{
|
agentConfMgr, err := agentConf.Initiate(&agentConf.ManagerOptions{
|
||||||
DB: localDB,
|
DB: signoz.SQLStore.SQLxDB(),
|
||||||
DBEngine: "sqlite",
|
|
||||||
AgentFeatures: []agentConf.AgentFeature{
|
AgentFeatures: []agentConf.AgentFeature{
|
||||||
logParsingPipelineController,
|
logParsingPipelineController,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,26 +1,20 @@
|
|||||||
package dao
|
package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.signoz.io/signoz/pkg/query-service/dao/sqlite"
|
"go.signoz.io/signoz/pkg/query-service/dao/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
var db ModelDao
|
var db ModelDao
|
||||||
|
|
||||||
func InitDao(engine, path string) error {
|
func InitDao(inputDB *sqlx.DB) error {
|
||||||
var err error
|
var err error
|
||||||
|
db, err = sqlite.InitDB(inputDB)
|
||||||
switch engine {
|
if err != nil {
|
||||||
case "sqlite":
|
return errors.Wrap(err, "failed to initialize DB")
|
||||||
db, err = sqlite.InitDB(path)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to initialize DB")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("RelationalDB type: %s is not supported in query service", engine)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package sqlite
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -17,83 +16,8 @@ type ModelDaoSqlite struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InitDB sets up setting up the connection pool global variable.
|
// InitDB sets up setting up the connection pool global variable.
|
||||||
func InitDB(dataSourceName string) (*ModelDaoSqlite, error) {
|
func InitDB(inputDB *sqlx.DB) (*ModelDaoSqlite, error) {
|
||||||
var err error
|
mds := &ModelDaoSqlite{db: inputDB}
|
||||||
|
|
||||||
db, err := sqlx.Open("sqlite3", dataSourceName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to Open sqlite3 DB")
|
|
||||||
}
|
|
||||||
db.SetMaxOpenConns(10)
|
|
||||||
|
|
||||||
table_schema := `
|
|
||||||
PRAGMA foreign_keys = ON;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS invites (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
email TEXT NOT NULL UNIQUE,
|
|
||||||
token TEXT NOT NULL,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
role TEXT NOT NULL,
|
|
||||||
org_id TEXT NOT NULL,
|
|
||||||
FOREIGN KEY(org_id) REFERENCES organizations(id)
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS organizations (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
is_anonymous INTEGER NOT NULL DEFAULT 0 CHECK(is_anonymous IN (0,1)),
|
|
||||||
has_opted_updates INTEGER NOT NULL DEFAULT 1 CHECK(has_opted_updates IN (0,1))
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
email TEXT NOT NULL UNIQUE,
|
|
||||||
password TEXT NOT NULL,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
profile_picture_url TEXT,
|
|
||||||
group_id TEXT NOT NULL,
|
|
||||||
org_id TEXT NOT NULL,
|
|
||||||
FOREIGN KEY(group_id) REFERENCES groups(id),
|
|
||||||
FOREIGN KEY(org_id) REFERENCES organizations(id)
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS groups (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
name TEXT NOT NULL UNIQUE
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS reset_password_request (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
user_id TEXT NOT NULL,
|
|
||||||
token TEXT NOT NULL,
|
|
||||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS user_flags (
|
|
||||||
user_id TEXT PRIMARY KEY,
|
|
||||||
flags TEXT,
|
|
||||||
FOREIGN KEY(user_id) REFERENCES users(id)
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS apdex_settings (
|
|
||||||
service_name TEXT PRIMARY KEY,
|
|
||||||
threshold FLOAT NOT NULL,
|
|
||||||
exclude_status_codes TEXT NOT NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS ingestion_keys (
|
|
||||||
key_id TEXT PRIMARY KEY,
|
|
||||||
name TEXT,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
ingestion_key TEXT NOT NULL,
|
|
||||||
ingestion_url TEXT NOT NULL,
|
|
||||||
data_region TEXT NOT NULL
|
|
||||||
);
|
|
||||||
`
|
|
||||||
|
|
||||||
_, err = db.Exec(table_schema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error in creating tables: %v", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
mds := &ModelDaoSqlite{db: db}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
if err := mds.initializeOrgPreferences(ctx); err != nil {
|
if err := mds.initializeOrgPreferences(ctx); err != nil {
|
||||||
|
|||||||
@@ -9,25 +9,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
prommodel "github.com/prometheus/common/model"
|
prommodel "github.com/prometheus/common/model"
|
||||||
|
"go.signoz.io/signoz/pkg/config"
|
||||||
|
"go.signoz.io/signoz/pkg/config/envprovider"
|
||||||
|
"go.signoz.io/signoz/pkg/instrumentation"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app"
|
"go.signoz.io/signoz/pkg/query-service/app"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
"go.signoz.io/signoz/pkg/query-service/constants"
|
"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/query-service/version"
|
||||||
|
"go.signoz.io/signoz/pkg/signoz"
|
||||||
|
pkgversion "go.signoz.io/signoz/pkg/version"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func initZapLog() *zap.Logger {
|
|
||||||
config := zap.NewProductionConfig()
|
|
||||||
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
|
||||||
config.EncoderConfig.TimeKey = "timestamp"
|
|
||||||
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
|
||||||
logger, _ := config.Build()
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
prommodel.NameValidationScheme = prommodel.UTF8Validation
|
prommodel.NameValidationScheme = prommodel.UTF8Validation
|
||||||
}
|
}
|
||||||
@@ -67,13 +61,33 @@ func main() {
|
|||||||
flag.DurationVar(&dialTimeout, "dial-timeout", 5*time.Second, "(the maximum time to establish a connection, only used with clickhouse if not set in ClickHouseUrl env var DSN.)")
|
flag.DurationVar(&dialTimeout, "dial-timeout", 5*time.Second, "(the maximum time to establish a connection, only used with clickhouse if not set in ClickHouseUrl env var DSN.)")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
loggerMgr := initZapLog()
|
config, err := signoz.NewConfig(context.Background(), config.ResolverConfig{
|
||||||
zap.ReplaceGlobals(loggerMgr)
|
Uris: []string{"env:"},
|
||||||
defer loggerMgr.Sync() // flushes buffer, if any
|
ProviderFactories: []config.ProviderFactory{
|
||||||
|
envprovider.NewFactory(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Fatal("Failed to create config", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
logger := loggerMgr.Sugar()
|
instrumentation, err := instrumentation.New(context.Background(), pkgversion.Build{}, config.Instrumentation)
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Fatal("Failed to create instrumentation", zap.Error(err))
|
||||||
|
}
|
||||||
|
defer instrumentation.Stop(context.Background())
|
||||||
|
|
||||||
|
zap.ReplaceGlobals(instrumentation.Logger())
|
||||||
|
defer instrumentation.Logger().Sync() // flushes buffer, if any
|
||||||
|
|
||||||
|
logger := instrumentation.Logger().Sugar()
|
||||||
version.PrintVersion()
|
version.PrintVersion()
|
||||||
|
|
||||||
|
signoz, err := signoz.New(context.Background(), instrumentation, config, signoz.NewProviderFactories())
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Fatal("Failed to create signoz struct", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
serverOptions := &app.ServerOptions{
|
serverOptions := &app.ServerOptions{
|
||||||
HTTPHostPort: constants.HTTPHostPort,
|
HTTPHostPort: constants.HTTPHostPort,
|
||||||
PromConfigPath: promConfigPath,
|
PromConfigPath: promConfigPath,
|
||||||
@@ -101,13 +115,7 @@ func main() {
|
|||||||
zap.L().Info("JWT secret key set successfully.")
|
zap.L().Info("JWT secret key set successfully.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := migrate.Migrate(constants.RELATIONAL_DATASOURCE_PATH); err != nil {
|
server, err := app.NewServer(serverOptions, config, signoz)
|
||||||
zap.L().Error("Failed to migrate", zap.Error(err))
|
|
||||||
} else {
|
|
||||||
zap.L().Info("Migration successful")
|
|
||||||
}
|
|
||||||
|
|
||||||
server, err := app.NewServer(serverOptions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal("Failed to create server", zap.Error(err))
|
logger.Fatal("Failed to create server", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,22 +16,6 @@ type DataMigration struct {
|
|||||||
Succeeded bool `db:"succeeded"`
|
Succeeded bool `db:"succeeded"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSchema(conn *sqlx.DB) error {
|
|
||||||
tableSchema := `
|
|
||||||
CREATE TABLE IF NOT EXISTS data_migrations (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
version VARCHAR(255) NOT NULL UNIQUE,
|
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
succeeded BOOLEAN NOT NULL DEFAULT FALSE
|
|
||||||
);
|
|
||||||
`
|
|
||||||
_, err := conn.Exec(tableSchema)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMigrationVersion(conn *sqlx.DB, version string) (*DataMigration, error) {
|
func getMigrationVersion(conn *sqlx.DB, version string) (*DataMigration, error) {
|
||||||
var migration DataMigration
|
var migration DataMigration
|
||||||
err := conn.Get(&migration, "SELECT * FROM data_migrations WHERE version = $1", version)
|
err := conn.Get(&migration, "SELECT * FROM data_migrations WHERE version = $1", version)
|
||||||
@@ -44,18 +28,6 @@ func getMigrationVersion(conn *sqlx.DB, version string) (*DataMigration, error)
|
|||||||
return &migration, nil
|
return &migration, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Migrate(dsn string) error {
|
|
||||||
conn, err := sqlx.Connect("sqlite3", dsn)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := initSchema(conn); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ClickHouseMigrate(conn driver.Conn, cluster string) error {
|
func ClickHouseMigrate(conn driver.Conn, cluster string) error {
|
||||||
|
|
||||||
database := "CREATE DATABASE IF NOT EXISTS signoz_analytics ON CLUSTER %s"
|
database := "CREATE DATABASE IF NOT EXISTS signoz_analytics ON CLUSTER %s"
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestLogPipelinesLifecycle(t *testing.T) {
|
func TestLogPipelinesLifecycle(t *testing.T) {
|
||||||
testbed := NewLogPipelinesTestBed(t, nil)
|
testbed := NewLogPipelinesTestBed(t, utils.NewQueryServiceDBForTests(t))
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
getPipelinesResp := testbed.GetPipelinesFromQS()
|
getPipelinesResp := testbed.GetPipelinesFromQS()
|
||||||
@@ -461,7 +461,7 @@ func NewTestbedWithoutOpamp(t *testing.T, testDB *sqlx.DB) *LogPipelinesTestBed
|
|||||||
}
|
}
|
||||||
|
|
||||||
controller, err := logparsingpipeline.NewLogParsingPipelinesController(
|
controller, err := logparsingpipeline.NewLogParsingPipelinesController(
|
||||||
testDB, "sqlite", ic.GetPipelinesForInstalledIntegrations,
|
testDB, ic.GetPipelinesForInstalledIntegrations,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not create a logparsingpipelines controller: %v", err)
|
t.Fatalf("could not create a logparsingpipelines controller: %v", err)
|
||||||
@@ -481,12 +481,10 @@ func NewTestbedWithoutOpamp(t *testing.T, testDB *sqlx.DB) *LogPipelinesTestBed
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mock an available opamp agent
|
// Mock an available opamp agent
|
||||||
testDB, err = opampModel.InitDB(testDB)
|
_ = opampModel.InitDB(testDB)
|
||||||
require.Nil(t, err, "failed to init opamp model")
|
|
||||||
|
|
||||||
agentConfMgr, err := agentConf.Initiate(&agentConf.ManagerOptions{
|
agentConfMgr, err := agentConf.Initiate(&agentConf.ManagerOptions{
|
||||||
DB: testDB,
|
DB: testDB,
|
||||||
DBEngine: "sqlite",
|
|
||||||
AgentFeatures: []agentConf.AgentFeature{
|
AgentFeatures: []agentConf.AgentFeature{
|
||||||
apiHandler.LogsParsingPipelineController,
|
apiHandler.LogsParsingPipelineController,
|
||||||
}})
|
}})
|
||||||
|
|||||||
@@ -1,38 +1,70 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/instrumentation/instrumentationtest"
|
||||||
"go.signoz.io/signoz/pkg/query-service/app/dashboards"
|
"go.signoz.io/signoz/pkg/query-service/app/dashboards"
|
||||||
"go.signoz.io/signoz/pkg/query-service/dao"
|
"go.signoz.io/signoz/pkg/query-service/dao"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore/sqlitesqlstore"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstoremigrator"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstoremigrator/migrations"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTestSqliteDB(t *testing.T) (testDB *sqlx.DB, testDBFilePath string) {
|
func NewQueryServiceDBForTests(t *testing.T) (testDB *sqlx.DB) {
|
||||||
testDBFile, err := os.CreateTemp("", "test-signoz-db-*")
|
testDBFile, err := os.CreateTemp("", "test-signoz-db-*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not create temp file for test db: %v", err)
|
t.Fatalf("could not create temp file for test db: %v", err)
|
||||||
}
|
}
|
||||||
testDBFilePath = testDBFile.Name()
|
testDBFilePath := testDBFile.Name()
|
||||||
t.Cleanup(func() { os.Remove(testDBFilePath) })
|
t.Cleanup(func() { os.Remove(testDBFilePath) })
|
||||||
testDBFile.Close()
|
testDBFile.Close()
|
||||||
|
|
||||||
testDB, err = sqlx.Open("sqlite3", testDBFilePath)
|
config := sqlstore.Config{
|
||||||
if err != nil {
|
Provider: "sqlite",
|
||||||
t.Fatalf("could not open test db sqlite file: %v", err)
|
Sqlite: sqlstore.SqliteConfig{
|
||||||
|
Path: testDBFilePath,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return testDB, testDBFilePath
|
sqlStore, err := factory.NewFromFactory(context.Background(), instrumentationtest.New().ToProviderSettings(), config, factory.MustNewNamedMap(sqlitesqlstore.NewFactory()), "sqlite")
|
||||||
}
|
if err != nil {
|
||||||
|
t.Fatalf("could not create sqlite provider: %v", err)
|
||||||
func NewQueryServiceDBForTests(t *testing.T) *sqlx.DB {
|
}
|
||||||
testDB, testDBFilePath := NewTestSqliteDB(t)
|
|
||||||
|
migrations, err := sqlstoremigrator.NewMigrations(context.Background(), instrumentationtest.New().ToProviderSettings(), config, factory.MustNewNamedMap(
|
||||||
// TODO(Raj): This should not require passing in the DB file path
|
migrations.NewAddDataMigrationsFactory(),
|
||||||
dao.InitDao("sqlite", testDBFilePath)
|
migrations.NewAddOrganizationFactory(),
|
||||||
dashboards.InitDB(testDBFilePath)
|
migrations.NewAddPreferencesFactory(),
|
||||||
|
migrations.NewAddDashboardsFactory(),
|
||||||
return testDB
|
migrations.NewAddSavedViewsFactory(),
|
||||||
|
migrations.NewAddAgentsFactory(),
|
||||||
|
migrations.NewAddPipelinesFactory(),
|
||||||
|
migrations.NewAddIntegrationsFactory(),
|
||||||
|
))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not create migrations: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStoreMigrator := sqlstoremigrator.New(context.Background(), instrumentationtest.New().ToProviderSettings(), sqlStore, migrations, config)
|
||||||
|
|
||||||
|
err = sqlStoreMigrator.Migrate(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not run migrations: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dao.InitDao(sqlStore.SQLxDB())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not init dao: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboards.InitDB(sqlStore.SQLxDB())
|
||||||
|
|
||||||
|
return sqlStore.SQLxDB()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,19 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Registry struct {
|
type Registry struct {
|
||||||
services []NamedService
|
services []factory.Service
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
startCh chan error
|
startCh chan error
|
||||||
stopCh chan error
|
stopCh chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new registry of services. It needs at least one service in the input.
|
// New creates a new registry of services. It needs at least one service in the input.
|
||||||
func New(logger *zap.Logger, services ...NamedService) (*Registry, error) {
|
func New(logger *zap.Logger, services ...factory.Service) (*Registry, error) {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
return nil, fmt.Errorf("cannot build registry, logger is required")
|
return nil, fmt.Errorf("cannot build registry, logger is required")
|
||||||
}
|
}
|
||||||
@@ -38,7 +39,7 @@ func New(logger *zap.Logger, services ...NamedService) (*Registry, error) {
|
|||||||
|
|
||||||
func (r *Registry) Start(ctx context.Context) error {
|
func (r *Registry) Start(ctx context.Context) error {
|
||||||
for _, s := range r.services {
|
for _, s := range r.services {
|
||||||
go func(s Service) {
|
go func(s factory.Service) {
|
||||||
err := s.Start(ctx)
|
err := s.Start(ctx)
|
||||||
r.startCh <- err
|
r.startCh <- err
|
||||||
}(s)
|
}(s)
|
||||||
@@ -66,7 +67,7 @@ func (r *Registry) Wait(ctx context.Context) error {
|
|||||||
|
|
||||||
func (r *Registry) Stop(ctx context.Context) error {
|
func (r *Registry) Stop(ctx context.Context) error {
|
||||||
for _, s := range r.services {
|
for _, s := range r.services {
|
||||||
go func(s Service) {
|
go func(s factory.Service) {
|
||||||
err := s.Stop(ctx)
|
err := s.Stop(ctx)
|
||||||
r.stopCh <- err
|
r.stopCh <- err
|
||||||
}(s)
|
}(s)
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.signoz.io/signoz/pkg/factory/factorytest"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRegistryWith2HttpServers(t *testing.T) {
|
func TestRegistryWith2HttpServers(t *testing.T) {
|
||||||
http1, err := newHttpService("http1")
|
http1, err := factorytest.NewHttpService("http1")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
http2, err := newHttpService("http2")
|
http2, err := factorytest.NewHttpService("http2")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
registry, err := New(zap.NewNop(), http1, http2)
|
registry, err := New(zap.NewNop(), http1, http2)
|
||||||
@@ -34,10 +35,10 @@ func TestRegistryWith2HttpServers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRegistryWith2HttpServersWithoutWait(t *testing.T) {
|
func TestRegistryWith2HttpServersWithoutWait(t *testing.T) {
|
||||||
http1, err := newHttpService("http1")
|
http1, err := factorytest.NewHttpService("http1")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
http2, err := newHttpService("http2")
|
http2, err := factorytest.NewHttpService("http2")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
registry, err := New(zap.NewNop(), http1, http2)
|
registry, err := New(zap.NewNop(), http1, http2)
|
||||||
|
|||||||
41
pkg/signoz/config.go
Normal file
41
pkg/signoz/config.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package signoz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config defines the entire 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfig(ctx context.Context, resolverConfig config.ResolverConfig) (Config, error) {
|
||||||
|
configFactories := []factory.ConfigFactory{
|
||||||
|
instrumentation.NewConfigFactory(),
|
||||||
|
web.NewConfigFactory(),
|
||||||
|
sqlstore.NewConfigFactory(),
|
||||||
|
cache.NewConfigFactory(),
|
||||||
|
}
|
||||||
|
|
||||||
|
conf, err := config.New(ctx, resolverConfig, configFactories)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var config Config
|
||||||
|
if err := conf.Unmarshal("", &config); err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
47
pkg/signoz/provider.go
Normal file
47
pkg/signoz/provider.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package signoz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore/sqlitesqlstore"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstoremigrator/migrations"
|
||||||
|
"go.signoz.io/signoz/pkg/web"
|
||||||
|
"go.signoz.io/signoz/pkg/web/noopweb"
|
||||||
|
"go.signoz.io/signoz/pkg/web/routerweb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProviderFactories struct {
|
||||||
|
SQLStoreMigrationFactories factory.NamedMap[factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config]]
|
||||||
|
SQLStoreProviderFactories factory.NamedMap[factory.ProviderFactory[sqlstore.SQLStore, 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(
|
||||||
|
sqlitesqlstore.NewFactory(),
|
||||||
|
),
|
||||||
|
WebProviderFactories: factory.MustNewNamedMap(
|
||||||
|
routerweb.NewFactory(),
|
||||||
|
noopweb.NewFactory(),
|
||||||
|
),
|
||||||
|
CacheProviderFactories: factory.MustNewNamedMap(
|
||||||
|
memorycache.NewFactory(),
|
||||||
|
rediscache.NewFactory(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,37 +1,57 @@
|
|||||||
package signoz
|
package signoz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"go.signoz.io/signoz/pkg/cache"
|
"go.signoz.io/signoz/pkg/cache"
|
||||||
"go.signoz.io/signoz/pkg/cache/strategy/memory"
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
"go.signoz.io/signoz/pkg/cache/strategy/redis"
|
"go.signoz.io/signoz/pkg/instrumentation"
|
||||||
"go.signoz.io/signoz/pkg/config"
|
"go.signoz.io/signoz/pkg/sqlstoremigrator"
|
||||||
|
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
"go.signoz.io/signoz/pkg/web"
|
"go.signoz.io/signoz/pkg/web"
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SigNoz struct {
|
type SigNoz struct {
|
||||||
Cache cache.Cache
|
Cache cache.Cache
|
||||||
Web *web.Web
|
Web web.Web
|
||||||
|
SQLStore sqlstore.SQLStore
|
||||||
|
SQLStoreMigrator sqlstore.SQLStoreMigrator
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config *config.Config, skipWebFrontend bool) (*SigNoz, error) {
|
func New(ctx context.Context, instrumentation instrumentation.Instrumentation, config Config, factories ProviderFactories) (*SigNoz, error) {
|
||||||
var cache cache.Cache
|
providerSettings := instrumentation.ToProviderSettings()
|
||||||
|
|
||||||
// init for the cache
|
cache, err := factory.NewFromFactory(ctx, providerSettings, config.Cache, factories.CacheProviderFactories, config.Cache.Provider)
|
||||||
switch config.Cache.Provider {
|
if err != nil {
|
||||||
case "memory":
|
return nil, err
|
||||||
cache = memory.New(&config.Cache.Memory)
|
|
||||||
case "redis":
|
|
||||||
cache = redis.New(&config.Cache.Redis)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
web, err := web.New(zap.L(), config.Web)
|
web, err := factory.NewFromFactory(ctx, providerSettings, config.Web, factories.WebProviderFactories, config.Web.GetProvider())
|
||||||
if err != nil && !skipWebFrontend {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStore, err := factory.NewFromFactory(ctx, providerSettings, config.SQLStore, factories.SQLStoreProviderFactories, config.SQLStore.Provider)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
migrations, err := sqlstoremigrator.NewMigrations(ctx, providerSettings, config.SQLStore, factories.SQLStoreMigrationFactories)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStoreMigrator := sqlstoremigrator.New(ctx, providerSettings, sqlStore, migrations, config.SQLStore)
|
||||||
|
|
||||||
|
err = sqlStoreMigrator.Migrate(ctx)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SigNoz{
|
return &SigNoz{
|
||||||
Cache: cache,
|
Cache: cache,
|
||||||
Web: web,
|
Web: web,
|
||||||
|
SQLStore: sqlStore,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
57
pkg/sqlstore/config.go
Normal file
57
pkg/sqlstore/config.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package sqlstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Provider string `mapstructure:"provider"`
|
||||||
|
Connection ConnectionConfig `mapstructure:",squash"`
|
||||||
|
Migration MigrationConfig `mapstructure:"migration"`
|
||||||
|
Sqlite SqliteConfig `mapstructure:"sqlite"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SqliteConfig struct {
|
||||||
|
Path string `mapstructure:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectionConfig struct {
|
||||||
|
MaxOpenConns int `mapstructure:"max_open_conns"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MigrationConfig struct {
|
||||||
|
LockTimeout time.Duration `mapstructure:"lock_timeout"`
|
||||||
|
LockInterval time.Duration `mapstructure:"lock_interval"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfigFactory() factory.ConfigFactory {
|
||||||
|
return factory.NewConfigFactory(factory.MustNewName("sqlstore"), newConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConfig() factory.Config {
|
||||||
|
return &Config{
|
||||||
|
Provider: "sqlite",
|
||||||
|
Connection: ConnectionConfig{
|
||||||
|
MaxOpenConns: 100,
|
||||||
|
},
|
||||||
|
Migration: MigrationConfig{
|
||||||
|
LockTimeout: 2 * time.Minute,
|
||||||
|
LockInterval: 10 * time.Second,
|
||||||
|
},
|
||||||
|
Sqlite: SqliteConfig{
|
||||||
|
Path: "/var/lib/signoz/signoz.db",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) Validate() error {
|
||||||
|
if c.Migration.LockTimeout < c.Migration.LockInterval {
|
||||||
|
return errors.New("lock_timeout must be greater than lock_interval")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
63
pkg/sqlstore/sqlitesqlstore/sqlite.go
Normal file
63
pkg/sqlstore/sqlitesqlstore/sqlite.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package sqlitesqlstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
_ "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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type provider struct {
|
||||||
|
sqlDB *sql.DB
|
||||||
|
bunDB *bun.DB
|
||||||
|
sqlxDB *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFactory() factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("sqlite"), New)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(ctx context.Context, settings factory.ProviderSettings, config sqlstore.Config) (sqlstore.SQLStore, error) {
|
||||||
|
if config.Provider != "sqlite" {
|
||||||
|
return nil, fmt.Errorf("provider %q is not supported by sqlite", config.Provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlDB, err := sql.Open("sqlite3", "file:"+config.Sqlite.Path+"?_foreign_keys=true")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ZapLogger.Info("connected to sqlite", zap.String("path", config.Sqlite.Path))
|
||||||
|
|
||||||
|
// Set connection options
|
||||||
|
sqlDB.SetMaxOpenConns(config.Connection.MaxOpenConns)
|
||||||
|
|
||||||
|
// Initialize ORMs
|
||||||
|
bunDB := bun.NewDB(sqlDB, sqlitedialect.New())
|
||||||
|
sqlxDB := sqlx.NewDb(sqlDB, "sqlite3")
|
||||||
|
|
||||||
|
return &provider{
|
||||||
|
sqlDB: sqlDB,
|
||||||
|
bunDB: bunDB,
|
||||||
|
sqlxDB: sqlxDB,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *provider) BunDB() *bun.DB {
|
||||||
|
return e.bunDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *provider) SQLDB() *sql.DB {
|
||||||
|
return e.sqlDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *provider) SQLxDB() *sqlx.DB {
|
||||||
|
return e.sqlxDB
|
||||||
|
}
|
||||||
37
pkg/sqlstore/sqlstore.go
Normal file
37
pkg/sqlstore/sqlstore.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package sqlstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SQLStore is the interface for the SQLStore.
|
||||||
|
type SQLStore interface {
|
||||||
|
// SQLDB returns the underlying sql.DB.
|
||||||
|
SQLDB() *sql.DB
|
||||||
|
// BunDB returns the underlying bun.DB. This is the recommended way to interact with the database.
|
||||||
|
BunDB() *bun.DB
|
||||||
|
// SQLxDB returns the underlying sqlx.DB.
|
||||||
|
SQLxDB() *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// SQLStoreMigrator is the interface for the SQLStoreMigrator.
|
||||||
|
type SQLStoreMigrator interface {
|
||||||
|
// Migrate migrates the database. Migrate acquires a lock on the database and runs the migrations.
|
||||||
|
Migrate(ctx context.Context) error
|
||||||
|
// Rollback rolls back the database. Rollback acquires a lock on the database and rolls back the migrations.
|
||||||
|
Rollback(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type SQLStoreMigration interface {
|
||||||
|
// Register registers the migration with the given migrations.
|
||||||
|
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
|
||||||
|
}
|
||||||
60
pkg/sqlstore/sqlstoretest/sqlstore.go
Normal file
60
pkg/sqlstore/sqlstoretest/sqlstore.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package sqlstoretest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/dialect/sqlitedialect"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ sqlstore.SQLStore = (*MockSQLStore)(nil)
|
||||||
|
|
||||||
|
type MockSQLStore struct {
|
||||||
|
db *sql.DB
|
||||||
|
mock sqlmock.Sqlmock
|
||||||
|
bunDB *bun.DB
|
||||||
|
sqlxDB *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(config sqlstore.Config, matcher sqlmock.QueryMatcher) *MockSQLStore {
|
||||||
|
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(matcher))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var bunDB *bun.DB
|
||||||
|
var sqlxDB *sqlx.DB
|
||||||
|
if config.Provider == "sqlite" {
|
||||||
|
bunDB = bun.NewDB(db, sqlitedialect.New())
|
||||||
|
sqlxDB = sqlx.NewDb(db, "sqlite3")
|
||||||
|
} else {
|
||||||
|
panic(fmt.Errorf("provider %q is not supported by mockSQLStore", config.Provider))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MockSQLStore{
|
||||||
|
db: db,
|
||||||
|
mock: mock,
|
||||||
|
bunDB: bunDB,
|
||||||
|
sqlxDB: sqlxDB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockSQLStore) BunDB() *bun.DB {
|
||||||
|
return s.bunDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockSQLStore) SQLDB() *sql.DB {
|
||||||
|
return s.db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockSQLStore) SQLxDB() *sqlx.DB {
|
||||||
|
return s.sqlxDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockSQLStore) Mock() sqlmock.Sqlmock {
|
||||||
|
return s.mock
|
||||||
|
}
|
||||||
65
pkg/sqlstoremigrator/migrations.go
Normal file
65
pkg/sqlstoremigrator/migrations.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package sqlstoremigrator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNoExecute = errors.New("no execute")
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMigrations(
|
||||||
|
ctx context.Context,
|
||||||
|
settings factory.ProviderSettings,
|
||||||
|
config sqlstore.Config,
|
||||||
|
factories factory.NamedMap[factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config]],
|
||||||
|
) (*migrate.Migrations, error) {
|
||||||
|
migrations := migrate.NewMigrations()
|
||||||
|
|
||||||
|
for _, factory := range factories.GetInOrder() {
|
||||||
|
migration, err := factory.New(ctx, settings, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = migration.Register(migrations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return migrations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapIfNotExists(ctx context.Context, db *bun.DB, table string, column string) func(q *bun.AddColumnQuery) *bun.AddColumnQuery {
|
||||||
|
return func(q *bun.AddColumnQuery) *bun.AddColumnQuery {
|
||||||
|
if db.Dialect().Name() != dialect.SQLite {
|
||||||
|
return q.IfNotExists()
|
||||||
|
}
|
||||||
|
|
||||||
|
var result string
|
||||||
|
err := db.
|
||||||
|
NewSelect().
|
||||||
|
ColumnExpr("name").
|
||||||
|
Table("pragma_table_info").
|
||||||
|
Where("arg = ?", table).
|
||||||
|
Where("name = ?", column).
|
||||||
|
Scan(ctx, &result)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
return q.Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.Err(ErrNoExecute)
|
||||||
|
}
|
||||||
|
}
|
||||||
52
pkg/sqlstoremigrator/migrations/000_add_data_migrations.go
Normal file
52
pkg/sqlstoremigrator/migrations/000_add_data_migrations.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type addDataMigrations struct {
|
||||||
|
settings factory.ProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddDataMigrationsFactory() factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_data_migrations"), newAddDataMigrations)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddDataMigrations(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.SQLStoreMigration, error) {
|
||||||
|
return &addDataMigrations{settings: settings}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addDataMigrations) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addDataMigrations) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
// CREATE TABLE IF NOT EXISTS data_migrations (
|
||||||
|
// id SERIAL PRIMARY KEY,
|
||||||
|
// version VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
// created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
// succeeded BOOLEAN NOT NULL DEFAULT FALSE
|
||||||
|
// );
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS data_migrations (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
version VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
succeeded BOOLEAN NOT NULL DEFAULT FALSE
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addDataMigrations) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
127
pkg/sqlstoremigrator/migrations/001_add_organization.go
Normal file
127
pkg/sqlstoremigrator/migrations/001_add_organization.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type addOrganization struct {
|
||||||
|
settings factory.ProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddOrganizationFactory() factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_organization"), newAddOrganization)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddOrganization(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.SQLStoreMigration, error) {
|
||||||
|
return &addOrganization{settings: settings}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addOrganization) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addOrganization) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
// table:invites
|
||||||
|
if _, err := db.NewRaw(`CREATE TABLE IF NOT EXISTS invites (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
email TEXT NOT NULL UNIQUE,
|
||||||
|
token TEXT NOT NULL,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
role TEXT NOT NULL,
|
||||||
|
org_id TEXT NOT NULL,
|
||||||
|
FOREIGN KEY(org_id) REFERENCES organizations(id)
|
||||||
|
)`).Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:organizations
|
||||||
|
if _, err := db.NewRaw(`CREATE TABLE IF NOT EXISTS organizations (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
is_anonymous INTEGER NOT NULL DEFAULT 0 CHECK(is_anonymous IN (0,1)),
|
||||||
|
has_opted_updates INTEGER NOT NULL DEFAULT 1 CHECK(has_opted_updates IN (0,1))
|
||||||
|
)`).Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:users
|
||||||
|
if _, err := db.NewRaw(`CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
email TEXT NOT NULL UNIQUE,
|
||||||
|
password TEXT NOT NULL,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
profile_picture_url TEXT,
|
||||||
|
group_id TEXT NOT NULL,
|
||||||
|
org_id TEXT NOT NULL,
|
||||||
|
FOREIGN KEY(group_id) REFERENCES groups(id),
|
||||||
|
FOREIGN KEY(org_id) REFERENCES organizations(id)
|
||||||
|
)`).Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:groups
|
||||||
|
if _, err := db.NewRaw(`CREATE TABLE IF NOT EXISTS groups (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL UNIQUE
|
||||||
|
)`).Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:reset_password_request
|
||||||
|
if _, err := db.NewRaw(`CREATE TABLE IF NOT EXISTS reset_password_request (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
token TEXT NOT NULL,
|
||||||
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||||
|
)`).Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:user_flags
|
||||||
|
if _, err := db.NewRaw(`CREATE TABLE IF NOT EXISTS user_flags (
|
||||||
|
user_id TEXT PRIMARY KEY,
|
||||||
|
flags TEXT,
|
||||||
|
FOREIGN KEY(user_id) REFERENCES users(id)
|
||||||
|
)`).Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:apdex_settings
|
||||||
|
if _, err := db.NewRaw(`CREATE TABLE IF NOT EXISTS apdex_settings (
|
||||||
|
service_name TEXT PRIMARY KEY,
|
||||||
|
threshold FLOAT NOT NULL,
|
||||||
|
exclude_status_codes TEXT NOT NULL
|
||||||
|
)`).Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:ingestion_keys
|
||||||
|
if _, err := db.NewRaw(`CREATE TABLE IF NOT EXISTS ingestion_keys (
|
||||||
|
key_id TEXT PRIMARY KEY,
|
||||||
|
name TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
ingestion_key TEXT NOT NULL,
|
||||||
|
ingestion_url TEXT NOT NULL,
|
||||||
|
data_region TEXT NOT NULL
|
||||||
|
)`).Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addOrganization) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
60
pkg/sqlstoremigrator/migrations/002_add_preferences.go
Normal file
60
pkg/sqlstoremigrator/migrations/002_add_preferences.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type addPreferences struct {
|
||||||
|
settings factory.ProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddPreferencesFactory() factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_preferences"), newAddPreferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddPreferences(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.SQLStoreMigration, error) {
|
||||||
|
return &addPreferences{settings: settings}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addPreferences) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addPreferences) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
// table:user_preference
|
||||||
|
if _, err := db.Exec(`CREATE TABLE IF NOT EXISTS user_preference (
|
||||||
|
preference_id TEXT NOT NULL,
|
||||||
|
preference_value TEXT,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (preference_id,user_id),
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
)`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:org_preference
|
||||||
|
if _, err := db.Exec(`CREATE TABLE IF NOT EXISTS org_preference (
|
||||||
|
preference_id TEXT NOT NULL,
|
||||||
|
preference_value TEXT,
|
||||||
|
org_id TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (preference_id,org_id),
|
||||||
|
FOREIGN KEY (org_id) REFERENCES organizations(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addPreferences) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
162
pkg/sqlstoremigrator/migrations/003_add_dashboards.go
Normal file
162
pkg/sqlstoremigrator/migrations/003_add_dashboards.go
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstoremigrator"
|
||||||
|
)
|
||||||
|
|
||||||
|
type addDashboards struct {
|
||||||
|
settings factory.ProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddDashboardsFactory() factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_dashboards"), newAddDashboards)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddDashboards(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.SQLStoreMigration, error) {
|
||||||
|
return &addDashboards{settings: settings}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addDashboards) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addDashboards) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
// table:dashboards
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS dashboards (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
uuid TEXT NOT NULL UNIQUE,
|
||||||
|
created_at datetime NOT NULL,
|
||||||
|
updated_at datetime NOT NULL,
|
||||||
|
data TEXT NOT NULL
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:rules
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS rules (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
updated_at datetime NOT NULL,
|
||||||
|
deleted INTEGER DEFAULT 0,
|
||||||
|
data TEXT NOT NULL
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:notification_channels
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS notification_channels (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
created_at datetime NOT NULL,
|
||||||
|
updated_at datetime NOT NULL,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
deleted INTEGER DEFAULT 0,
|
||||||
|
data TEXT NOT NULL
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:planned_maintenance
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS planned_maintenance (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
alert_ids TEXT,
|
||||||
|
schedule TEXT NOT NULL,
|
||||||
|
created_at datetime NOT NULL,
|
||||||
|
created_by TEXT NOT NULL,
|
||||||
|
updated_at datetime NOT NULL,
|
||||||
|
updated_by TEXT NOT NULL
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:ttl_status
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS ttl_status (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
transaction_id TEXT NOT NULL,
|
||||||
|
created_at datetime NOT NULL,
|
||||||
|
updated_at datetime NOT NULL,
|
||||||
|
table_name TEXT NOT NULL,
|
||||||
|
ttl INTEGER DEFAULT 0,
|
||||||
|
cold_storage_ttl INTEGER DEFAULT 0,
|
||||||
|
status TEXT NOT NULL
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:rules op:add column created_at
|
||||||
|
if _, err := db.
|
||||||
|
NewAddColumn().
|
||||||
|
Table("rules").
|
||||||
|
ColumnExpr("created_at datetime").
|
||||||
|
Apply(sqlstoremigrator.WrapIfNotExists(ctx, db, "rules", "created_at")).
|
||||||
|
Exec(ctx); err != nil && err != sqlstoremigrator.ErrNoExecute {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:rules op:add column created_by
|
||||||
|
if _, err := db.
|
||||||
|
NewAddColumn().
|
||||||
|
Table("rules").
|
||||||
|
ColumnExpr("created_by TEXT").
|
||||||
|
Apply(sqlstoremigrator.WrapIfNotExists(ctx, db, "rules", "created_by")).
|
||||||
|
Exec(ctx); err != nil && err != sqlstoremigrator.ErrNoExecute {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:rules op:add column updated_by
|
||||||
|
if _, err := db.
|
||||||
|
NewAddColumn().
|
||||||
|
Table("rules").
|
||||||
|
ColumnExpr("updated_by TEXT").
|
||||||
|
Apply(sqlstoremigrator.WrapIfNotExists(ctx, db, "rules", "updated_by")).
|
||||||
|
Exec(ctx); err != nil && err != sqlstoremigrator.ErrNoExecute {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:dashboards op:add column created_by
|
||||||
|
if _, err := db.
|
||||||
|
NewAddColumn().
|
||||||
|
Table("dashboards").
|
||||||
|
ColumnExpr("created_by TEXT").
|
||||||
|
Apply(sqlstoremigrator.WrapIfNotExists(ctx, db, "dashboards", "created_by")).
|
||||||
|
Exec(ctx); err != nil && err != sqlstoremigrator.ErrNoExecute {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:dashboards op:add column updated_by
|
||||||
|
if _, err := db.
|
||||||
|
NewAddColumn().
|
||||||
|
Table("dashboards").
|
||||||
|
ColumnExpr("updated_by TEXT").
|
||||||
|
Apply(sqlstoremigrator.WrapIfNotExists(ctx, db, "dashboards", "updated_by")).
|
||||||
|
Exec(ctx); err != nil && err != sqlstoremigrator.ErrNoExecute {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// table:dashboards op:add column locked
|
||||||
|
if _, err := db.
|
||||||
|
NewAddColumn().
|
||||||
|
Table("dashboards").
|
||||||
|
ColumnExpr("locked INTEGER DEFAULT 0").
|
||||||
|
Apply(sqlstoremigrator.WrapIfNotExists(ctx, db, "dashboards", "locked")).
|
||||||
|
Exec(ctx); err != nil && err != sqlstoremigrator.ErrNoExecute {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addDashboards) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
55
pkg/sqlstoremigrator/migrations/004_add_saved_views.go
Normal file
55
pkg/sqlstoremigrator/migrations/004_add_saved_views.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type addSavedViews struct {
|
||||||
|
settings factory.ProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddSavedViewsFactory() factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_saved_views"), newAddSavedViews)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddSavedViews(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.SQLStoreMigration, error) {
|
||||||
|
return &addSavedViews{settings: settings}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addSavedViews) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addSavedViews) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
// table:saved_views op:create
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS saved_views (
|
||||||
|
uuid TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
category TEXT NOT NULL,
|
||||||
|
created_at datetime NOT NULL,
|
||||||
|
created_by TEXT,
|
||||||
|
updated_at datetime NOT NULL,
|
||||||
|
updated_by TEXT,
|
||||||
|
source_page TEXT NOT NULL,
|
||||||
|
tags TEXT,
|
||||||
|
data TEXT NOT NULL,
|
||||||
|
extra_data TEXT
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addSavedViews) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
94
pkg/sqlstoremigrator/migrations/005_add_agents.go
Normal file
94
pkg/sqlstoremigrator/migrations/005_add_agents.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type addAgents struct {
|
||||||
|
settings factory.ProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddAgentsFactory() factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_agents"), newAddAgents)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddAgents(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.SQLStoreMigration, error) {
|
||||||
|
return &addAgents{settings: settings}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addAgents) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addAgents) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS agents (
|
||||||
|
agent_id TEXT PRIMARY KEY UNIQUE,
|
||||||
|
started_at datetime NOT NULL,
|
||||||
|
terminated_at datetime,
|
||||||
|
current_status TEXT NOT NULL,
|
||||||
|
effective_config TEXT NOT NULL
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS agent_config_versions(
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_by TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_by TEXT,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
version INTEGER DEFAULT 1,
|
||||||
|
active int,
|
||||||
|
is_valid int,
|
||||||
|
disabled int,
|
||||||
|
element_type VARCHAR(120) NOT NULL,
|
||||||
|
deploy_status VARCHAR(80) NOT NULL DEFAULT 'DIRTY',
|
||||||
|
deploy_sequence INTEGER,
|
||||||
|
deploy_result TEXT,
|
||||||
|
last_hash TEXT,
|
||||||
|
last_config TEXT,
|
||||||
|
UNIQUE(element_type, version)
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE UNIQUE INDEX IF NOT EXISTS agent_config_versions_u1 ON agent_config_versions(element_type, version);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE INDEX IF NOT EXISTS agent_config_versions_nu1 ON agent_config_versions(last_hash);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS agent_config_elements(
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_by TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_by TEXT,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
element_id TEXT NOT NULL,
|
||||||
|
element_type VARCHAR(120) NOT NULL,
|
||||||
|
version_id TEXT NOT NULL
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE UNIQUE INDEX IF NOT EXISTS agent_config_elements_u1 ON agent_config_elements(version_id, element_id, element_type);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addAgents) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
53
pkg/sqlstoremigrator/migrations/006_add_pipelines.go
Normal file
53
pkg/sqlstoremigrator/migrations/006_add_pipelines.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type addPipelines struct {
|
||||||
|
settings factory.ProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddPipelinesFactory() factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_pipelines"), newAddPipelines)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddPipelines(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.SQLStoreMigration, error) {
|
||||||
|
return &addPipelines{settings: settings}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addPipelines) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addPipelines) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS pipelines(
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
order_id INTEGER,
|
||||||
|
enabled BOOLEAN,
|
||||||
|
created_by TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
name VARCHAR(400) NOT NULL,
|
||||||
|
alias VARCHAR(20) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
filter TEXT NOT NULL,
|
||||||
|
config_json TEXT
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addPipelines) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
59
pkg/sqlstoremigrator/migrations/007_add_integrations.go
Normal file
59
pkg/sqlstoremigrator/migrations/007_add_integrations.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type addIntegrations struct {
|
||||||
|
settings factory.ProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddIntegrationsFactory() factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_integrations"), newAddIntegrations)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddIntegrations(_ context.Context, settings factory.ProviderSettings, _ sqlstore.Config) (sqlstore.SQLStoreMigration, error) {
|
||||||
|
return &addIntegrations{settings: settings}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addIntegrations) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addIntegrations) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS integrations_installed(
|
||||||
|
integration_id TEXT PRIMARY KEY,
|
||||||
|
config_json TEXT,
|
||||||
|
installed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS cloud_integrations_accounts(
|
||||||
|
cloud_provider TEXT NOT NULL,
|
||||||
|
id TEXT NOT NULL,
|
||||||
|
config_json TEXT,
|
||||||
|
cloud_account_id TEXT,
|
||||||
|
last_agent_report_json TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
|
removed_at TIMESTAMP,
|
||||||
|
UNIQUE(cloud_provider, id)
|
||||||
|
)`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addIntegrations) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
35
pkg/sqlstoremigrator/migrations/migrationstest/000_noop.go
Normal file
35
pkg/sqlstoremigrator/migrations/migrationstest/000_noop.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package migrationstest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NoopMigrationFactory() factory.ProviderFactory[sqlstore.SQLStoreMigration, sqlstore.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("noop"), newNoopMigration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNoopMigration(_ context.Context, _ factory.ProviderSettings, _ sqlstore.Config) (sqlstore.SQLStoreMigration, error) {
|
||||||
|
return &noopMigration{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopMigration struct{}
|
||||||
|
|
||||||
|
func (migration *noopMigration) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *noopMigration) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *noopMigration) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
108
pkg/sqlstoremigrator/migrator.go
Normal file
108
pkg/sqlstoremigrator/migrator.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package sqlstoremigrator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
migrationTableName = "migration"
|
||||||
|
migrationLockTableName = "migration_lock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type migrator struct {
|
||||||
|
migrator *migrate.Migrator
|
||||||
|
sqlStore sqlstore.SQLStore
|
||||||
|
settings factory.ScopedProviderSettings
|
||||||
|
config sqlstore.MigrationConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(ctx context.Context, providerSettings factory.ProviderSettings, sqlstore sqlstore.SQLStore, migrations *migrate.Migrations, config sqlstore.Config) sqlstore.SQLStoreMigrator {
|
||||||
|
return &migrator{
|
||||||
|
sqlStore: sqlstore,
|
||||||
|
migrator: migrate.NewMigrator(sqlstore.BunDB(), migrations, migrate.WithTableName(migrationTableName), migrate.WithLocksTableName(migrationLockTableName)),
|
||||||
|
settings: factory.NewScopedProviderSettings(providerSettings, "go.signoz.io/signoz/pkg/sqlstore/sqlstoremigrator"),
|
||||||
|
config: config.Migration,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migrator *migrator) Migrate(ctx context.Context) error {
|
||||||
|
migrator.settings.ZapLogger().Info("starting sqlstore migrations", zap.String("dialect", migrator.sqlStore.BunDB().Dialect().Name().String()))
|
||||||
|
if err := migrator.migrator.Init(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := migrator.Lock(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer migrator.migrator.Unlock(ctx) //nolint:errcheck
|
||||||
|
|
||||||
|
group, err := migrator.migrator.Migrate(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if group.IsZero() {
|
||||||
|
migrator.settings.ZapLogger().Info("no new migrations to run (database is up to date)", zap.String("dialect", migrator.sqlStore.BunDB().Dialect().Name().String()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
migrator.settings.ZapLogger().Info("migrated to", zap.String("group", group.String()), zap.String("dialect", migrator.sqlStore.BunDB().Dialect().Name().String()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migrator *migrator) Rollback(ctx context.Context) error {
|
||||||
|
if err := migrator.Lock(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer migrator.migrator.Unlock(ctx) //nolint:errcheck
|
||||||
|
|
||||||
|
group, err := migrator.migrator.Rollback(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if group.IsZero() {
|
||||||
|
migrator.settings.ZapLogger().Info("no groups to roll back", zap.String("dialect", migrator.sqlStore.BunDB().Dialect().Name().String()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
migrator.settings.ZapLogger().Info("rolled back", zap.String("group", group.String()), zap.String("dialect", migrator.sqlStore.BunDB().Dialect().Name().String()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migrator *migrator) Lock(ctx context.Context) error {
|
||||||
|
if err := migrator.migrator.Lock(ctx); err == nil {
|
||||||
|
migrator.settings.ZapLogger().Info("acquired migration lock", zap.String("dialect", migrator.sqlStore.BunDB().Dialect().Name().String()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
timer := time.NewTimer(migrator.config.LockTimeout)
|
||||||
|
defer timer.Stop()
|
||||||
|
|
||||||
|
ticker := time.NewTicker(migrator.config.LockInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
err := errors.New("timed out waiting for lock")
|
||||||
|
migrator.settings.ZapLogger().Error("cannot acquire lock", zap.Error(err), zap.Duration("lock_timeout", migrator.config.LockTimeout), zap.String("dialect", migrator.sqlStore.BunDB().Dialect().Name().String()))
|
||||||
|
return err
|
||||||
|
case <-ticker.C:
|
||||||
|
if err := migrator.migrator.Lock(ctx); err == nil {
|
||||||
|
migrator.settings.ZapLogger().Info("acquired migration lock", zap.String("dialect", migrator.sqlStore.BunDB().Dialect().Name().String()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
pkg/sqlstoremigrator/migrator_test.go
Normal file
49
pkg/sqlstoremigrator/migrator_test.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package sqlstoremigrator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/instrumentation/instrumentationtest"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstore/sqlstoretest"
|
||||||
|
"go.signoz.io/signoz/pkg/sqlstoremigrator/migrations/migrationstest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMigratorWithSqliteAndNoopMigration(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
config := sqlstore.Config{Provider: "sqlite", Migration: sqlstore.MigrationConfig{LockTimeout: 10 * time.Second, LockInterval: 1 * time.Second}}
|
||||||
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
|
sqlStore := sqlstoretest.New(config, sqlmock.QueryMatcherEqual)
|
||||||
|
migrationFactories := factory.MustNewNamedMap(migrationstest.NoopMigrationFactory())
|
||||||
|
migrations, err := NewMigrations(ctx, providerSettings, config, migrationFactories)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
migrator := New(ctx, instrumentationtest.New().ToProviderSettings(), sqlStore, migrations, config)
|
||||||
|
|
||||||
|
sqlStore.Mock().ExpectExec(
|
||||||
|
fmt.Sprintf("CREATE TABLE IF NOT EXISTS migration (%q INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, %q VARCHAR, %q INTEGER, %q TIMESTAMP NOT NULL DEFAULT current_timestamp)", "id", "name", "group_id", "migrated_at"),
|
||||||
|
).WillReturnResult(driver.ResultNoRows)
|
||||||
|
|
||||||
|
sqlStore.Mock().ExpectExec(
|
||||||
|
fmt.Sprintf("CREATE TABLE IF NOT EXISTS migration_lock (%q INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, %q VARCHAR, UNIQUE (%q))", "id", "table_name", "table_name"),
|
||||||
|
).WillReturnResult(driver.ResultNoRows)
|
||||||
|
|
||||||
|
sqlStore.Mock().ExpectQuery(`INSERT INTO migration_lock ("table_name") VALUES ('migration') RETURNING "id"`).
|
||||||
|
WillReturnRows(sqlStore.Mock().NewRows([]string{"id"}).AddRow(1))
|
||||||
|
|
||||||
|
sqlStore.Mock().ExpectQuery(`SELECT * FROM migration`).
|
||||||
|
WillReturnRows(sqlStore.Mock().NewRows([]string{"id"}).AddRow(1))
|
||||||
|
|
||||||
|
sqlStore.Mock().ExpectQuery(`INSERT INTO migration ("name", "group_id") VALUES ('000', 1) RETURNING "id", "migrated_at"`).
|
||||||
|
WillReturnRows(sqlStore.Mock().NewRows([]string{"id", "migrated_at"}).AddRow(1, time.Now()))
|
||||||
|
|
||||||
|
err = migrator.Migrate(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
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.
|
// Config holds the configuration for web.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
// Whether the web package is enabled.
|
||||||
|
Enabled bool `mapstructure:"enabled"`
|
||||||
// The prefix to serve the files from
|
// The prefix to serve the files from
|
||||||
Prefix string `mapstructure:"prefix"`
|
Prefix string `mapstructure:"prefix"`
|
||||||
// The directory containing the static build files. The root of this directory should
|
// The directory containing the static build files. The root of this directory should
|
||||||
@@ -16,14 +15,26 @@ type Config struct {
|
|||||||
Directory string `mapstructure:"directory"`
|
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{
|
return &Config{
|
||||||
|
Enabled: true,
|
||||||
Prefix: "/",
|
Prefix: "/",
|
||||||
Directory: "/etc/signoz/web",
|
Directory: "/etc/signoz/web",
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Validate() error {
|
func (c Config) Validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Config) GetProvider() string {
|
||||||
|
if c.Enabled {
|
||||||
|
return "router"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "noop"
|
||||||
|
}
|
||||||
|
|||||||
45
pkg/web/config_test.go
Normal file
45
pkg/web/config_test.go
Normal 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)
|
||||||
|
}
|
||||||
26
pkg/web/noopweb/noop.go
Normal file
26
pkg/web/noopweb/noop.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package noopweb
|
||||||
|
|
||||||
|
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) {}
|
||||||
98
pkg/web/routerweb/router.go
Normal file
98
pkg/web/routerweb/router.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package routerweb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"go.signoz.io/signoz/pkg/factory"
|
||||||
|
"go.signoz.io/signoz/pkg/http/middleware"
|
||||||
|
"go.signoz.io/signoz/pkg/web"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ web.Web = (*router)(nil)
|
||||||
|
|
||||||
|
const (
|
||||||
|
indexFileName string = "index.html"
|
||||||
|
)
|
||||||
|
|
||||||
|
type router struct {
|
||||||
|
config web.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
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(config.Directory)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot access web directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := fi.IsDir()
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("web directory is not a directory")
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.IsNotExist(err) || fi.IsDir() {
|
||||||
|
return nil, fmt.Errorf("%q does not exist", indexFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &router{
|
||||||
|
config: config,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (web *router) AddToRouter(router *mux.Router) error {
|
||||||
|
cache := middleware.NewCache(7 * 24 * time.Hour)
|
||||||
|
err := router.PathPrefix(web.config.Prefix).
|
||||||
|
Handler(
|
||||||
|
http.StripPrefix(
|
||||||
|
web.config.Prefix,
|
||||||
|
cache.Wrap(http.HandlerFunc(web.ServeHTTP)),
|
||||||
|
),
|
||||||
|
).GetError()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to add web to router: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (web *router) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
// Join internally call path.Clean to prevent directory traversal
|
||||||
|
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.config.Directory, indexFileName))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// if we got an error (that wasn't that the file doesn't exist) stating the
|
||||||
|
// file, return a 500 internal server error and stop
|
||||||
|
// TODO: Put down a crash html page here
|
||||||
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, use http.FileServer to serve the static file
|
||||||
|
http.FileServer(http.Dir(web.config.Directory)).ServeHTTP(rw, req)
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package web
|
package routerweb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -11,7 +12,8 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap"
|
"go.signoz.io/signoz/pkg/instrumentation/instrumentationtest"
|
||||||
|
"go.signoz.io/signoz/pkg/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServeHttpWithoutPrefix(t *testing.T) {
|
func TestServeHttpWithoutPrefix(t *testing.T) {
|
||||||
@@ -22,7 +24,7 @@ func TestServeHttpWithoutPrefix(t *testing.T) {
|
|||||||
expected, err := io.ReadAll(fi)
|
expected, err := io.ReadAll(fi)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
web, err := New(zap.NewNop(), Config{Prefix: "/", Directory: filepath.Join("testdata")})
|
web, err := New(context.Background(), instrumentationtest.New().ToProviderSettings(), web.Config{Prefix: "/", Directory: filepath.Join("testdata")})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
@@ -87,7 +89,7 @@ func TestServeHttpWithPrefix(t *testing.T) {
|
|||||||
expected, err := io.ReadAll(fi)
|
expected, err := io.ReadAll(fi)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
web, err := New(zap.NewNop(), Config{Prefix: "/web", Directory: filepath.Join("testdata")})
|
web, err := New(context.Background(), instrumentationtest.New().ToProviderSettings(), web.Config{Prefix: "/web", Directory: filepath.Join("testdata")})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
@@ -1,94 +1,15 @@
|
|||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"go.signoz.io/signoz/pkg/http/middleware"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ http.Handler = (*Web)(nil)
|
// Web is the interface that wraps the methods of the web package.
|
||||||
|
type Web interface {
|
||||||
const (
|
// AddToRouter adds the web routes to the router.
|
||||||
indexFileName string = "index.html"
|
AddToRouter(router *mux.Router) error
|
||||||
)
|
// ServeHTTP serves the web routes.
|
||||||
|
http.Handler
|
||||||
type Web struct {
|
|
||||||
logger *zap.Logger
|
|
||||||
cfg Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(logger *zap.Logger, cfg Config) (*Web, error) {
|
|
||||||
if logger == nil {
|
|
||||||
return nil, fmt.Errorf("cannot build web, logger is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := os.Stat(cfg.Directory)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot access web directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ok := fi.IsDir()
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("web directory is not a directory")
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err = os.Stat(filepath.Join(cfg.Directory, indexFileName))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot access %q in web directory: %w", indexFileName, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if os.IsNotExist(err) || fi.IsDir() {
|
|
||||||
return nil, fmt.Errorf("%q does not exist", indexFileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Web{
|
|
||||||
logger: logger.Named("go.signoz.io/pkg/web"),
|
|
||||||
cfg: cfg,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (web *Web) AddToRouter(router *mux.Router) error {
|
|
||||||
cache := middleware.NewCache(7 * 24 * time.Hour)
|
|
||||||
err := router.PathPrefix(web.cfg.Prefix).
|
|
||||||
Handler(
|
|
||||||
http.StripPrefix(
|
|
||||||
web.cfg.Prefix,
|
|
||||||
cache.Wrap(http.HandlerFunc(web.ServeHTTP)),
|
|
||||||
),
|
|
||||||
).GetError()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to add web to router: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (web *Web) 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)
|
|
||||||
|
|
||||||
// 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))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
// if we got an error (that wasn't that the file doesn't exist) stating the
|
|
||||||
// file, return a 500 internal server error and stop
|
|
||||||
// TODO: Put down a crash html page here
|
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, use http.FileServer to serve the static file
|
|
||||||
http.FileServer(http.Dir(web.cfg.Directory)).ServeHTTP(rw, req)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user