mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 12:49:06 +08:00
feat(sqlstorehook): add sqlstore logging hook (#7137)
### Summary add sqlstore logging hook
This commit is contained in:
parent
c3951afdfd
commit
2a939e813d
@ -8,6 +8,7 @@ import (
|
||||
"go.signoz.io/signoz/pkg/sqlmigration"
|
||||
"go.signoz.io/signoz/pkg/sqlstore"
|
||||
"go.signoz.io/signoz/pkg/sqlstore/sqlitesqlstore"
|
||||
"go.signoz.io/signoz/pkg/sqlstore/sqlstorehook"
|
||||
"go.signoz.io/signoz/pkg/telemetrystore"
|
||||
"go.signoz.io/signoz/pkg/telemetrystore/clickhousetelemetrystore"
|
||||
"go.signoz.io/signoz/pkg/telemetrystore/telemetrystorehook"
|
||||
@ -34,7 +35,6 @@ type ProviderConfig struct {
|
||||
}
|
||||
|
||||
func NewProviderConfig() ProviderConfig {
|
||||
hook := telemetrystorehook.NewFactory()
|
||||
return ProviderConfig{
|
||||
CacheProviderFactories: factory.MustNewNamedMap(
|
||||
memorycache.NewFactory(),
|
||||
@ -45,7 +45,7 @@ func NewProviderConfig() ProviderConfig {
|
||||
noopweb.NewFactory(),
|
||||
),
|
||||
SQLStoreProviderFactories: factory.MustNewNamedMap(
|
||||
sqlitesqlstore.NewFactory(),
|
||||
sqlitesqlstore.NewFactory(sqlstorehook.NewLoggingFactory()),
|
||||
// postgressqlstore.NewFactory(),
|
||||
),
|
||||
SQLMigrationProviderFactories: factory.MustNewNamedMap(
|
||||
@ -62,7 +62,7 @@ func NewProviderConfig() ProviderConfig {
|
||||
sqlmigration.NewModifyDatetimeFactory(),
|
||||
),
|
||||
TelemetryStoreProviderFactories: factory.MustNewNamedMap(
|
||||
clickhousetelemetrystore.NewFactory(hook),
|
||||
clickhousetelemetrystore.NewFactory(telemetrystorehook.NewFactory()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
18
pkg/sqlstore/bun.go
Normal file
18
pkg/sqlstore/bun.go
Normal file
@ -0,0 +1,18 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/schema"
|
||||
)
|
||||
|
||||
func NewBunDB(sqldb *sql.DB, dialect schema.Dialect, hooks []SQLStoreHook, opts ...bun.DBOption) *bun.DB {
|
||||
bunDB := bun.NewDB(sqldb, dialect, opts...)
|
||||
|
||||
for _, hook := range hooks {
|
||||
bunDB.AddQueryHook(hook)
|
||||
}
|
||||
|
||||
return bunDB
|
||||
}
|
@ -20,11 +20,22 @@ type provider struct {
|
||||
sqlxdb *sqlx.DB
|
||||
}
|
||||
|
||||
func NewFactory() factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("postgres"), New)
|
||||
func NewFactory(hookFactories ...factory.ProviderFactory[sqlstore.SQLStoreHook, sqlstore.Config]) factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("postgres"), func(ctx context.Context, providerSettings factory.ProviderSettings, config sqlstore.Config) (sqlstore.SQLStore, error) {
|
||||
hooks := make([]sqlstore.SQLStoreHook, len(hookFactories))
|
||||
for i, hookFactory := range hookFactories {
|
||||
hook, err := hookFactory.New(ctx, providerSettings, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hooks[i] = hook
|
||||
}
|
||||
|
||||
func New(ctx context.Context, providerSettings factory.ProviderSettings, config sqlstore.Config) (sqlstore.SQLStore, error) {
|
||||
return New(ctx, providerSettings, config, hooks...)
|
||||
})
|
||||
}
|
||||
|
||||
func New(ctx context.Context, providerSettings factory.ProviderSettings, config sqlstore.Config, hooks ...sqlstore.SQLStoreHook) (sqlstore.SQLStore, error) {
|
||||
settings := factory.NewScopedProviderSettings(providerSettings, "go.signoz.io/signoz/pkg/sqlstore/postgressqlstore")
|
||||
|
||||
pgConfig, err := pgxpool.ParseConfig(config.Postgres.DSN)
|
||||
@ -46,7 +57,7 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
|
||||
return &provider{
|
||||
settings: settings,
|
||||
sqldb: sqldb,
|
||||
bundb: bun.NewDB(sqldb, pgdialect.New()),
|
||||
bundb: sqlstore.NewBunDB(sqldb, pgdialect.New(), hooks),
|
||||
sqlxdb: sqlx.NewDb(sqldb, "postgres"),
|
||||
}, nil
|
||||
}
|
||||
|
@ -19,11 +19,22 @@ type provider struct {
|
||||
sqlxdb *sqlx.DB
|
||||
}
|
||||
|
||||
func NewFactory() factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("sqlite"), New)
|
||||
func NewFactory(hookFactories ...factory.ProviderFactory[sqlstore.SQLStoreHook, sqlstore.Config]) factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("sqlite"), func(ctx context.Context, providerSettings factory.ProviderSettings, config sqlstore.Config) (sqlstore.SQLStore, error) {
|
||||
hooks := make([]sqlstore.SQLStoreHook, len(hookFactories))
|
||||
for i, hookFactory := range hookFactories {
|
||||
hook, err := hookFactory.New(ctx, providerSettings, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hooks[i] = hook
|
||||
}
|
||||
|
||||
func New(ctx context.Context, providerSettings factory.ProviderSettings, config sqlstore.Config) (sqlstore.SQLStore, error) {
|
||||
return New(ctx, providerSettings, config, hooks...)
|
||||
})
|
||||
}
|
||||
|
||||
func New(ctx context.Context, providerSettings factory.ProviderSettings, config sqlstore.Config, hooks ...sqlstore.SQLStoreHook) (sqlstore.SQLStore, error) {
|
||||
settings := factory.NewScopedProviderSettings(providerSettings, "go.signoz.io/signoz/pkg/sqlitesqlstore")
|
||||
|
||||
sqldb, err := sql.Open("sqlite3", "file:"+config.Sqlite.Path+"?_foreign_keys=true")
|
||||
@ -36,7 +47,7 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
|
||||
return &provider{
|
||||
settings: settings,
|
||||
sqldb: sqldb,
|
||||
bundb: bun.NewDB(sqldb, sqlitedialect.New()),
|
||||
bundb: sqlstore.NewBunDB(sqldb, sqlitedialect.New(), hooks),
|
||||
sqlxdb: sqlx.NewDb(sqldb, "sqlite3"),
|
||||
}, nil
|
||||
}
|
||||
|
@ -16,3 +16,7 @@ type SQLStore interface {
|
||||
// SQLxDB returns an instance of sqlx.DB.
|
||||
SQLxDB() *sqlx.DB
|
||||
}
|
||||
|
||||
type SQLStoreHook interface {
|
||||
bun.QueryHook
|
||||
}
|
||||
|
43
pkg/sqlstore/sqlstorehook/logging.go
Normal file
43
pkg/sqlstore/sqlstorehook/logging.go
Normal file
@ -0,0 +1,43 @@
|
||||
package sqlstorehook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/uptrace/bun"
|
||||
"go.signoz.io/signoz/pkg/factory"
|
||||
"go.signoz.io/signoz/pkg/sqlstore"
|
||||
)
|
||||
|
||||
type logging struct {
|
||||
bun.QueryHook
|
||||
logger *slog.Logger
|
||||
level slog.Level
|
||||
}
|
||||
|
||||
func NewLoggingFactory() factory.ProviderFactory[sqlstore.SQLStoreHook, sqlstore.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("logging"), NewLogging)
|
||||
}
|
||||
|
||||
func NewLogging(ctx context.Context, providerSettings factory.ProviderSettings, config sqlstore.Config) (sqlstore.SQLStoreHook, error) {
|
||||
return &logging{
|
||||
logger: factory.NewScopedProviderSettings(providerSettings, "go.signoz.io/signoz/pkg/sqlstore/sqlstorehook").Logger(),
|
||||
level: slog.LevelDebug,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (logging) BeforeQuery(ctx context.Context, event *bun.QueryEvent) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (hook logging) AfterQuery(ctx context.Context, event *bun.QueryEvent) {
|
||||
hook.logger.Log(
|
||||
ctx,
|
||||
hook.level,
|
||||
"::SQLSTORE-QUERY::",
|
||||
"db.query.operation", event.Operation(),
|
||||
"db.query.text", event.Query,
|
||||
"db.duration", time.Since(event.StartTime).String(),
|
||||
)
|
||||
}
|
@ -99,8 +99,8 @@ func TestNewConfigFromChannels(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
channels Channels
|
||||
expectedRoutes string
|
||||
expectedReceivers string
|
||||
expectedRoutes []map[string]any
|
||||
expectedReceivers []map[string]any
|
||||
}{
|
||||
{
|
||||
name: "OneEmailChannel",
|
||||
@ -111,8 +111,8 @@ func TestNewConfigFromChannels(t *testing.T) {
|
||||
Data: `{"name":"email-receiver","email_configs":[{"to":"test@example.com"}]}`,
|
||||
},
|
||||
},
|
||||
expectedRoutes: `[{"receiver":"email-receiver","continue":true}]`,
|
||||
expectedReceivers: `[{"name":"default-receiver"},{"name":"email-receiver","email_configs":[{"send_resolved":false,"to":"test@example.com","from":"alerts@example.com","hello":"localhost","smarthost":"smtp.example.com:587","require_tls":true,"tls_config":{"insecure_skip_verify":false}}]}]`,
|
||||
expectedRoutes: []map[string]any{{"receiver": "email-receiver", "continue": true}},
|
||||
expectedReceivers: []map[string]any{{"name": "default-receiver"}, {"name": "email-receiver", "email_configs": []any{map[string]any{"send_resolved": false, "to": "test@example.com", "from": "alerts@example.com", "hello": "localhost", "smarthost": "smtp.example.com:587", "require_tls": true, "tls_config": map[string]any{"insecure_skip_verify": false}}}}},
|
||||
},
|
||||
{
|
||||
name: "OneSlackChannel",
|
||||
@ -123,8 +123,8 @@ func TestNewConfigFromChannels(t *testing.T) {
|
||||
Data: `{"name":"slack-receiver","slack_configs":[{"channel":"#alerts","api_url":"https://slack.com/api/test","send_resolved":true}]}`,
|
||||
},
|
||||
},
|
||||
expectedRoutes: `[{"receiver":"slack-receiver","continue":true}]`,
|
||||
expectedReceivers: `[{"name":"default-receiver"},{"name":"slack-receiver","slack_configs":[{"send_resolved":true,"http_config":{"tls_config":{"insecure_skip_verify":false},"follow_redirects":true,"enable_http2":true,"proxy_url":null},"api_url":"https://slack.com/api/test","channel":"#alerts"}]}]`,
|
||||
expectedRoutes: []map[string]any{{"receiver": "slack-receiver", "continue": true}},
|
||||
expectedReceivers: []map[string]any{{"name": "default-receiver"}, {"name": "slack-receiver", "slack_configs": []any{map[string]any{"send_resolved": true, "http_config": map[string]any{"tls_config": map[string]any{"insecure_skip_verify": false}, "follow_redirects": true, "enable_http2": true, "proxy_url": nil}, "api_url": "https://slack.com/api/test", "channel": "#alerts"}}}},
|
||||
},
|
||||
{
|
||||
name: "OnePagerdutyChannel",
|
||||
@ -135,8 +135,8 @@ func TestNewConfigFromChannels(t *testing.T) {
|
||||
Data: `{"name":"pagerduty-receiver","pagerduty_configs":[{"service_key":"test"}]}`,
|
||||
},
|
||||
},
|
||||
expectedRoutes: `[{"receiver":"pagerduty-receiver","continue":true}]`,
|
||||
expectedReceivers: `[{"name":"default-receiver"},{"name":"pagerduty-receiver","pagerduty_configs":[{"send_resolved":false,"http_config":{"tls_config":{"insecure_skip_verify":false},"follow_redirects":true,"enable_http2":true,"proxy_url":null},"service_key":"test","url":"https://events.pagerduty.com/v2/enqueue"}]}]`,
|
||||
expectedRoutes: []map[string]any{{"receiver": "pagerduty-receiver", "continue": true}},
|
||||
expectedReceivers: []map[string]any{{"name": "default-receiver"}, {"name": "pagerduty-receiver", "pagerduty_configs": []any{map[string]any{"send_resolved": false, "http_config": map[string]any{"tls_config": map[string]any{"insecure_skip_verify": false}, "follow_redirects": true, "enable_http2": true, "proxy_url": nil}, "service_key": "test", "url": "https://events.pagerduty.com/v2/enqueue"}}}},
|
||||
},
|
||||
{
|
||||
name: "OnePagerdutyAndOneSlackChannel",
|
||||
@ -152,8 +152,8 @@ func TestNewConfigFromChannels(t *testing.T) {
|
||||
Data: `{"name":"slack-receiver","slack_configs":[{"channel":"#alerts","api_url":"https://slack.com/api/test","send_resolved":true}]}`,
|
||||
},
|
||||
},
|
||||
expectedRoutes: `[{"receiver":"pagerduty-receiver","continue":true},{"receiver":"slack-receiver","continue":true}]`,
|
||||
expectedReceivers: `[{"name":"default-receiver"},{"name":"pagerduty-receiver","pagerduty_configs":[{"send_resolved":false,"http_config":{"tls_config":{"insecure_skip_verify":false},"follow_redirects":true,"enable_http2":true,"proxy_url":null},"service_key":"test","url":"https://events.pagerduty.com/v2/enqueue"}]},{"name":"slack-receiver","slack_configs":[{"send_resolved":true,"http_config":{"tls_config":{"insecure_skip_verify":false},"follow_redirects":true,"enable_http2":true,"proxy_url":null},"api_url":"https://slack.com/api/test","channel":"#alerts"}]}]`,
|
||||
expectedRoutes: []map[string]any{{"receiver": "pagerduty-receiver", "continue": true}, {"receiver": "slack-receiver", "continue": true}},
|
||||
expectedReceivers: []map[string]any{{"name": "default-receiver"}, {"name": "pagerduty-receiver", "pagerduty_configs": []any{map[string]any{"send_resolved": false, "http_config": map[string]any{"tls_config": map[string]any{"insecure_skip_verify": false}, "follow_redirects": true, "enable_http2": true, "proxy_url": nil}, "service_key": "test", "url": "https://events.pagerduty.com/v2/enqueue"}}}, {"name": "slack-receiver", "slack_configs": []any{map[string]any{"send_resolved": true, "http_config": map[string]any{"tls_config": map[string]any{"insecure_skip_verify": false}, "follow_redirects": true, "enable_http2": true, "proxy_url": nil}, "api_url": "https://slack.com/api/test", "channel": "#alerts"}}}},
|
||||
},
|
||||
}
|
||||
|
||||
@ -180,11 +180,17 @@ func TestNewConfigFromChannels(t *testing.T) {
|
||||
|
||||
routes, err := json.Marshal(c.alertmanagerConfig.Route.Routes)
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, tc.expectedRoutes, string(routes))
|
||||
var actualRoutes []map[string]any
|
||||
err = json.Unmarshal(routes, &actualRoutes)
|
||||
assert.NoError(t, err)
|
||||
assert.ElementsMatch(t, tc.expectedRoutes, actualRoutes)
|
||||
|
||||
receivers, err := json.Marshal(c.alertmanagerConfig.Receivers)
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, tc.expectedReceivers, string(receivers))
|
||||
var actualReceivers []map[string]any
|
||||
err = json.Unmarshal(receivers, &actualReceivers)
|
||||
assert.NoError(t, err)
|
||||
assert.ElementsMatch(t, tc.expectedReceivers, actualReceivers)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user