mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-28 17:31:58 +08:00
Merge branch 'funcs' into formula-eval
This commit is contained in:
commit
08e8f053aa
1
.gitignore
vendored
1
.gitignore
vendored
@ -66,6 +66,7 @@ e2e/.auth
|
|||||||
# go
|
# go
|
||||||
vendor/
|
vendor/
|
||||||
**/main/**
|
**/main/**
|
||||||
|
__debug_bin**
|
||||||
|
|
||||||
# git-town
|
# git-town
|
||||||
.git-branches.toml
|
.git-branches.toml
|
||||||
|
@ -207,3 +207,11 @@ emailing:
|
|||||||
key_file_path:
|
key_file_path:
|
||||||
# The path to the certificate file.
|
# The path to the certificate file.
|
||||||
cert_file_path:
|
cert_file_path:
|
||||||
|
|
||||||
|
##################### Sharder (experimental) #####################
|
||||||
|
sharder:
|
||||||
|
# Specifies the sharder provider to use.
|
||||||
|
provider: noop
|
||||||
|
single:
|
||||||
|
# The org id to which this instance belongs to.
|
||||||
|
org_id: org_id
|
||||||
|
@ -3,13 +3,15 @@ package httplicensing
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/SigNoz/signoz/ee/query-service/constants"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/ee/query-service/constants"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/ee/licensing/licensingstore/sqllicensingstore"
|
"github.com/SigNoz/signoz/ee/licensing/licensingstore/sqllicensingstore"
|
||||||
"github.com/SigNoz/signoz/pkg/errors"
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
"github.com/SigNoz/signoz/pkg/licensing"
|
"github.com/SigNoz/signoz/pkg/licensing"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types/featuretypes"
|
"github.com/SigNoz/signoz/pkg/types/featuretypes"
|
||||||
"github.com/SigNoz/signoz/pkg/types/licensetypes"
|
"github.com/SigNoz/signoz/pkg/types/licensetypes"
|
||||||
@ -19,23 +21,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type provider struct {
|
type provider struct {
|
||||||
store licensetypes.Store
|
store licensetypes.Store
|
||||||
zeus zeus.Zeus
|
zeus zeus.Zeus
|
||||||
config licensing.Config
|
config licensing.Config
|
||||||
settings factory.ScopedProviderSettings
|
settings factory.ScopedProviderSettings
|
||||||
stopChan chan struct{}
|
orgGetter organization.Getter
|
||||||
|
stopChan chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProviderFactory(store sqlstore.SQLStore, zeus zeus.Zeus) factory.ProviderFactory[licensing.Licensing, licensing.Config] {
|
func NewProviderFactory(store sqlstore.SQLStore, zeus zeus.Zeus, orgGetter organization.Getter) factory.ProviderFactory[licensing.Licensing, licensing.Config] {
|
||||||
return factory.NewProviderFactory(factory.MustNewName("http"), func(ctx context.Context, providerSettings factory.ProviderSettings, config licensing.Config) (licensing.Licensing, error) {
|
return factory.NewProviderFactory(factory.MustNewName("http"), func(ctx context.Context, providerSettings factory.ProviderSettings, config licensing.Config) (licensing.Licensing, error) {
|
||||||
return New(ctx, providerSettings, config, store, zeus)
|
return New(ctx, providerSettings, config, store, zeus, orgGetter)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, ps factory.ProviderSettings, config licensing.Config, sqlstore sqlstore.SQLStore, zeus zeus.Zeus) (licensing.Licensing, error) {
|
func New(ctx context.Context, ps factory.ProviderSettings, config licensing.Config, sqlstore sqlstore.SQLStore, zeus zeus.Zeus, orgGetter organization.Getter) (licensing.Licensing, error) {
|
||||||
settings := factory.NewScopedProviderSettings(ps, "github.com/SigNoz/signoz/ee/licensing/httplicensing")
|
settings := factory.NewScopedProviderSettings(ps, "github.com/SigNoz/signoz/ee/licensing/httplicensing")
|
||||||
licensestore := sqllicensingstore.New(sqlstore)
|
licensestore := sqllicensingstore.New(sqlstore)
|
||||||
return &provider{store: licensestore, zeus: zeus, config: config, settings: settings, stopChan: make(chan struct{})}, nil
|
return &provider{
|
||||||
|
store: licensestore,
|
||||||
|
zeus: zeus,
|
||||||
|
config: config,
|
||||||
|
settings: settings,
|
||||||
|
orgGetter: orgGetter,
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *provider) Start(ctx context.Context) error {
|
func (provider *provider) Start(ctx context.Context) error {
|
||||||
@ -67,13 +77,13 @@ func (provider *provider) Stop(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (provider *provider) Validate(ctx context.Context) error {
|
func (provider *provider) Validate(ctx context.Context) error {
|
||||||
organizations, err := provider.store.ListOrganizations(ctx)
|
organizations, err := provider.orgGetter.ListByOwnedKeyRange(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, organizationID := range organizations {
|
for _, organization := range organizations {
|
||||||
err := provider.Refresh(ctx, organizationID)
|
err := provider.Refresh(ctx, organization.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -168,6 +178,11 @@ func (provider *provider) Refresh(ctx context.Context, organizationID valuer.UUI
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = provider.InitFeatures(ctx, activeLicense.Features)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/errors"
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
|
||||||
"github.com/SigNoz/signoz/pkg/types/featuretypes"
|
"github.com/SigNoz/signoz/pkg/types/featuretypes"
|
||||||
"github.com/SigNoz/signoz/pkg/types/licensetypes"
|
"github.com/SigNoz/signoz/pkg/types/licensetypes"
|
||||||
"github.com/SigNoz/signoz/pkg/valuer"
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
@ -82,31 +81,6 @@ func (store *store) Update(ctx context.Context, organizationID valuer.UUID, stor
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *store) ListOrganizations(ctx context.Context) ([]valuer.UUID, error) {
|
|
||||||
orgIDStrs := make([]string, 0)
|
|
||||||
err := store.sqlstore.
|
|
||||||
BunDB().
|
|
||||||
NewSelect().
|
|
||||||
Model(new(types.Organization)).
|
|
||||||
Column("id").
|
|
||||||
Scan(ctx, &orgIDStrs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
orgIDs := make([]valuer.UUID, len(orgIDStrs))
|
|
||||||
for idx, orgIDStr := range orgIDStrs {
|
|
||||||
orgID, err := valuer.NewUUID(orgIDStr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
orgIDs[idx] = orgID
|
|
||||||
}
|
|
||||||
|
|
||||||
return orgIDs, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (store *store) CreateFeature(ctx context.Context, storableFeature *featuretypes.StorableFeature) error {
|
func (store *store) CreateFeature(ctx context.Context, storableFeature *featuretypes.StorableFeature) error {
|
||||||
_, err := store.
|
_, err := store.
|
||||||
sqlstore.
|
sqlstore.
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/cache"
|
"github.com/SigNoz/signoz/pkg/cache"
|
||||||
"github.com/SigNoz/signoz/pkg/http/middleware"
|
"github.com/SigNoz/signoz/pkg/http/middleware"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||||
"github.com/SigNoz/signoz/pkg/signoz"
|
"github.com/SigNoz/signoz/pkg/signoz"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
@ -113,6 +114,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
serverOptions.SigNoz.SQLStore,
|
serverOptions.SigNoz.SQLStore,
|
||||||
serverOptions.SigNoz.TelemetryStore,
|
serverOptions.SigNoz.TelemetryStore,
|
||||||
serverOptions.SigNoz.Prometheus,
|
serverOptions.SigNoz.Prometheus,
|
||||||
|
serverOptions.SigNoz.Modules.OrgGetter,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -157,7 +159,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start the usagemanager
|
// start the usagemanager
|
||||||
usageManager, err := usage.New(serverOptions.SigNoz.Licensing, serverOptions.SigNoz.TelemetryStore.ClickhouseDB(), serverOptions.SigNoz.Zeus, serverOptions.SigNoz.Modules.Organization)
|
usageManager, err := usage.New(serverOptions.SigNoz.Licensing, serverOptions.SigNoz.TelemetryStore.ClickhouseDB(), serverOptions.SigNoz.Zeus, serverOptions.SigNoz.Modules.OrgGetter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -225,7 +227,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
&opAmpModel.AllAgents, agentConfMgr,
|
&opAmpModel.AllAgents, agentConfMgr,
|
||||||
)
|
)
|
||||||
|
|
||||||
orgs, err := apiHandler.Signoz.Modules.Organization.GetAll(context.Background())
|
orgs, err := apiHandler.Signoz.Modules.OrgGetter.ListByOwnedKeyRange(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -240,11 +242,10 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) createPrivateServer(apiHandler *api.APIHandler) (*http.Server, error) {
|
func (s *Server) createPrivateServer(apiHandler *api.APIHandler) (*http.Server, error) {
|
||||||
|
|
||||||
r := baseapp.NewRouter()
|
r := baseapp.NewRouter()
|
||||||
|
|
||||||
r.Use(middleware.NewAuth(s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
r.Use(middleware.NewAuth(s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}, s.serverOptions.SigNoz.Sharder, s.serverOptions.SigNoz.Instrumentation.Logger()).Wrap)
|
||||||
r.Use(middleware.NewAPIKey(s.serverOptions.SigNoz.SQLStore, []string{"SIGNOZ-API-KEY"}, s.serverOptions.SigNoz.Instrumentation.Logger()).Wrap)
|
r.Use(middleware.NewAPIKey(s.serverOptions.SigNoz.SQLStore, []string{"SIGNOZ-API-KEY"}, s.serverOptions.SigNoz.Instrumentation.Logger(), s.serverOptions.SigNoz.Sharder).Wrap)
|
||||||
r.Use(middleware.NewTimeout(s.serverOptions.SigNoz.Instrumentation.Logger(),
|
r.Use(middleware.NewTimeout(s.serverOptions.SigNoz.Instrumentation.Logger(),
|
||||||
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Default,
|
s.serverOptions.Config.APIServer.Timeout.Default,
|
||||||
@ -275,8 +276,8 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
|
|||||||
r := baseapp.NewRouter()
|
r := baseapp.NewRouter()
|
||||||
am := middleware.NewAuthZ(s.serverOptions.SigNoz.Instrumentation.Logger())
|
am := middleware.NewAuthZ(s.serverOptions.SigNoz.Instrumentation.Logger())
|
||||||
|
|
||||||
r.Use(middleware.NewAuth(s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
r.Use(middleware.NewAuth(s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}, s.serverOptions.SigNoz.Sharder, s.serverOptions.SigNoz.Instrumentation.Logger()).Wrap)
|
||||||
r.Use(middleware.NewAPIKey(s.serverOptions.SigNoz.SQLStore, []string{"SIGNOZ-API-KEY"}, s.serverOptions.SigNoz.Instrumentation.Logger()).Wrap)
|
r.Use(middleware.NewAPIKey(s.serverOptions.SigNoz.SQLStore, []string{"SIGNOZ-API-KEY"}, s.serverOptions.SigNoz.Instrumentation.Logger(), s.serverOptions.SigNoz.Sharder).Wrap)
|
||||||
r.Use(middleware.NewTimeout(s.serverOptions.SigNoz.Instrumentation.Logger(),
|
r.Use(middleware.NewTimeout(s.serverOptions.SigNoz.Instrumentation.Logger(),
|
||||||
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Default,
|
s.serverOptions.Config.APIServer.Timeout.Default,
|
||||||
@ -297,6 +298,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
|
|||||||
apiHandler.RegisterMessagingQueuesRoutes(r, am)
|
apiHandler.RegisterMessagingQueuesRoutes(r, am)
|
||||||
apiHandler.RegisterThirdPartyApiRoutes(r, am)
|
apiHandler.RegisterThirdPartyApiRoutes(r, am)
|
||||||
apiHandler.MetricExplorerRoutes(r, am)
|
apiHandler.MetricExplorerRoutes(r, am)
|
||||||
|
apiHandler.RegisterTraceFunnelsRoutes(r, am)
|
||||||
|
|
||||||
c := cors.New(cors.Options{
|
c := cors.New(cors.Options{
|
||||||
AllowedOrigins: []string{"*"},
|
AllowedOrigins: []string{"*"},
|
||||||
@ -450,6 +452,7 @@ func makeRulesManager(
|
|||||||
sqlstore sqlstore.SQLStore,
|
sqlstore sqlstore.SQLStore,
|
||||||
telemetryStore telemetrystore.TelemetryStore,
|
telemetryStore telemetrystore.TelemetryStore,
|
||||||
prometheus prometheus.Prometheus,
|
prometheus prometheus.Prometheus,
|
||||||
|
orgGetter organization.Getter,
|
||||||
) (*baserules.Manager, error) {
|
) (*baserules.Manager, error) {
|
||||||
// create manager opts
|
// create manager opts
|
||||||
managerOpts := &baserules.ManagerOptions{
|
managerOpts := &baserules.ManagerOptions{
|
||||||
@ -465,6 +468,7 @@ func makeRulesManager(
|
|||||||
PrepareTestRuleFunc: rules.TestNotification,
|
PrepareTestRuleFunc: rules.TestNotification,
|
||||||
Alertmanager: alertmanager,
|
Alertmanager: alertmanager,
|
||||||
SQLStore: sqlstore,
|
SQLStore: sqlstore,
|
||||||
|
OrgGetter: orgGetter,
|
||||||
}
|
}
|
||||||
|
|
||||||
// create Manager
|
// create Manager
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/config/fileprovider"
|
"github.com/SigNoz/signoz/pkg/config/fileprovider"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
pkglicensing "github.com/SigNoz/signoz/pkg/licensing"
|
pkglicensing "github.com/SigNoz/signoz/pkg/licensing"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
baseconst "github.com/SigNoz/signoz/pkg/query-service/constants"
|
baseconst "github.com/SigNoz/signoz/pkg/query-service/constants"
|
||||||
"github.com/SigNoz/signoz/pkg/signoz"
|
"github.com/SigNoz/signoz/pkg/signoz"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
@ -133,8 +134,8 @@ func main() {
|
|||||||
zeus.Config(),
|
zeus.Config(),
|
||||||
httpzeus.NewProviderFactory(),
|
httpzeus.NewProviderFactory(),
|
||||||
licensing.Config(24*time.Hour, 3),
|
licensing.Config(24*time.Hour, 3),
|
||||||
func(sqlstore sqlstore.SQLStore, zeus pkgzeus.Zeus) factory.ProviderFactory[pkglicensing.Licensing, pkglicensing.Config] {
|
func(sqlstore sqlstore.SQLStore, zeus pkgzeus.Zeus, orgGetter organization.Getter) factory.ProviderFactory[pkglicensing.Licensing, pkglicensing.Config] {
|
||||||
return httplicensing.NewProviderFactory(sqlstore, zeus)
|
return httplicensing.NewProviderFactory(sqlstore, zeus, orgGetter)
|
||||||
},
|
},
|
||||||
signoz.NewEmailingProviderFactories(),
|
signoz.NewEmailingProviderFactories(),
|
||||||
signoz.NewCacheProviderFactories(),
|
signoz.NewCacheProviderFactories(),
|
||||||
|
@ -41,16 +41,16 @@ type Manager struct {
|
|||||||
|
|
||||||
zeus zeus.Zeus
|
zeus zeus.Zeus
|
||||||
|
|
||||||
organizationModule organization.Module
|
orgGetter organization.Getter
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(licenseService licensing.Licensing, clickhouseConn clickhouse.Conn, zeus zeus.Zeus, organizationModule organization.Module) (*Manager, error) {
|
func New(licenseService licensing.Licensing, clickhouseConn clickhouse.Conn, zeus zeus.Zeus, orgGetter organization.Getter) (*Manager, error) {
|
||||||
m := &Manager{
|
m := &Manager{
|
||||||
clickhouseConn: clickhouseConn,
|
clickhouseConn: clickhouseConn,
|
||||||
licenseService: licenseService,
|
licenseService: licenseService,
|
||||||
scheduler: gocron.NewScheduler(time.UTC).Every(1).Day().At("00:00"), // send usage every at 00:00 UTC
|
scheduler: gocron.NewScheduler(time.UTC).Every(1).Day().At("00:00"), // send usage every at 00:00 UTC
|
||||||
zeus: zeus,
|
zeus: zeus,
|
||||||
organizationModule: organizationModule,
|
orgGetter: orgGetter,
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
@ -74,8 +74,7 @@ func (lm *Manager) Start(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (lm *Manager) UploadUsage(ctx context.Context) {
|
func (lm *Manager) UploadUsage(ctx context.Context) {
|
||||||
|
organizations, err := lm.orgGetter.ListByOwnedKeyRange(ctx)
|
||||||
organizations, err := lm.organizationModule.GetAll(context.Background())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Error("failed to get organizations", zap.Error(err))
|
zap.L().Error("failed to get organizations", zap.Error(err))
|
||||||
return
|
return
|
||||||
|
@ -28,6 +28,7 @@ import { QueryBuilderProvider } from 'providers/QueryBuilder';
|
|||||||
import { Suspense, useCallback, useEffect, useState } from 'react';
|
import { Suspense, useCallback, useEffect, useState } from 'react';
|
||||||
import { Route, Router, Switch } from 'react-router-dom';
|
import { Route, Router, Switch } from 'react-router-dom';
|
||||||
import { CompatRouter } from 'react-router-dom-v5-compat';
|
import { CompatRouter } from 'react-router-dom-v5-compat';
|
||||||
|
import { LicenseStatus } from 'types/api/licensesV3/getActive';
|
||||||
import { Userpilot } from 'userpilot';
|
import { Userpilot } from 'userpilot';
|
||||||
import { extractDomain } from 'utils/app';
|
import { extractDomain } from 'utils/app';
|
||||||
|
|
||||||
@ -171,11 +172,13 @@ function App(): JSX.Element {
|
|||||||
user &&
|
user &&
|
||||||
!!user.email
|
!!user.email
|
||||||
) {
|
) {
|
||||||
|
// either the active API returns error with 404 or 501 and if it returns a terminated license means it's on basic plan
|
||||||
const isOnBasicPlan =
|
const isOnBasicPlan =
|
||||||
activeLicenseFetchError &&
|
(activeLicenseFetchError &&
|
||||||
[StatusCodes.NOT_FOUND, StatusCodes.NOT_IMPLEMENTED].includes(
|
[StatusCodes.NOT_FOUND, StatusCodes.NOT_IMPLEMENTED].includes(
|
||||||
activeLicenseFetchError?.getHttpStatusCode(),
|
activeLicenseFetchError?.getHttpStatusCode(),
|
||||||
);
|
)) ||
|
||||||
|
(activeLicense?.status && activeLicense.status === LicenseStatus.INVALID);
|
||||||
const isIdentifiedUser = getLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER);
|
const isIdentifiedUser = getLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER);
|
||||||
|
|
||||||
if (isLoggedInState && user && user.id && user.email && !isIdentifiedUser) {
|
if (isLoggedInState && user && user.id && user.email && !isIdentifiedUser) {
|
||||||
@ -190,6 +193,10 @@ function App(): JSX.Element {
|
|||||||
updatedRoutes = updatedRoutes.filter(
|
updatedRoutes = updatedRoutes.filter(
|
||||||
(route) => route?.path !== ROUTES.BILLING,
|
(route) => route?.path !== ROUTES.BILLING,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isEnterpriseSelfHostedUser) {
|
||||||
|
updatedRoutes.push(LIST_LICENSES);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// always add support route for cloud users
|
// always add support route for cloud users
|
||||||
updatedRoutes = [...updatedRoutes, SUPPORT_ROUTE];
|
updatedRoutes = [...updatedRoutes, SUPPORT_ROUTE];
|
||||||
|
@ -16,6 +16,7 @@ import JSONView from 'container/LogDetailedView/JsonView';
|
|||||||
import Overview from 'container/LogDetailedView/Overview';
|
import Overview from 'container/LogDetailedView/Overview';
|
||||||
import {
|
import {
|
||||||
aggregateAttributesResourcesToString,
|
aggregateAttributesResourcesToString,
|
||||||
|
escapeHtml,
|
||||||
removeEscapeCharacters,
|
removeEscapeCharacters,
|
||||||
unescapeString,
|
unescapeString,
|
||||||
} from 'container/LogDetailedView/utils';
|
} from 'container/LogDetailedView/utils';
|
||||||
@ -118,7 +119,7 @@ function LogDetail({
|
|||||||
const htmlBody = useMemo(
|
const htmlBody = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
__html: convert.toHtml(
|
__html: convert.toHtml(
|
||||||
dompurify.sanitize(unescapeString(log?.body || ''), {
|
dompurify.sanitize(unescapeString(escapeHtml(log?.body || '')), {
|
||||||
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
|
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
@ -7,7 +7,7 @@ import cx from 'classnames';
|
|||||||
import LogDetail from 'components/LogDetail';
|
import LogDetail from 'components/LogDetail';
|
||||||
import { VIEW_TYPES } from 'components/LogDetail/constants';
|
import { VIEW_TYPES } from 'components/LogDetail/constants';
|
||||||
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||||
import { unescapeString } from 'container/LogDetailedView/utils';
|
import { escapeHtml, unescapeString } from 'container/LogDetailedView/utils';
|
||||||
import { FontSize } from 'container/OptionsMenu/types';
|
import { FontSize } from 'container/OptionsMenu/types';
|
||||||
import dompurify from 'dompurify';
|
import dompurify from 'dompurify';
|
||||||
import { useActiveLog } from 'hooks/logs/useActiveLog';
|
import { useActiveLog } from 'hooks/logs/useActiveLog';
|
||||||
@ -58,7 +58,7 @@ function LogGeneralField({
|
|||||||
const html = useMemo(
|
const html = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
__html: convert.toHtml(
|
__html: convert.toHtml(
|
||||||
dompurify.sanitize(unescapeString(fieldValue), {
|
dompurify.sanitize(unescapeString(escapeHtml(fieldValue)), {
|
||||||
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
|
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
@ -5,7 +5,7 @@ import { DrawerProps } from 'antd';
|
|||||||
import LogDetail from 'components/LogDetail';
|
import LogDetail from 'components/LogDetail';
|
||||||
import { VIEW_TYPES, VIEWS } from 'components/LogDetail/constants';
|
import { VIEW_TYPES, VIEWS } from 'components/LogDetail/constants';
|
||||||
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||||
import { unescapeString } from 'container/LogDetailedView/utils';
|
import { escapeHtml, unescapeString } from 'container/LogDetailedView/utils';
|
||||||
import LogsExplorerContext from 'container/LogsExplorerContext';
|
import LogsExplorerContext from 'container/LogsExplorerContext';
|
||||||
import dompurify from 'dompurify';
|
import dompurify from 'dompurify';
|
||||||
import { useActiveLog } from 'hooks/logs/useActiveLog';
|
import { useActiveLog } from 'hooks/logs/useActiveLog';
|
||||||
@ -177,7 +177,7 @@ function RawLogView({
|
|||||||
const html = useMemo(
|
const html = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
__html: convert.toHtml(
|
__html: convert.toHtml(
|
||||||
dompurify.sanitize(unescapeString(text), {
|
dompurify.sanitize(unescapeString(escapeHtml(text)), {
|
||||||
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
|
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
@ -21,8 +21,10 @@ import { FORBID_DOM_PURIFY_TAGS } from 'utils/app';
|
|||||||
|
|
||||||
import { DataType } from '../TableView';
|
import { DataType } from '../TableView';
|
||||||
import {
|
import {
|
||||||
|
escapeHtml,
|
||||||
filterKeyForField,
|
filterKeyForField,
|
||||||
jsonToDataNodes,
|
jsonToDataNodes,
|
||||||
|
parseFieldValue,
|
||||||
recursiveParseJSON,
|
recursiveParseJSON,
|
||||||
removeEscapeCharacters,
|
removeEscapeCharacters,
|
||||||
unescapeString,
|
unescapeString,
|
||||||
@ -85,7 +87,7 @@ export function TableViewActions(
|
|||||||
record.field === 'body'
|
record.field === 'body'
|
||||||
? {
|
? {
|
||||||
__html: convert.toHtml(
|
__html: convert.toHtml(
|
||||||
dompurify.sanitize(unescapeString(record.value), {
|
dompurify.sanitize(unescapeString(escapeHtml(record.value)), {
|
||||||
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
|
FORBID_TAGS: [...FORBID_DOM_PURIFY_TAGS],
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@ -155,7 +157,11 @@ export function TableViewActions(
|
|||||||
<ArrowDownToDot size={14} style={{ transform: 'rotate(90deg)' }} />
|
<ArrowDownToDot size={14} style={{ transform: 'rotate(90deg)' }} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onClick={onClickHandler(OPERATORS['='], fieldFilterKey, fieldData.value)}
|
onClick={onClickHandler(
|
||||||
|
OPERATORS['='],
|
||||||
|
fieldFilterKey,
|
||||||
|
parseFieldValue(fieldData.value),
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Filter out value">
|
<Tooltip title="Filter out value">
|
||||||
@ -171,7 +177,7 @@ export function TableViewActions(
|
|||||||
onClick={onClickHandler(
|
onClick={onClickHandler(
|
||||||
OPERATORS['!='],
|
OPERATORS['!='],
|
||||||
fieldFilterKey,
|
fieldFilterKey,
|
||||||
fieldData.value,
|
parseFieldValue(fieldData.value),
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -259,6 +259,24 @@ export const getDataTypes = (value: unknown): DataTypes => {
|
|||||||
return determineType(value);
|
return determineType(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// prevent html rendering in the value
|
||||||
|
export const escapeHtml = (unsafe: string): string =>
|
||||||
|
unsafe
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''');
|
||||||
|
|
||||||
|
// parse field value to remove escaping characters
|
||||||
|
export const parseFieldValue = (value: string): string => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(value);
|
||||||
|
} catch (error) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// now we do not want to render colors everywhere like in tooltip and monaco editor hence we remove such codes to make
|
// now we do not want to render colors everywhere like in tooltip and monaco editor hence we remove such codes to make
|
||||||
// the log line readable
|
// the log line readable
|
||||||
export const removeEscapeCharacters = (str: string): string =>
|
export const removeEscapeCharacters = (str: string): string =>
|
||||||
|
@ -28,16 +28,12 @@ import LogsExplorerTable from 'container/LogsExplorerTable';
|
|||||||
import { useOptionsMenu } from 'container/OptionsMenu';
|
import { useOptionsMenu } from 'container/OptionsMenu';
|
||||||
import TimeSeriesView from 'container/TimeSeriesView/TimeSeriesView';
|
import TimeSeriesView from 'container/TimeSeriesView/TimeSeriesView';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
|
||||||
import { addEmptyWidgetInDashboardJSONWithQuery } from 'hooks/dashboard/utils';
|
|
||||||
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
|
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
|
||||||
import { useGetExplorerQueryRange } from 'hooks/queryBuilder/useGetExplorerQueryRange';
|
import { useGetExplorerQueryRange } from 'hooks/queryBuilder/useGetExplorerQueryRange';
|
||||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import useAxiosError from 'hooks/useAxiosError';
|
|
||||||
import useClickOutside from 'hooks/useClickOutside';
|
import useClickOutside from 'hooks/useClickOutside';
|
||||||
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
|
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
|
||||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||||
import { FlatLogData } from 'lib/logs/flatLogData';
|
import { FlatLogData } from 'lib/logs/flatLogData';
|
||||||
@ -98,7 +94,6 @@ function LogsExplorerViews({
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
chartQueryKeyRef: MutableRefObject<any>;
|
chartQueryKeyRef: MutableRefObject<any>;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const { notifications } = useNotifications();
|
|
||||||
const { safeNavigate } = useSafeNavigate();
|
const { safeNavigate } = useSafeNavigate();
|
||||||
|
|
||||||
// this is to respect the panel type present in the URL rather than defaulting it to list always.
|
// this is to respect the panel type present in the URL rather than defaulting it to list always.
|
||||||
@ -141,8 +136,6 @@ function LogsExplorerViews({
|
|||||||
const [queryId, setQueryId] = useState<string>(v4());
|
const [queryId, setQueryId] = useState<string>(v4());
|
||||||
const [queryStats, setQueryStats] = useState<WsDataEvent>();
|
const [queryStats, setQueryStats] = useState<WsDataEvent>();
|
||||||
|
|
||||||
const handleAxisError = useAxiosError();
|
|
||||||
|
|
||||||
const listQuery = useMemo(() => {
|
const listQuery = useMemo(() => {
|
||||||
if (!stagedQuery || stagedQuery.builder.queryData.length < 1) return null;
|
if (!stagedQuery || stagedQuery.builder.queryData.length < 1) return null;
|
||||||
|
|
||||||
@ -396,11 +389,6 @@ function LogsExplorerViews({
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [data?.payload]);
|
}, [data?.payload]);
|
||||||
|
|
||||||
const {
|
|
||||||
mutate: updateDashboard,
|
|
||||||
isLoading: isUpdateDashboardLoading,
|
|
||||||
} = useUpdateDashboard();
|
|
||||||
|
|
||||||
const getUpdatedQueryForExport = useCallback((): Query => {
|
const getUpdatedQueryForExport = useCallback((): Query => {
|
||||||
const updatedQuery = cloneDeep(currentQuery);
|
const updatedQuery = cloneDeep(currentQuery);
|
||||||
|
|
||||||
@ -424,68 +412,22 @@ function LogsExplorerViews({
|
|||||||
? getUpdatedQueryForExport()
|
? getUpdatedQueryForExport()
|
||||||
: exportDefaultQuery;
|
: exportDefaultQuery;
|
||||||
|
|
||||||
const updatedDashboard = addEmptyWidgetInDashboardJSONWithQuery(
|
|
||||||
dashboard,
|
|
||||||
query,
|
|
||||||
widgetId,
|
|
||||||
panelTypeParam,
|
|
||||||
options.selectColumns,
|
|
||||||
);
|
|
||||||
|
|
||||||
logEvent('Logs Explorer: Add to dashboard successful', {
|
logEvent('Logs Explorer: Add to dashboard successful', {
|
||||||
panelType,
|
panelType,
|
||||||
isNewDashboard,
|
isNewDashboard,
|
||||||
dashboardName: dashboard?.data?.title,
|
dashboardName: dashboard?.data?.title,
|
||||||
});
|
});
|
||||||
|
|
||||||
updateDashboard(updatedDashboard, {
|
const dashboardEditView = generateExportToDashboardLink({
|
||||||
onSuccess: (data) => {
|
query,
|
||||||
if (data.error) {
|
panelType: panelTypeParam,
|
||||||
const message =
|
dashboardId: dashboard.uuid,
|
||||||
data.error === 'feature usage exceeded' ? (
|
widgetId,
|
||||||
<span>
|
|
||||||
Panel limit exceeded for {DataSource.LOGS} in community edition. Please
|
|
||||||
checkout our paid plans{' '}
|
|
||||||
<a
|
|
||||||
href="https://signoz.io/pricing/?utm_source=product&utm_medium=dashboard-limit"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
here
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
data.error
|
|
||||||
);
|
|
||||||
notifications.error({
|
|
||||||
message,
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dashboardEditView = generateExportToDashboardLink({
|
|
||||||
query,
|
|
||||||
panelType: panelTypeParam,
|
|
||||||
dashboardId: data.payload?.uuid || '',
|
|
||||||
widgetId,
|
|
||||||
});
|
|
||||||
|
|
||||||
safeNavigate(dashboardEditView);
|
|
||||||
},
|
|
||||||
onError: handleAxisError,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
safeNavigate(dashboardEditView);
|
||||||
},
|
},
|
||||||
[
|
[getUpdatedQueryForExport, exportDefaultQuery, safeNavigate, panelType],
|
||||||
getUpdatedQueryForExport,
|
|
||||||
exportDefaultQuery,
|
|
||||||
options.selectColumns,
|
|
||||||
safeNavigate,
|
|
||||||
notifications,
|
|
||||||
panelType,
|
|
||||||
updateDashboard,
|
|
||||||
handleAxisError,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -811,7 +753,6 @@ function LogsExplorerViews({
|
|||||||
<ExplorerOptionWrapper
|
<ExplorerOptionWrapper
|
||||||
disabled={!stagedQuery}
|
disabled={!stagedQuery}
|
||||||
query={exportDefaultQuery}
|
query={exportDefaultQuery}
|
||||||
isLoading={isUpdateDashboardLoading}
|
|
||||||
onExport={handleExport}
|
onExport={handleExport}
|
||||||
sourcepage={DataSource.LOGS}
|
sourcepage={DataSource.LOGS}
|
||||||
/>
|
/>
|
||||||
|
@ -2,18 +2,12 @@ import './Explorer.styles.scss';
|
|||||||
|
|
||||||
import * as Sentry from '@sentry/react';
|
import * as Sentry from '@sentry/react';
|
||||||
import { Switch } from 'antd';
|
import { Switch } from 'antd';
|
||||||
import axios from 'axios';
|
|
||||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
|
||||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import ExplorerOptionWrapper from 'container/ExplorerOptions/ExplorerOptionWrapper';
|
import ExplorerOptionWrapper from 'container/ExplorerOptions/ExplorerOptionWrapper';
|
||||||
import { useOptionsMenu } from 'container/OptionsMenu';
|
|
||||||
import RightToolbarActions from 'container/QueryBuilder/components/ToolbarActions/RightToolbarActions';
|
import RightToolbarActions from 'container/QueryBuilder/components/ToolbarActions/RightToolbarActions';
|
||||||
import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
|
import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
|
||||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
|
||||||
import { addEmptyWidgetInDashboardJSONWithQuery } from 'hooks/dashboard/utils';
|
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
|
||||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||||
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
@ -39,13 +33,6 @@ function Explorer(): JSX.Element {
|
|||||||
currentQuery,
|
currentQuery,
|
||||||
} = useQueryBuilder();
|
} = useQueryBuilder();
|
||||||
const { safeNavigate } = useSafeNavigate();
|
const { safeNavigate } = useSafeNavigate();
|
||||||
const { notifications } = useNotifications();
|
|
||||||
const { mutate: updateDashboard, isLoading } = useUpdateDashboard();
|
|
||||||
const { options } = useOptionsMenu({
|
|
||||||
storageKey: LOCALSTORAGE.METRICS_LIST_OPTIONS,
|
|
||||||
dataSource: DataSource.METRICS,
|
|
||||||
aggregateOperator: 'noop',
|
|
||||||
});
|
|
||||||
|
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const isOneChartPerQueryEnabled =
|
const isOneChartPerQueryEnabled =
|
||||||
@ -86,59 +73,16 @@ function Explorer(): JSX.Element {
|
|||||||
|
|
||||||
const widgetId = uuid();
|
const widgetId = uuid();
|
||||||
|
|
||||||
const updatedDashboard = addEmptyWidgetInDashboardJSONWithQuery(
|
const dashboardEditView = generateExportToDashboardLink({
|
||||||
dashboard,
|
query: queryToExport || exportDefaultQuery,
|
||||||
queryToExport || exportDefaultQuery,
|
panelType: PANEL_TYPES.TIME_SERIES,
|
||||||
|
dashboardId: dashboard?.uuid || '',
|
||||||
widgetId,
|
widgetId,
|
||||||
PANEL_TYPES.TIME_SERIES,
|
|
||||||
options.selectColumns,
|
|
||||||
);
|
|
||||||
|
|
||||||
updateDashboard(updatedDashboard, {
|
|
||||||
onSuccess: (data) => {
|
|
||||||
if (data.error) {
|
|
||||||
const message =
|
|
||||||
data.error === 'feature usage exceeded' ? (
|
|
||||||
<span>
|
|
||||||
Panel limit exceeded for {DataSource.METRICS} in community edition.
|
|
||||||
Please checkout our paid plans{' '}
|
|
||||||
<a
|
|
||||||
href="https://signoz.io/pricing/?utm_source=product&utm_medium=dashboard-limit"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
here
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
data.error
|
|
||||||
);
|
|
||||||
notifications.error({
|
|
||||||
message,
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const dashboardEditView = generateExportToDashboardLink({
|
|
||||||
query: queryToExport || exportDefaultQuery,
|
|
||||||
panelType: PANEL_TYPES.TIME_SERIES,
|
|
||||||
dashboardId: data.payload?.uuid || '',
|
|
||||||
widgetId,
|
|
||||||
});
|
|
||||||
|
|
||||||
safeNavigate(dashboardEditView);
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
if (axios.isAxiosError(error)) {
|
|
||||||
notifications.error({
|
|
||||||
message: error.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
safeNavigate(dashboardEditView);
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
[exportDefaultQuery, safeNavigate],
|
||||||
[exportDefaultQuery, notifications, updateDashboard],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const splitedQueries = useMemo(
|
const splitedQueries = useMemo(
|
||||||
@ -201,7 +145,6 @@ function Explorer(): JSX.Element {
|
|||||||
<ExplorerOptionWrapper
|
<ExplorerOptionWrapper
|
||||||
disabled={!stagedQuery}
|
disabled={!stagedQuery}
|
||||||
query={exportDefaultQuery}
|
query={exportDefaultQuery}
|
||||||
isLoading={isLoading}
|
|
||||||
sourcepage={DataSource.METRICS}
|
sourcepage={DataSource.METRICS}
|
||||||
onExport={handleExport}
|
onExport={handleExport}
|
||||||
isOneChartPerQuery={showOneChartPerQuery}
|
isOneChartPerQuery={showOneChartPerQuery}
|
||||||
|
@ -26,6 +26,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
|
import { LicenseStatus } from 'types/api/licensesV3/getActive';
|
||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
import { USER_ROLES } from 'types/roles';
|
import { USER_ROLES } from 'types/roles';
|
||||||
import { checkVersionState } from 'utils/app';
|
import { checkVersionState } from 'utils/app';
|
||||||
@ -301,10 +302,11 @@ function SideNav(): JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isOnBasicPlan =
|
const isOnBasicPlan =
|
||||||
activeLicenseFetchError &&
|
(activeLicenseFetchError &&
|
||||||
[StatusCodes.NOT_FOUND, StatusCodes.NOT_IMPLEMENTED].includes(
|
[StatusCodes.NOT_FOUND, StatusCodes.NOT_IMPLEMENTED].includes(
|
||||||
activeLicenseFetchError?.getHttpStatusCode(),
|
activeLicenseFetchError?.getHttpStatusCode(),
|
||||||
);
|
)) ||
|
||||||
|
(activeLicense?.status && activeLicense.status === LicenseStatus.INVALID);
|
||||||
|
|
||||||
if (user.role !== USER_ROLES.ADMIN || isOnBasicPlan) {
|
if (user.role !== USER_ROLES.ADMIN || isOnBasicPlan) {
|
||||||
updatedMenuItems = updatedMenuItems.filter(
|
updatedMenuItems = updatedMenuItems.filter(
|
||||||
@ -353,6 +355,7 @@ function SideNav(): JSX.Element {
|
|||||||
t,
|
t,
|
||||||
user.role,
|
user.role,
|
||||||
activeLicenseFetchError,
|
activeLicenseFetchError,
|
||||||
|
activeLicense?.status,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -4,7 +4,6 @@ import { FilterOutlined } from '@ant-design/icons';
|
|||||||
import * as Sentry from '@sentry/react';
|
import * as Sentry from '@sentry/react';
|
||||||
import { Button, Card, Tabs, Tooltip } from 'antd';
|
import { Button, Card, Tabs, Tooltip } from 'antd';
|
||||||
import logEvent from 'api/common/logEvent';
|
import logEvent from 'api/common/logEvent';
|
||||||
import axios from 'axios';
|
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
|
import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
|
||||||
import QuickFilters from 'components/QuickFilters/QuickFilters';
|
import QuickFilters from 'components/QuickFilters/QuickFilters';
|
||||||
@ -19,13 +18,10 @@ import RightToolbarActions from 'container/QueryBuilder/components/ToolbarAction
|
|||||||
import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
|
import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
|
||||||
import { defaultSelectedColumns } from 'container/TracesExplorer/ListView/configs';
|
import { defaultSelectedColumns } from 'container/TracesExplorer/ListView/configs';
|
||||||
import QuerySection from 'container/TracesExplorer/QuerySection';
|
import QuerySection from 'container/TracesExplorer/QuerySection';
|
||||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
|
||||||
import { addEmptyWidgetInDashboardJSONWithQuery } from 'hooks/dashboard/utils';
|
|
||||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||||
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
|
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
|
||||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||||
import { cloneDeep, isEmpty, set } from 'lodash-es';
|
import { cloneDeep, isEmpty, set } from 'lodash-es';
|
||||||
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
||||||
@ -40,8 +36,6 @@ import { ActionsWrapper, Container } from './styles';
|
|||||||
import { getTabsItems } from './utils';
|
import { getTabsItems } from './utils';
|
||||||
|
|
||||||
function TracesExplorer(): JSX.Element {
|
function TracesExplorer(): JSX.Element {
|
||||||
const { notifications } = useNotifications();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
currentQuery,
|
currentQuery,
|
||||||
panelType,
|
panelType,
|
||||||
@ -124,9 +118,7 @@ function TracesExplorer(): JSX.Element {
|
|||||||
[currentQuery, updateAllQueriesOperators],
|
[currentQuery, updateAllQueriesOperators],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { mutate: updateDashboard, isLoading } = useUpdateDashboard();
|
const getUpdatedQueryForExport = useCallback((): Query => {
|
||||||
|
|
||||||
const getUpdatedQueryForExport = (): Query => {
|
|
||||||
const updatedQuery = cloneDeep(currentQuery);
|
const updatedQuery = cloneDeep(currentQuery);
|
||||||
|
|
||||||
set(
|
set(
|
||||||
@ -136,7 +128,7 @@ function TracesExplorer(): JSX.Element {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return updatedQuery;
|
return updatedQuery;
|
||||||
};
|
}, [currentQuery, options.selectColumns]);
|
||||||
|
|
||||||
const handleExport = useCallback(
|
const handleExport = useCallback(
|
||||||
(dashboard: Dashboard | null, isNewDashboard?: boolean): void => {
|
(dashboard: Dashboard | null, isNewDashboard?: boolean): void => {
|
||||||
@ -153,65 +145,22 @@ function TracesExplorer(): JSX.Element {
|
|||||||
? getUpdatedQueryForExport()
|
? getUpdatedQueryForExport()
|
||||||
: exportDefaultQuery;
|
: exportDefaultQuery;
|
||||||
|
|
||||||
const updatedDashboard = addEmptyWidgetInDashboardJSONWithQuery(
|
|
||||||
dashboard,
|
|
||||||
query,
|
|
||||||
widgetId,
|
|
||||||
panelTypeParam,
|
|
||||||
options.selectColumns,
|
|
||||||
);
|
|
||||||
|
|
||||||
logEvent('Traces Explorer: Add to dashboard successful', {
|
logEvent('Traces Explorer: Add to dashboard successful', {
|
||||||
panelType,
|
panelType,
|
||||||
isNewDashboard,
|
isNewDashboard,
|
||||||
dashboardName: dashboard?.data?.title,
|
dashboardName: dashboard?.data?.title,
|
||||||
});
|
});
|
||||||
|
|
||||||
updateDashboard(updatedDashboard, {
|
const dashboardEditView = generateExportToDashboardLink({
|
||||||
onSuccess: (data) => {
|
query,
|
||||||
if (data.error) {
|
panelType: panelTypeParam,
|
||||||
const message =
|
dashboardId: dashboard?.uuid || '',
|
||||||
data.error === 'feature usage exceeded' ? (
|
widgetId,
|
||||||
<span>
|
|
||||||
Panel limit exceeded for {DataSource.TRACES} in community edition.
|
|
||||||
Please checkout our paid plans{' '}
|
|
||||||
<a
|
|
||||||
href="https://signoz.io/pricing/?utm_source=product&utm_medium=dashboard-limit"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
here
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
data.error
|
|
||||||
);
|
|
||||||
notifications.error({
|
|
||||||
message,
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const dashboardEditView = generateExportToDashboardLink({
|
|
||||||
query,
|
|
||||||
panelType: panelTypeParam,
|
|
||||||
dashboardId: data.payload?.uuid || '',
|
|
||||||
widgetId,
|
|
||||||
});
|
|
||||||
|
|
||||||
safeNavigate(dashboardEditView);
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
if (axios.isAxiosError(error)) {
|
|
||||||
notifications.error({
|
|
||||||
message: error.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
safeNavigate(dashboardEditView);
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
[exportDefaultQuery, panelType, safeNavigate, getUpdatedQueryForExport],
|
||||||
[exportDefaultQuery, notifications, panelType, updateDashboard],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
useShareBuilderUrl(defaultQuery);
|
useShareBuilderUrl(defaultQuery);
|
||||||
@ -282,11 +231,7 @@ function TracesExplorer(): JSX.Element {
|
|||||||
|
|
||||||
<Container className="traces-explorer-views">
|
<Container className="traces-explorer-views">
|
||||||
<ActionsWrapper>
|
<ActionsWrapper>
|
||||||
<ExportPanel
|
<ExportPanel query={exportDefaultQuery} onExport={handleExport} />
|
||||||
query={exportDefaultQuery}
|
|
||||||
isLoading={isLoading}
|
|
||||||
onExport={handleExport}
|
|
||||||
/>
|
|
||||||
</ActionsWrapper>
|
</ActionsWrapper>
|
||||||
|
|
||||||
<Tabs
|
<Tabs
|
||||||
@ -299,7 +244,6 @@ function TracesExplorer(): JSX.Element {
|
|||||||
<ExplorerOptionWrapper
|
<ExplorerOptionWrapper
|
||||||
disabled={!stagedQuery}
|
disabled={!stagedQuery}
|
||||||
query={exportDefaultQuery}
|
query={exportDefaultQuery}
|
||||||
isLoading={isLoading}
|
|
||||||
sourcepage={DataSource.TRACES}
|
sourcepage={DataSource.TRACES}
|
||||||
onExport={handleExport}
|
onExport={handleExport}
|
||||||
/>
|
/>
|
||||||
|
@ -6,6 +6,7 @@ export enum LicenseEvent {
|
|||||||
export enum LicenseStatus {
|
export enum LicenseStatus {
|
||||||
SUSPENDED = 'SUSPENDED',
|
SUSPENDED = 'SUSPENDED',
|
||||||
VALID = 'VALID',
|
VALID = 'VALID',
|
||||||
|
INVALID = 'INVALID',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum LicenseState {
|
export enum LicenseState {
|
||||||
|
@ -67,23 +67,6 @@ func (store *config) Set(ctx context.Context, config *alertmanagertypes.Config,
|
|||||||
}, opts...)
|
}, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *config) ListOrgs(ctx context.Context) ([]string, error) {
|
|
||||||
var orgIDs []string
|
|
||||||
|
|
||||||
err := store.
|
|
||||||
sqlstore.
|
|
||||||
BunDB().
|
|
||||||
NewSelect().
|
|
||||||
Table("organizations").
|
|
||||||
ColumnExpr("id").
|
|
||||||
Scan(ctx, &orgIDs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return orgIDs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (store *config) CreateChannel(ctx context.Context, channel *alertmanagertypes.Channel, opts ...alertmanagertypes.StoreOption) error {
|
func (store *config) CreateChannel(ctx context.Context, channel *alertmanagertypes.Channel, opts ...alertmanagertypes.StoreOption) error {
|
||||||
return store.wrap(ctx, func(ctx context.Context) error {
|
return store.wrap(ctx, func(ctx context.Context) error {
|
||||||
if _, err := store.
|
if _, err := store.
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerbatcher"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerbatcher"
|
||||||
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerstore/sqlalertmanagerstore"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerstore/sqlalertmanagerstore"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
|
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
|
||||||
"github.com/SigNoz/signoz/pkg/valuer"
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
@ -57,16 +58,17 @@ type provider struct {
|
|||||||
configStore alertmanagertypes.ConfigStore
|
configStore alertmanagertypes.ConfigStore
|
||||||
batcher *alertmanagerbatcher.Batcher
|
batcher *alertmanagerbatcher.Batcher
|
||||||
url *url.URL
|
url *url.URL
|
||||||
|
orgGetter organization.Getter
|
||||||
orgID string
|
orgID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[alertmanager.Alertmanager, alertmanager.Config] {
|
func NewFactory(sqlstore sqlstore.SQLStore, orgGetter organization.Getter) factory.ProviderFactory[alertmanager.Alertmanager, alertmanager.Config] {
|
||||||
return factory.NewProviderFactory(factory.MustNewName("legacy"), func(ctx context.Context, settings factory.ProviderSettings, config alertmanager.Config) (alertmanager.Alertmanager, error) {
|
return factory.NewProviderFactory(factory.MustNewName("legacy"), func(ctx context.Context, settings factory.ProviderSettings, config alertmanager.Config) (alertmanager.Alertmanager, error) {
|
||||||
return New(ctx, settings, config, sqlstore)
|
return New(ctx, settings, config, sqlstore, orgGetter)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, providerSettings factory.ProviderSettings, config alertmanager.Config, sqlstore sqlstore.SQLStore) (*provider, error) {
|
func New(ctx context.Context, providerSettings factory.ProviderSettings, config alertmanager.Config, sqlstore sqlstore.SQLStore, orgGetter organization.Getter) (*provider, error) {
|
||||||
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/alertmanager/legacyalertmanager")
|
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/alertmanager/legacyalertmanager")
|
||||||
configStore := sqlalertmanagerstore.NewConfigStore(sqlstore)
|
configStore := sqlalertmanagerstore.NewConfigStore(sqlstore)
|
||||||
|
|
||||||
@ -92,7 +94,7 @@ func (provider *provider) Start(ctx context.Context) error {
|
|||||||
// For the first time, we need to get the orgID from the config store.
|
// For the first time, we need to get the orgID from the config store.
|
||||||
// Since this is the legacy alertmanager, we get the first org from the store.
|
// Since this is the legacy alertmanager, we get the first org from the store.
|
||||||
if provider.orgID == "" {
|
if provider.orgID == "" {
|
||||||
orgIDs, err := provider.configStore.ListOrgs(ctx)
|
orgIDs, err := provider.orgGetter.ListByOwnedKeyRange(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
provider.settings.Logger().ErrorContext(ctx, "failed to send alerts to alertmanager", "error", err)
|
provider.settings.Logger().ErrorContext(ctx, "failed to send alerts to alertmanager", "error", err)
|
||||||
continue
|
continue
|
||||||
@ -103,7 +105,7 @@ func (provider *provider) Start(ctx context.Context) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
provider.orgID = orgIDs[0]
|
provider.orgID = orgIDs[0].ID.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := provider.putAlerts(ctx, provider.orgID, alerts); err != nil {
|
if err := provider.putAlerts(ctx, provider.orgID, alerts); err != nil {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerserver"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerserver"
|
||||||
"github.com/SigNoz/signoz/pkg/errors"
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
|
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,6 +21,9 @@ type Service struct {
|
|||||||
// configStore is the config store for the alertmanager service
|
// configStore is the config store for the alertmanager service
|
||||||
configStore alertmanagertypes.ConfigStore
|
configStore alertmanagertypes.ConfigStore
|
||||||
|
|
||||||
|
// organization is the organization module for the alertmanager service
|
||||||
|
orgGetter organization.Getter
|
||||||
|
|
||||||
// settings is the settings for the alertmanager service
|
// settings is the settings for the alertmanager service
|
||||||
settings factory.ScopedProviderSettings
|
settings factory.ScopedProviderSettings
|
||||||
|
|
||||||
@ -30,11 +34,19 @@ type Service struct {
|
|||||||
serversMtx sync.RWMutex
|
serversMtx sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, settings factory.ScopedProviderSettings, config alertmanagerserver.Config, stateStore alertmanagertypes.StateStore, configStore alertmanagertypes.ConfigStore) *Service {
|
func New(
|
||||||
|
ctx context.Context,
|
||||||
|
settings factory.ScopedProviderSettings,
|
||||||
|
config alertmanagerserver.Config,
|
||||||
|
stateStore alertmanagertypes.StateStore,
|
||||||
|
configStore alertmanagertypes.ConfigStore,
|
||||||
|
orgGetter organization.Getter,
|
||||||
|
) *Service {
|
||||||
service := &Service{
|
service := &Service{
|
||||||
config: config,
|
config: config,
|
||||||
stateStore: stateStore,
|
stateStore: stateStore,
|
||||||
configStore: configStore,
|
configStore: configStore,
|
||||||
|
orgGetter: orgGetter,
|
||||||
settings: settings,
|
settings: settings,
|
||||||
servers: make(map[string]*alertmanagerserver.Server),
|
servers: make(map[string]*alertmanagerserver.Server),
|
||||||
serversMtx: sync.RWMutex{},
|
serversMtx: sync.RWMutex{},
|
||||||
@ -44,38 +56,38 @@ func New(ctx context.Context, settings factory.ScopedProviderSettings, config al
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (service *Service) SyncServers(ctx context.Context) error {
|
func (service *Service) SyncServers(ctx context.Context) error {
|
||||||
orgIDs, err := service.configStore.ListOrgs(ctx)
|
orgs, err := service.orgGetter.ListByOwnedKeyRange(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
service.serversMtx.Lock()
|
service.serversMtx.Lock()
|
||||||
for _, orgID := range orgIDs {
|
for _, org := range orgs {
|
||||||
config, err := service.getConfig(ctx, orgID)
|
config, err := service.getConfig(ctx, org.ID.StringValue())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
service.settings.Logger().ErrorContext(ctx, "failed to get alertmanager config for org", "org_id", orgID, "error", err)
|
service.settings.Logger().ErrorContext(ctx, "failed to get alertmanager config for org", "org_id", org.ID.StringValue(), "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the server is not present, create it and sync the config
|
// If the server is not present, create it and sync the config
|
||||||
if _, ok := service.servers[orgID]; !ok {
|
if _, ok := service.servers[org.ID.StringValue()]; !ok {
|
||||||
server, err := service.newServer(ctx, orgID)
|
server, err := service.newServer(ctx, org.ID.StringValue())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
service.settings.Logger().ErrorContext(ctx, "failed to create alertmanager server", "org_id", orgID, "error", err)
|
service.settings.Logger().ErrorContext(ctx, "failed to create alertmanager server", "org_id", org.ID.StringValue(), "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
service.servers[orgID] = server
|
service.servers[org.ID.StringValue()] = server
|
||||||
}
|
}
|
||||||
|
|
||||||
if service.servers[orgID].Hash() == config.StoreableConfig().Hash {
|
if service.servers[org.ID.StringValue()].Hash() == config.StoreableConfig().Hash {
|
||||||
service.settings.Logger().DebugContext(ctx, "skipping alertmanager sync for org", "org_id", orgID, "hash", config.StoreableConfig().Hash)
|
service.settings.Logger().DebugContext(ctx, "skipping alertmanager sync for org", "org_id", org.ID.StringValue(), "hash", config.StoreableConfig().Hash)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = service.servers[orgID].SetConfig(ctx, config)
|
err = service.servers[org.ID.StringValue()].SetConfig(ctx, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
service.settings.Logger().ErrorContext(ctx, "failed to set config for alertmanager server", "org_id", orgID, "error", err)
|
service.settings.Logger().ErrorContext(ctx, "failed to set config for alertmanager server", "org_id", org.ID.StringValue(), "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerstore/sqlalertmanagerstore"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerstore/sqlalertmanagerstore"
|
||||||
"github.com/SigNoz/signoz/pkg/errors"
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
|
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
|
||||||
"github.com/SigNoz/signoz/pkg/valuer"
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
@ -22,13 +23,13 @@ type provider struct {
|
|||||||
stopC chan struct{}
|
stopC chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[alertmanager.Alertmanager, alertmanager.Config] {
|
func NewFactory(sqlstore sqlstore.SQLStore, orgGetter organization.Getter) factory.ProviderFactory[alertmanager.Alertmanager, alertmanager.Config] {
|
||||||
return factory.NewProviderFactory(factory.MustNewName("signoz"), func(ctx context.Context, settings factory.ProviderSettings, config alertmanager.Config) (alertmanager.Alertmanager, error) {
|
return factory.NewProviderFactory(factory.MustNewName("signoz"), func(ctx context.Context, settings factory.ProviderSettings, config alertmanager.Config) (alertmanager.Alertmanager, error) {
|
||||||
return New(ctx, settings, config, sqlstore)
|
return New(ctx, settings, config, sqlstore, orgGetter)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, providerSettings factory.ProviderSettings, config alertmanager.Config, sqlstore sqlstore.SQLStore) (*provider, error) {
|
func New(ctx context.Context, providerSettings factory.ProviderSettings, config alertmanager.Config, sqlstore sqlstore.SQLStore, orgGetter organization.Getter) (*provider, error) {
|
||||||
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager")
|
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager")
|
||||||
configStore := sqlalertmanagerstore.NewConfigStore(sqlstore)
|
configStore := sqlalertmanagerstore.NewConfigStore(sqlstore)
|
||||||
stateStore := sqlalertmanagerstore.NewStateStore(sqlstore)
|
stateStore := sqlalertmanagerstore.NewStateStore(sqlstore)
|
||||||
@ -40,6 +41,7 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
|
|||||||
config.Signoz.Config,
|
config.Signoz.Config,
|
||||||
stateStore,
|
stateStore,
|
||||||
configStore,
|
configStore,
|
||||||
|
orgGetter,
|
||||||
),
|
),
|
||||||
settings: settings,
|
settings: settings,
|
||||||
config: config,
|
config: config,
|
||||||
|
@ -5,9 +5,15 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
apiKeyCrossOrgMessage string = "::API-KEY-CROSS-ORG::"
|
||||||
)
|
)
|
||||||
|
|
||||||
type APIKey struct {
|
type APIKey struct {
|
||||||
@ -15,10 +21,11 @@ type APIKey struct {
|
|||||||
uuid *authtypes.UUID
|
uuid *authtypes.UUID
|
||||||
headers []string
|
headers []string
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
|
sharder sharder.Sharder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAPIKey(store sqlstore.SQLStore, headers []string, logger *slog.Logger) *APIKey {
|
func NewAPIKey(store sqlstore.SQLStore, headers []string, logger *slog.Logger, sharder sharder.Sharder) *APIKey {
|
||||||
return &APIKey{store: store, uuid: authtypes.NewUUID(), headers: headers, logger: logger}
|
return &APIKey{store: store, uuid: authtypes.NewUUID(), headers: headers, logger: logger, sharder: sharder}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APIKey) Wrap(next http.Handler) http.Handler {
|
func (a *APIKey) Wrap(next http.Handler) http.Handler {
|
||||||
@ -36,13 +43,20 @@ func (a *APIKey) Wrap(next http.Handler) http.Handler {
|
|||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiKeyToken, ok := authtypes.UUIDFromContext(ctx)
|
apiKeyToken, ok := authtypes.UUIDFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.store.BunDB().NewSelect().Model(&apiKey).Where("token = ?", apiKeyToken).Scan(r.Context())
|
err = a.
|
||||||
|
store.
|
||||||
|
BunDB().
|
||||||
|
NewSelect().
|
||||||
|
Model(&apiKey).
|
||||||
|
Where("token = ?", apiKeyToken).
|
||||||
|
Scan(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
@ -71,6 +85,18 @@ func (a *APIKey) Wrap(next http.Handler) http.Handler {
|
|||||||
|
|
||||||
ctx = authtypes.NewContextWithClaims(ctx, jwt)
|
ctx = authtypes.NewContextWithClaims(ctx, jwt)
|
||||||
|
|
||||||
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.sharder.IsMyOwnedKey(r.Context(), types.NewOrganizationKey(valuer.MustNewUUID(claims.OrgID))); err != nil {
|
||||||
|
a.logger.ErrorContext(r.Context(), apiKeyCrossOrgMessage, "claims", claims, "error", err)
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r = r.WithContext(ctx)
|
r = r.WithContext(ctx)
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
|
@ -1,18 +1,28 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
authCrossOrgMessage string = "::AUTH-CROSS-ORG::"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Auth struct {
|
type Auth struct {
|
||||||
jwt *authtypes.JWT
|
jwt *authtypes.JWT
|
||||||
headers []string
|
headers []string
|
||||||
|
sharder sharder.Sharder
|
||||||
|
logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuth(jwt *authtypes.JWT, headers []string) *Auth {
|
func NewAuth(jwt *authtypes.JWT, headers []string, sharder sharder.Sharder, logger *slog.Logger) *Auth {
|
||||||
return &Auth{jwt: jwt, headers: headers}
|
return &Auth{jwt: jwt, headers: headers, sharder: sharder, logger: logger}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) Wrap(next http.Handler) http.Handler {
|
func (a *Auth) Wrap(next http.Handler) http.Handler {
|
||||||
@ -28,6 +38,18 @@ func (a *Auth) Wrap(next http.Handler) http.Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.sharder.IsMyOwnedKey(r.Context(), types.NewOrganizationKey(valuer.MustNewUUID(claims.OrgID))); err != nil {
|
||||||
|
a.logger.ErrorContext(r.Context(), authCrossOrgMessage, "claims", claims, "error", err)
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r = r.WithContext(ctx)
|
r = r.WithContext(ctx)
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
|
@ -4,13 +4,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
"github.com/SigNoz/signoz/pkg/types/apdextypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Module interface {
|
type Module interface {
|
||||||
Get(context.Context, string, []string) ([]*types.ApdexSettings, error)
|
Get(context.Context, string, []string) ([]*apdextypes.Settings, error)
|
||||||
|
|
||||||
Set(context.Context, string, *types.ApdexSettings) error
|
Set(context.Context, string, *apdextypes.Settings) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/http/render"
|
"github.com/SigNoz/signoz/pkg/http/render"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/apdex"
|
"github.com/SigNoz/signoz/pkg/modules/apdex"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
"github.com/SigNoz/signoz/pkg/types/apdextypes"
|
||||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ func (handler *handler) Set(rw http.ResponseWriter, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var apdexSettings types.ApdexSettings
|
var apdexSettings apdextypes.Settings
|
||||||
if err := json.NewDecoder(req.Body).Decode(&apdexSettings); err != nil {
|
if err := json.NewDecoder(req.Body).Decode(&apdexSettings); err != nil {
|
||||||
render.Error(rw, err)
|
render.Error(rw, err)
|
||||||
return
|
return
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/errors"
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/apdex"
|
"github.com/SigNoz/signoz/pkg/modules/apdex"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
"github.com/SigNoz/signoz/pkg/types/apdextypes"
|
||||||
"github.com/SigNoz/signoz/pkg/valuer"
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
"github.com/uptrace/bun"
|
"github.com/uptrace/bun"
|
||||||
)
|
)
|
||||||
@ -25,8 +25,8 @@ func NewModule(sqlstore sqlstore.SQLStore) apdex.Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (module *module) Get(ctx context.Context, orgID string, services []string) ([]*types.ApdexSettings, error) {
|
func (module *module) Get(ctx context.Context, orgID string, services []string) ([]*apdextypes.Settings, error) {
|
||||||
var apdexSettings []*types.ApdexSettings
|
var apdexSettings []*apdextypes.Settings
|
||||||
|
|
||||||
err := module.
|
err := module.
|
||||||
sqlstore.
|
sqlstore.
|
||||||
@ -51,7 +51,7 @@ func (module *module) Get(ctx context.Context, orgID string, services []string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
apdexSettings = append(apdexSettings, &types.ApdexSettings{
|
apdexSettings = append(apdexSettings, &apdextypes.Settings{
|
||||||
ServiceName: service,
|
ServiceName: service,
|
||||||
Threshold: defaultApdexThreshold,
|
Threshold: defaultApdexThreshold,
|
||||||
})
|
})
|
||||||
@ -61,7 +61,7 @@ func (module *module) Get(ctx context.Context, orgID string, services []string)
|
|||||||
return apdexSettings, nil
|
return apdexSettings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (module *module) Set(ctx context.Context, orgID string, apdexSettings *types.ApdexSettings) error {
|
func (module *module) Set(ctx context.Context, orgID string, apdexSettings *apdextypes.Settings) error {
|
||||||
apdexSettings.OrgID = orgID
|
apdexSettings.OrgID = orgID
|
||||||
apdexSettings.Identifiable.ID = valuer.GenerateUUID()
|
apdexSettings.Identifiable.ID = valuer.GenerateUUID()
|
||||||
|
|
||||||
|
36
pkg/modules/organization/implorganization/getter.go
Normal file
36
pkg/modules/organization/implorganization/getter.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package implorganization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type getter struct {
|
||||||
|
store types.OrganizationStore
|
||||||
|
sharder sharder.Sharder
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetter(store types.OrganizationStore, sharder sharder.Sharder) organization.Getter {
|
||||||
|
return &getter{store: store, sharder: sharder}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (module *getter) Get(ctx context.Context, id valuer.UUID) (*types.Organization, error) {
|
||||||
|
return module.store.Get(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (module *getter) List(ctx context.Context) ([]*types.Organization, error) {
|
||||||
|
return module.store.GetAll(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (module *getter) ListByOwnedKeyRange(ctx context.Context) ([]*types.Organization, error) {
|
||||||
|
start, end, err := module.sharder.GetMyOwnedKeyRange(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return module.store.ListByKeyRange(ctx, start, end)
|
||||||
|
}
|
@ -15,11 +15,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
module organization.Module
|
orgGetter organization.Getter
|
||||||
|
orgSetter organization.Setter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(module organization.Module) organization.Handler {
|
func NewHandler(orgGetter organization.Getter, orgSetter organization.Setter) organization.Handler {
|
||||||
return &handler{module: module}
|
return &handler{orgGetter: orgGetter, orgSetter: orgSetter}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *handler) Get(rw http.ResponseWriter, r *http.Request) {
|
func (handler *handler) Get(rw http.ResponseWriter, r *http.Request) {
|
||||||
@ -38,7 +39,7 @@ func (handler *handler) Get(rw http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
organization, err := handler.module.Get(ctx, orgID)
|
organization, err := handler.orgGetter.Get(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
render.Error(rw, err)
|
render.Error(rw, err)
|
||||||
return
|
return
|
||||||
@ -70,7 +71,7 @@ func (handler *handler) Update(rw http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req.ID = orgID
|
req.ID = orgID
|
||||||
err = handler.module.Update(ctx, req)
|
err = handler.orgSetter.Update(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
render.Error(rw, err)
|
render.Error(rw, err)
|
||||||
return
|
return
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
package implorganization
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
|
||||||
"github.com/SigNoz/signoz/pkg/valuer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type module struct {
|
|
||||||
store types.OrganizationStore
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewModule(organizationStore types.OrganizationStore) organization.Module {
|
|
||||||
return &module{store: organizationStore}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (module *module) Create(ctx context.Context, organization *types.Organization) error {
|
|
||||||
return module.store.Create(ctx, organization)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (module *module) Get(ctx context.Context, id valuer.UUID) (*types.Organization, error) {
|
|
||||||
return module.store.Get(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (module *module) GetAll(ctx context.Context) ([]*types.Organization, error) {
|
|
||||||
return module.store.GetAll(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (module *module) Update(ctx context.Context, updatedOrganization *types.Organization) error {
|
|
||||||
return module.store.Update(ctx, updatedOrganization)
|
|
||||||
}
|
|
40
pkg/modules/organization/implorganization/setter.go
Normal file
40
pkg/modules/organization/implorganization/setter.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package implorganization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/quickfilter"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type setter struct {
|
||||||
|
store types.OrganizationStore
|
||||||
|
alertmanager alertmanager.Alertmanager
|
||||||
|
quickfilter quickfilter.Module
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSetter(store types.OrganizationStore, alertmanager alertmanager.Alertmanager, quickfilter quickfilter.Module) organization.Setter {
|
||||||
|
return &setter{store: store, alertmanager: alertmanager, quickfilter: quickfilter}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (module *setter) Create(ctx context.Context, organization *types.Organization) error {
|
||||||
|
if err := module.store.Create(ctx, organization); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := module.alertmanager.SetDefaultConfig(ctx, organization.ID.StringValue()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := module.quickfilter.SetDefaultConfig(ctx, organization.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (module *setter) Update(ctx context.Context, updatedOrganization *types.Organization) error {
|
||||||
|
return module.store.Update(ctx, updatedOrganization)
|
||||||
|
}
|
@ -92,3 +92,20 @@ func (store *store) Delete(ctx context.Context, id valuer.UUID) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (store *store) ListByKeyRange(ctx context.Context, start, end uint32) ([]*types.Organization, error) {
|
||||||
|
organizations := make([]*types.Organization, 0)
|
||||||
|
err := store.
|
||||||
|
sqlstore.
|
||||||
|
BunDB().
|
||||||
|
NewSelect().
|
||||||
|
Model(&organizations).
|
||||||
|
Where("key >= ?", start).
|
||||||
|
Where("key <= ?", end).
|
||||||
|
Scan(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return organizations, nil
|
||||||
|
}
|
||||||
|
@ -8,17 +8,22 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/valuer"
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Module interface {
|
type Getter interface {
|
||||||
// Create creates the given organization
|
|
||||||
Create(context.Context, *types.Organization) error
|
|
||||||
|
|
||||||
// Get gets the organization based on the given id
|
// Get gets the organization based on the given id
|
||||||
Get(context.Context, valuer.UUID) (*types.Organization, error)
|
Get(context.Context, valuer.UUID) (*types.Organization, error)
|
||||||
|
|
||||||
// GetAll gets all the organizations
|
// Lists all the organizations
|
||||||
GetAll(context.Context) ([]*types.Organization, error)
|
List(context.Context) ([]*types.Organization, error)
|
||||||
|
|
||||||
// Update updates the given organization based on id present
|
// ListByOwnedKeyRange gets all the organizations owned by the instance
|
||||||
|
ListByOwnedKeyRange(context.Context) ([]*types.Organization, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Setter interface {
|
||||||
|
// Create creates the given organization
|
||||||
|
Create(context.Context, *types.Organization) error
|
||||||
|
|
||||||
|
// Update updates the given organization
|
||||||
Update(context.Context, *types.Organization) error
|
Update(context.Context, *types.Organization) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
235
pkg/modules/tracefunnel/impltracefunnel/handler.go
Normal file
235
pkg/modules/tracefunnel/impltracefunnel/handler.go
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
package impltracefunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
|
"github.com/SigNoz/signoz/pkg/http/render"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/tracefunnel"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
|
tf "github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
type handler struct {
|
||||||
|
module tracefunnel.Module
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(module tracefunnel.Module) tracefunnel.Handler {
|
||||||
|
return &handler{module: module}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (handler *handler) New(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
var req tf.PostableFunnel
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
funnel, err := handler.module.Create(r.Context(), req.Timestamp, req.Name, valuer.MustNewUUID(claims.UserID), valuer.MustNewUUID(claims.OrgID))
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"failed to create funnel: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := tf.ConstructFunnelResponse(funnel, &claims)
|
||||||
|
render.Success(rw, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (handler *handler) UpdateSteps(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
var req tf.PostableFunnel
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedAt, err := tf.ValidateAndConvertTimestamp(req.Timestamp)
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
funnel, err := handler.module.Get(r.Context(), req.FunnelID, valuer.MustNewUUID(claims.OrgID))
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"funnel not found: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
steps, err := tf.ProcessFunnelSteps(req.Steps)
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
funnel.Steps = steps
|
||||||
|
funnel.UpdatedAt = updatedAt
|
||||||
|
funnel.UpdatedBy = claims.UserID
|
||||||
|
|
||||||
|
if req.Name != "" {
|
||||||
|
funnel.Name = req.Name
|
||||||
|
}
|
||||||
|
if req.Description != "" {
|
||||||
|
funnel.Description = req.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := handler.module.Update(r.Context(), funnel, valuer.MustNewUUID(claims.UserID)); err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"failed to update funnel in database: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedFunnel, err := handler.module.Get(r.Context(), funnel.ID, valuer.MustNewUUID(claims.OrgID))
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"failed to get updated funnel: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := tf.ConstructFunnelResponse(updatedFunnel, &claims)
|
||||||
|
render.Success(rw, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (handler *handler) UpdateFunnel(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
var req tf.PostableFunnel
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedAt, err := tf.ValidateAndConvertTimestamp(req.Timestamp)
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
funnelID := vars["funnel_id"]
|
||||||
|
|
||||||
|
funnel, err := handler.module.Get(r.Context(), valuer.MustNewUUID(funnelID), valuer.MustNewUUID(claims.OrgID))
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"funnel not found: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
funnel.UpdatedAt = updatedAt
|
||||||
|
funnel.UpdatedBy = claims.UserID
|
||||||
|
|
||||||
|
if req.Name != "" {
|
||||||
|
funnel.Name = req.Name
|
||||||
|
}
|
||||||
|
if req.Description != "" {
|
||||||
|
funnel.Description = req.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := handler.module.Update(r.Context(), funnel, valuer.MustNewUUID(claims.UserID)); err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"failed to update funnel in database: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedFunnel, err := handler.module.Get(r.Context(), funnel.ID, valuer.MustNewUUID(claims.OrgID))
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"failed to get updated funnel: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := tf.ConstructFunnelResponse(updatedFunnel, &claims)
|
||||||
|
render.Success(rw, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (handler *handler) List(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
funnels, err := handler.module.List(r.Context(), valuer.MustNewUUID(claims.OrgID))
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"failed to list funnels: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response []tf.GettableFunnel
|
||||||
|
for _, f := range funnels {
|
||||||
|
response = append(response, tf.ConstructFunnelResponse(f, &claims))
|
||||||
|
}
|
||||||
|
|
||||||
|
render.Success(rw, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (handler *handler) Get(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
funnelID := vars["funnel_id"]
|
||||||
|
|
||||||
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
funnel, err := handler.module.Get(r.Context(), valuer.MustNewUUID(funnelID), valuer.MustNewUUID(claims.OrgID))
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"funnel not found: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response := tf.ConstructFunnelResponse(funnel, &claims)
|
||||||
|
render.Success(rw, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (handler *handler) Delete(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
funnelID := vars["funnel_id"]
|
||||||
|
|
||||||
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
render.Error(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := handler.module.Delete(r.Context(), valuer.MustNewUUID(funnelID), valuer.MustNewUUID(claims.OrgID)); err != nil {
|
||||||
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
||||||
|
errors.CodeInvalidInput,
|
||||||
|
"failed to delete funnel: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
render.Success(rw, http.StatusOK, nil)
|
||||||
|
}
|
173
pkg/modules/tracefunnel/impltracefunnel/handler_test.go
Normal file
173
pkg/modules/tracefunnel/impltracefunnel/handler_test.go
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
package impltracefunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
|
traceFunnels "github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockModule struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockModule) Create(ctx context.Context, timestamp int64, name string, userID valuer.UUID, orgID valuer.UUID) (*traceFunnels.StorableFunnel, error) {
|
||||||
|
args := m.Called(ctx, timestamp, name, userID, orgID)
|
||||||
|
return args.Get(0).(*traceFunnels.StorableFunnel), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockModule) Get(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) (*traceFunnels.StorableFunnel, error) {
|
||||||
|
args := m.Called(ctx, funnelID, orgID)
|
||||||
|
return args.Get(0).(*traceFunnels.StorableFunnel), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockModule) Update(ctx context.Context, funnel *traceFunnels.StorableFunnel, userID valuer.UUID) error {
|
||||||
|
args := m.Called(ctx, funnel, userID)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockModule) List(ctx context.Context, orgID valuer.UUID) ([]*traceFunnels.StorableFunnel, error) {
|
||||||
|
args := m.Called(ctx, orgID)
|
||||||
|
return args.Get(0).([]*traceFunnels.StorableFunnel), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockModule) Delete(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) error {
|
||||||
|
args := m.Called(ctx, funnelID, orgID)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockModule) Save(ctx context.Context, funnel *traceFunnels.StorableFunnel, userID valuer.UUID, orgID valuer.UUID) error {
|
||||||
|
args := m.Called(ctx, funnel, userID, orgID)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockModule) GetFunnelMetadata(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) (int64, int64, string, error) {
|
||||||
|
args := m.Called(ctx, funnelID, orgID)
|
||||||
|
return args.Get(0).(int64), args.Get(1).(int64), args.String(2), args.Error(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_List(t *testing.T) {
|
||||||
|
mockModule := new(MockModule)
|
||||||
|
handler := NewHandler(mockModule)
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/trace-funnels/list", nil)
|
||||||
|
|
||||||
|
orgID := valuer.GenerateUUID()
|
||||||
|
claims := authtypes.Claims{
|
||||||
|
OrgID: orgID.String(),
|
||||||
|
}
|
||||||
|
req = req.WithContext(authtypes.NewContextWithClaims(req.Context(), claims))
|
||||||
|
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
|
||||||
|
funnel1ID := valuer.GenerateUUID()
|
||||||
|
funnel2ID := valuer.GenerateUUID()
|
||||||
|
expectedFunnels := []*traceFunnels.StorableFunnel{
|
||||||
|
{
|
||||||
|
Identifiable: types.Identifiable{
|
||||||
|
ID: funnel1ID,
|
||||||
|
},
|
||||||
|
Name: "funnel-1",
|
||||||
|
OrgID: orgID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Identifiable: types.Identifiable{
|
||||||
|
ID: funnel2ID,
|
||||||
|
},
|
||||||
|
Name: "funnel-2",
|
||||||
|
OrgID: orgID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mockModule.On("List", req.Context(), orgID).Return(expectedFunnels, nil)
|
||||||
|
|
||||||
|
handler.List(rr, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, rr.Code)
|
||||||
|
|
||||||
|
var response struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Data []traceFunnels.GettableFunnel `json:"data"`
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(rr.Body.Bytes(), &response)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "success", response.Status)
|
||||||
|
assert.Len(t, response.Data, 2)
|
||||||
|
assert.Equal(t, "funnel-1", response.Data[0].FunnelName)
|
||||||
|
assert.Equal(t, "funnel-2", response.Data[1].FunnelName)
|
||||||
|
|
||||||
|
mockModule.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_Get(t *testing.T) {
|
||||||
|
mockModule := new(MockModule)
|
||||||
|
handler := NewHandler(mockModule)
|
||||||
|
|
||||||
|
funnelID := valuer.GenerateUUID()
|
||||||
|
orgID := valuer.GenerateUUID()
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/trace-funnels/"+funnelID.String(), nil)
|
||||||
|
req = mux.SetURLVars(req, map[string]string{"funnel_id": funnelID.String()})
|
||||||
|
req = req.WithContext(authtypes.NewContextWithClaims(req.Context(), authtypes.Claims{
|
||||||
|
OrgID: orgID.String(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
|
||||||
|
expectedFunnel := &traceFunnels.StorableFunnel{
|
||||||
|
Identifiable: types.Identifiable{
|
||||||
|
ID: funnelID,
|
||||||
|
},
|
||||||
|
Name: "test-funnel",
|
||||||
|
OrgID: orgID,
|
||||||
|
}
|
||||||
|
|
||||||
|
mockModule.On("Get", req.Context(), funnelID, orgID).Return(expectedFunnel, nil)
|
||||||
|
|
||||||
|
handler.Get(rr, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, rr.Code)
|
||||||
|
|
||||||
|
var response struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Data traceFunnels.GettableFunnel `json:"data"`
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(rr.Body.Bytes(), &response)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "success", response.Status)
|
||||||
|
assert.Equal(t, "test-funnel", response.Data.FunnelName)
|
||||||
|
assert.Equal(t, expectedFunnel.OrgID.String(), response.Data.OrgID)
|
||||||
|
|
||||||
|
mockModule.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_Delete(t *testing.T) {
|
||||||
|
mockModule := new(MockModule)
|
||||||
|
handler := NewHandler(mockModule)
|
||||||
|
|
||||||
|
funnelID := valuer.GenerateUUID()
|
||||||
|
orgID := valuer.GenerateUUID()
|
||||||
|
req := httptest.NewRequest(http.MethodDelete, "/api/v1/trace-funnels/"+funnelID.String(), nil)
|
||||||
|
req = mux.SetURLVars(req, map[string]string{"funnel_id": funnelID.String()})
|
||||||
|
req = req.WithContext(authtypes.NewContextWithClaims(req.Context(), authtypes.Claims{
|
||||||
|
OrgID: orgID.String(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
|
||||||
|
mockModule.On("Delete", req.Context(), funnelID, orgID).Return(nil)
|
||||||
|
|
||||||
|
handler.Delete(rr, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, rr.Code)
|
||||||
|
|
||||||
|
mockModule.AssertExpectations(t)
|
||||||
|
}
|
96
pkg/modules/tracefunnel/impltracefunnel/module.go
Normal file
96
pkg/modules/tracefunnel/impltracefunnel/module.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package impltracefunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/tracefunnel"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
|
traceFunnels "github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type module struct {
|
||||||
|
store traceFunnels.FunnelStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewModule(store traceFunnels.FunnelStore) tracefunnel.Module {
|
||||||
|
return &module{
|
||||||
|
store: store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (module *module) Create(ctx context.Context, timestamp int64, name string, userID valuer.UUID, orgID valuer.UUID) (*traceFunnels.StorableFunnel, error) {
|
||||||
|
funnel := &traceFunnels.StorableFunnel{
|
||||||
|
Name: name,
|
||||||
|
OrgID: orgID,
|
||||||
|
}
|
||||||
|
funnel.CreatedAt = time.Unix(0, timestamp*1000000) // Convert to nanoseconds
|
||||||
|
funnel.CreatedBy = userID.String()
|
||||||
|
|
||||||
|
// Set up the user relationship
|
||||||
|
funnel.CreatedByUser = &types.User{
|
||||||
|
Identifiable: types.Identifiable{
|
||||||
|
ID: userID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if funnel.ID.IsZero() {
|
||||||
|
funnel.ID = valuer.GenerateUUID()
|
||||||
|
}
|
||||||
|
|
||||||
|
if funnel.CreatedAt.IsZero() {
|
||||||
|
funnel.CreatedAt = time.Now()
|
||||||
|
}
|
||||||
|
if funnel.UpdatedAt.IsZero() {
|
||||||
|
funnel.UpdatedAt = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set created_by if CreatedByUser is present
|
||||||
|
if funnel.CreatedByUser != nil {
|
||||||
|
funnel.CreatedBy = funnel.CreatedByUser.Identifiable.ID.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := module.store.Create(ctx, funnel); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create funnel: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return funnel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets a funnel by ID
|
||||||
|
func (module *module) Get(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) (*traceFunnels.StorableFunnel, error) {
|
||||||
|
return module.store.Get(ctx, funnelID, orgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates a funnel
|
||||||
|
func (module *module) Update(ctx context.Context, funnel *traceFunnels.StorableFunnel, userID valuer.UUID) error {
|
||||||
|
funnel.UpdatedBy = userID.String()
|
||||||
|
return module.store.Update(ctx, funnel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List lists all funnels for an organization
|
||||||
|
func (module *module) List(ctx context.Context, orgID valuer.UUID) ([]*traceFunnels.StorableFunnel, error) {
|
||||||
|
funnels, err := module.store.List(ctx, orgID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to list funnels: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return funnels, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes a funnel
|
||||||
|
func (module *module) Delete(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) error {
|
||||||
|
return module.store.Delete(ctx, funnelID, orgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFunnelMetadata gets metadata for a funnel
|
||||||
|
func (module *module) GetFunnelMetadata(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) (int64, int64, string, error) {
|
||||||
|
funnel, err := module.store.Get(ctx, funnelID, orgID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return funnel.CreatedAt.UnixNano() / 1000000, funnel.UpdatedAt.UnixNano() / 1000000, funnel.Description, nil
|
||||||
|
}
|
114
pkg/modules/tracefunnel/impltracefunnel/store.go
Normal file
114
pkg/modules/tracefunnel/impltracefunnel/store.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package impltracefunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
|
traceFunnels "github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type store struct {
|
||||||
|
sqlstore sqlstore.SQLStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStore(sqlstore sqlstore.SQLStore) traceFunnels.FunnelStore {
|
||||||
|
return &store{sqlstore: sqlstore}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *store) Create(ctx context.Context, funnel *traceFunnels.StorableFunnel) error {
|
||||||
|
// Check if a funnel with the same name already exists in the organization
|
||||||
|
exists, err := store.
|
||||||
|
sqlstore.
|
||||||
|
BunDB().
|
||||||
|
NewSelect().
|
||||||
|
Model(new(traceFunnels.StorableFunnel)).
|
||||||
|
Where("name = ? AND org_id = ?", funnel.Name, funnel.OrgID.String()).
|
||||||
|
Exists(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to check for existing funnelr")
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
return store.sqlstore.WrapAlreadyExistsErrf(nil, traceFunnels.ErrFunnelAlreadyExists, "a funnel with name '%s' already exists in this organization", funnel.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = store.
|
||||||
|
sqlstore.
|
||||||
|
BunDB().
|
||||||
|
NewInsert().
|
||||||
|
Model(funnel).
|
||||||
|
Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to create funnels")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a funnel by ID
|
||||||
|
func (store *store) Get(ctx context.Context, uuid valuer.UUID, orgID valuer.UUID) (*traceFunnels.StorableFunnel, error) {
|
||||||
|
funnel := &traceFunnels.StorableFunnel{}
|
||||||
|
err := store.
|
||||||
|
sqlstore.
|
||||||
|
BunDB().
|
||||||
|
NewSelect().
|
||||||
|
Model(funnel).
|
||||||
|
Relation("CreatedByUser").
|
||||||
|
Where("?TableAlias.id = ? AND ?TableAlias.org_id = ?", uuid.String(), orgID.String()).
|
||||||
|
Scan(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to get funnels")
|
||||||
|
}
|
||||||
|
return funnel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates an existing funnel
|
||||||
|
func (store *store) Update(ctx context.Context, funnel *traceFunnels.StorableFunnel) error {
|
||||||
|
funnel.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
_, err := store.
|
||||||
|
sqlstore.
|
||||||
|
BunDB().
|
||||||
|
NewUpdate().
|
||||||
|
Model(funnel).
|
||||||
|
WherePK().
|
||||||
|
Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return store.sqlstore.WrapAlreadyExistsErrf(err, traceFunnels.ErrFunnelAlreadyExists, "a funnel with name '%s' already exists in this organization", funnel.Name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List retrieves all funnels for a given organization
|
||||||
|
func (store *store) List(ctx context.Context, orgID valuer.UUID) ([]*traceFunnels.StorableFunnel, error) {
|
||||||
|
var funnels []*traceFunnels.StorableFunnel
|
||||||
|
err := store.
|
||||||
|
sqlstore.
|
||||||
|
BunDB().
|
||||||
|
NewSelect().
|
||||||
|
Model(&funnels).
|
||||||
|
Relation("CreatedByUser").
|
||||||
|
Where("?TableAlias.org_id = ?", orgID.String()).
|
||||||
|
Scan(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to list funnels")
|
||||||
|
}
|
||||||
|
return funnels, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes a funnel by ID
|
||||||
|
func (store *store) Delete(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) error {
|
||||||
|
_, err := store.
|
||||||
|
sqlstore.
|
||||||
|
BunDB().
|
||||||
|
NewDelete().
|
||||||
|
Model(new(traceFunnels.StorableFunnel)).
|
||||||
|
Where("id = ? AND org_id = ?", funnelID.String(), orgID.String()).
|
||||||
|
Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to delete funnel")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
38
pkg/modules/tracefunnel/tracefunnel.go
Normal file
38
pkg/modules/tracefunnel/tracefunnel.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package tracefunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
traceFunnels "github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Module defines the interface for trace funnel operations
|
||||||
|
type Module interface {
|
||||||
|
Create(ctx context.Context, timestamp int64, name string, userID valuer.UUID, orgID valuer.UUID) (*traceFunnels.StorableFunnel, error)
|
||||||
|
|
||||||
|
Get(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) (*traceFunnels.StorableFunnel, error)
|
||||||
|
|
||||||
|
Update(ctx context.Context, funnel *traceFunnels.StorableFunnel, userID valuer.UUID) error
|
||||||
|
|
||||||
|
List(ctx context.Context, orgID valuer.UUID) ([]*traceFunnels.StorableFunnel, error)
|
||||||
|
|
||||||
|
Delete(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) error
|
||||||
|
|
||||||
|
GetFunnelMetadata(ctx context.Context, funnelID valuer.UUID, orgID valuer.UUID) (int64, int64, string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Handler interface {
|
||||||
|
New(http.ResponseWriter, *http.Request)
|
||||||
|
|
||||||
|
UpdateSteps(http.ResponseWriter, *http.Request)
|
||||||
|
|
||||||
|
UpdateFunnel(http.ResponseWriter, *http.Request)
|
||||||
|
|
||||||
|
List(http.ResponseWriter, *http.Request)
|
||||||
|
|
||||||
|
Get(http.ResponseWriter, *http.Request)
|
||||||
|
|
||||||
|
Delete(http.ResponseWriter, *http.Request)
|
||||||
|
}
|
183
pkg/modules/tracefunnel/tracefunneltest/module_test.go
Normal file
183
pkg/modules/tracefunnel/tracefunneltest/module_test.go
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
package tracefunneltest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/tracefunnel/impltracefunnel"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
|
traceFunnels "github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockStore struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockStore) Create(ctx context.Context, funnel *traceFunnels.StorableFunnel) error {
|
||||||
|
args := m.Called(ctx, funnel)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockStore) Get(ctx context.Context, uuid valuer.UUID, orgID valuer.UUID) (*traceFunnels.StorableFunnel, error) {
|
||||||
|
args := m.Called(ctx, uuid, orgID)
|
||||||
|
return args.Get(0).(*traceFunnels.StorableFunnel), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockStore) List(ctx context.Context, orgID valuer.UUID) ([]*traceFunnels.StorableFunnel, error) {
|
||||||
|
args := m.Called(ctx, orgID)
|
||||||
|
return args.Get(0).([]*traceFunnels.StorableFunnel), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockStore) Update(ctx context.Context, funnel *traceFunnels.StorableFunnel) error {
|
||||||
|
args := m.Called(ctx, funnel)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockStore) Delete(ctx context.Context, uuid valuer.UUID, orgID valuer.UUID) error {
|
||||||
|
args := m.Called(ctx, uuid, orgID)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModule_Create(t *testing.T) {
|
||||||
|
mockStore := new(MockStore)
|
||||||
|
module := impltracefunnel.NewModule(mockStore)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
timestamp := time.Now().UnixMilli()
|
||||||
|
name := "test-funnel"
|
||||||
|
userID := valuer.GenerateUUID()
|
||||||
|
orgID := valuer.GenerateUUID()
|
||||||
|
|
||||||
|
mockStore.On("Create", ctx, mock.MatchedBy(func(f *traceFunnels.StorableFunnel) bool {
|
||||||
|
return f.Name == name &&
|
||||||
|
f.CreatedBy == userID.String() &&
|
||||||
|
f.OrgID == orgID &&
|
||||||
|
f.CreatedByUser != nil &&
|
||||||
|
f.CreatedByUser.ID == userID &&
|
||||||
|
f.CreatedAt.UnixNano()/1000000 == timestamp
|
||||||
|
})).Return(nil)
|
||||||
|
|
||||||
|
funnel, err := module.Create(ctx, timestamp, name, userID, orgID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, funnel)
|
||||||
|
assert.Equal(t, name, funnel.Name)
|
||||||
|
assert.Equal(t, userID.String(), funnel.CreatedBy)
|
||||||
|
assert.Equal(t, orgID, funnel.OrgID)
|
||||||
|
assert.NotNil(t, funnel.CreatedByUser)
|
||||||
|
assert.Equal(t, userID, funnel.CreatedByUser.ID)
|
||||||
|
|
||||||
|
mockStore.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModule_Get(t *testing.T) {
|
||||||
|
mockStore := new(MockStore)
|
||||||
|
module := impltracefunnel.NewModule(mockStore)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
funnelID := valuer.GenerateUUID()
|
||||||
|
orgID := valuer.GenerateUUID()
|
||||||
|
expectedFunnel := &traceFunnels.StorableFunnel{
|
||||||
|
Name: "test-funnel",
|
||||||
|
}
|
||||||
|
|
||||||
|
mockStore.On("Get", ctx, funnelID, orgID).Return(expectedFunnel, nil)
|
||||||
|
|
||||||
|
funnel, err := module.Get(ctx, funnelID, orgID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expectedFunnel, funnel)
|
||||||
|
|
||||||
|
mockStore.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModule_Update(t *testing.T) {
|
||||||
|
mockStore := new(MockStore)
|
||||||
|
module := impltracefunnel.NewModule(mockStore)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
userID := valuer.GenerateUUID()
|
||||||
|
funnel := &traceFunnels.StorableFunnel{
|
||||||
|
Name: "test-funnel",
|
||||||
|
}
|
||||||
|
|
||||||
|
mockStore.On("Update", ctx, funnel).Return(nil)
|
||||||
|
|
||||||
|
err := module.Update(ctx, funnel, userID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, userID.String(), funnel.UpdatedBy)
|
||||||
|
|
||||||
|
mockStore.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModule_List(t *testing.T) {
|
||||||
|
mockStore := new(MockStore)
|
||||||
|
module := impltracefunnel.NewModule(mockStore)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
orgID := valuer.GenerateUUID()
|
||||||
|
expectedFunnels := []*traceFunnels.StorableFunnel{
|
||||||
|
{
|
||||||
|
Name: "funnel-1",
|
||||||
|
OrgID: orgID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "funnel-2",
|
||||||
|
OrgID: orgID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mockStore.On("List", ctx, orgID).Return(expectedFunnels, nil)
|
||||||
|
|
||||||
|
funnels, err := module.List(ctx, orgID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, funnels, 2)
|
||||||
|
assert.Equal(t, expectedFunnels, funnels)
|
||||||
|
|
||||||
|
mockStore.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModule_Delete(t *testing.T) {
|
||||||
|
mockStore := new(MockStore)
|
||||||
|
module := impltracefunnel.NewModule(mockStore)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
funnelID := valuer.GenerateUUID()
|
||||||
|
orgID := valuer.GenerateUUID()
|
||||||
|
|
||||||
|
mockStore.On("Delete", ctx, funnelID, orgID).Return(nil)
|
||||||
|
|
||||||
|
err := module.Delete(ctx, funnelID, orgID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
mockStore.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModule_GetFunnelMetadata(t *testing.T) {
|
||||||
|
mockStore := new(MockStore)
|
||||||
|
module := impltracefunnel.NewModule(mockStore)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
funnelID := valuer.GenerateUUID()
|
||||||
|
orgID := valuer.GenerateUUID()
|
||||||
|
now := time.Now()
|
||||||
|
expectedFunnel := &traceFunnels.StorableFunnel{
|
||||||
|
Description: "test description",
|
||||||
|
TimeAuditable: types.TimeAuditable{
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mockStore.On("Get", ctx, funnelID, orgID).Return(expectedFunnel, nil)
|
||||||
|
|
||||||
|
createdAt, updatedAt, description, err := module.GetFunnelMetadata(ctx, funnelID, orgID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, now.UnixNano()/1000000, createdAt)
|
||||||
|
assert.Equal(t, now.UnixNano()/1000000, updatedAt)
|
||||||
|
assert.Equal(t, "test description", description)
|
||||||
|
|
||||||
|
mockStore.AssertExpectations(t)
|
||||||
|
}
|
@ -11,8 +11,10 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/emailing"
|
"github.com/SigNoz/signoz/pkg/emailing"
|
||||||
"github.com/SigNoz/signoz/pkg/errors"
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/constants"
|
"github.com/SigNoz/signoz/pkg/query-service/constants"
|
||||||
|
"github.com/SigNoz/signoz/pkg/query-service/model"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/telemetry"
|
"github.com/SigNoz/signoz/pkg/query-service/telemetry"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
@ -22,20 +24,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Module struct {
|
type Module struct {
|
||||||
store types.UserStore
|
store types.UserStore
|
||||||
jwt *authtypes.JWT
|
jwt *authtypes.JWT
|
||||||
emailing emailing.Emailing
|
emailing emailing.Emailing
|
||||||
settings factory.ScopedProviderSettings
|
settings factory.ScopedProviderSettings
|
||||||
|
orgSetter organization.Setter
|
||||||
}
|
}
|
||||||
|
|
||||||
// This module is a WIP, don't take inspiration from this.
|
// This module is a WIP, don't take inspiration from this.
|
||||||
func NewModule(store types.UserStore, jwt *authtypes.JWT, emailing emailing.Emailing, providerSettings factory.ProviderSettings) user.Module {
|
func NewModule(store types.UserStore, jwt *authtypes.JWT, emailing emailing.Emailing, providerSettings factory.ProviderSettings, orgSetter organization.Setter) user.Module {
|
||||||
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/modules/user/impluser")
|
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/modules/user/impluser")
|
||||||
return &Module{
|
return &Module{
|
||||||
store: store,
|
store: store,
|
||||||
jwt: jwt,
|
jwt: jwt,
|
||||||
emailing: emailing,
|
emailing: emailing,
|
||||||
settings: settings,
|
settings: settings,
|
||||||
|
orgSetter: orgSetter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,3 +542,36 @@ func (m *Module) ListDomains(ctx context.Context, orgID valuer.UUID) ([]*types.G
|
|||||||
func (m *Module) UpdateDomain(ctx context.Context, domain *types.GettableOrgDomain) error {
|
func (m *Module) UpdateDomain(ctx context.Context, domain *types.GettableOrgDomain) error {
|
||||||
return m.store.UpdateDomain(ctx, domain)
|
return m.store.UpdateDomain(ctx, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Module) Register(ctx context.Context, req *types.PostableRegisterOrgAndAdmin) (*types.User, error) {
|
||||||
|
if req.Email == "" {
|
||||||
|
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "email is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Password == "" {
|
||||||
|
return nil, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "password is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
organization := types.NewOrganization(req.OrgDisplayName)
|
||||||
|
err := m.orgSetter.Create(ctx, organization)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.InternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := types.NewUser(req.Name, req.Email, types.RoleAdmin.String(), organization.ID.StringValue())
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.InternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
password, err := types.NewFactorPassword(req.Password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.InternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err = m.CreateUserWithPassword(ctx, user, password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.InternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
@ -62,6 +62,9 @@ type Module interface {
|
|||||||
ListAPIKeys(ctx context.Context, orgID valuer.UUID) ([]*types.StorableAPIKeyUser, error)
|
ListAPIKeys(ctx context.Context, orgID valuer.UUID) ([]*types.StorableAPIKeyUser, error)
|
||||||
RevokeAPIKey(ctx context.Context, id, removedByUserID valuer.UUID) error
|
RevokeAPIKey(ctx context.Context, id, removedByUserID valuer.UUID) error
|
||||||
GetAPIKey(ctx context.Context, orgID valuer.UUID, id valuer.UUID) (*types.StorableAPIKeyUser, error)
|
GetAPIKey(ctx context.Context, orgID valuer.UUID, id valuer.UUID) (*types.StorableAPIKeyUser, error)
|
||||||
|
|
||||||
|
// Register
|
||||||
|
Register(ctx context.Context, req *types.PostableRegisterOrgAndAdmin) (*types.User, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
|
@ -6267,9 +6267,6 @@ func (r *ClickHouseReader) GetUpdatedMetricsMetadata(ctx context.Context, orgID
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
cachedMetadata[metricName] = metadata
|
cachedMetadata[metricName] = metadata
|
||||||
} else {
|
} else {
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error retrieving metrics metadata from cache", zap.String("metric_name", metricName), zap.Error(err))
|
|
||||||
}
|
|
||||||
missingMetrics = append(missingMetrics, metricName)
|
missingMetrics = append(missingMetrics, metricName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,23 @@ package cloudintegrations
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/emailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing/noopemailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerserver"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
||||||
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
|
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/model"
|
"github.com/SigNoz/signoz/pkg/query-service/model"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/utils"
|
"github.com/SigNoz/signoz/pkg/query-service/utils"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/signoz"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@ -24,11 +30,16 @@ func TestRegenerateConnectionUrlWithUpdatedConfig(t *testing.T) {
|
|||||||
controller, err := NewController(sqlStore)
|
controller, err := NewController(sqlStore)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
organizationModule := implorganization.NewModule(implorganization.NewStore(sqlStore))
|
|
||||||
providerSettings := instrumentationtest.New().ToProviderSettings()
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
emailing, _ := noopemailing.New(context.Background(), providerSettings, emailing.Config{})
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
userModule := impluser.NewModule(impluser.NewStore(sqlStore, providerSettings), nil, emailing, providerSettings)
|
require.NoError(err)
|
||||||
user, apiErr := createTestUser(organizationModule, userModule)
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlStore), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{Provider: "signoz", Signoz: alertmanager.Signoz{PollInterval: 10 * time.Second, Config: alertmanagerserver.NewConfig()}}, sqlStore, orgGetter)
|
||||||
|
require.NoError(err)
|
||||||
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
|
emailing := emailingtest.New()
|
||||||
|
modules := signoz.NewModules(sqlStore, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
|
user, apiErr := createTestUser(modules.OrgSetter, modules.User)
|
||||||
require.Nil(apiErr)
|
require.Nil(apiErr)
|
||||||
|
|
||||||
// should be able to generate connection url for
|
// should be able to generate connection url for
|
||||||
@ -74,11 +85,17 @@ func TestAgentCheckIns(t *testing.T) {
|
|||||||
sqlStore := utils.NewQueryServiceDBForTests(t)
|
sqlStore := utils.NewQueryServiceDBForTests(t)
|
||||||
controller, err := NewController(sqlStore)
|
controller, err := NewController(sqlStore)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
organizationModule := implorganization.NewModule(implorganization.NewStore(sqlStore))
|
|
||||||
providerSettings := instrumentationtest.New().ToProviderSettings()
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
emailing, _ := noopemailing.New(context.Background(), providerSettings, emailing.Config{})
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
userModule := impluser.NewModule(impluser.NewStore(sqlStore, providerSettings), nil, emailing, providerSettings)
|
require.NoError(err)
|
||||||
user, apiErr := createTestUser(organizationModule, userModule)
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlStore), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{Provider: "signoz", Signoz: alertmanager.Signoz{PollInterval: 10 * time.Second, Config: alertmanagerserver.NewConfig()}}, sqlStore, orgGetter)
|
||||||
|
require.NoError(err)
|
||||||
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
|
emailing := emailingtest.New()
|
||||||
|
modules := signoz.NewModules(sqlStore, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
|
user, apiErr := createTestUser(modules.OrgSetter, modules.User)
|
||||||
require.Nil(apiErr)
|
require.Nil(apiErr)
|
||||||
|
|
||||||
// An agent should be able to check in from a cloud account even
|
// An agent should be able to check in from a cloud account even
|
||||||
@ -164,11 +181,16 @@ func TestCantDisconnectNonExistentAccount(t *testing.T) {
|
|||||||
controller, err := NewController(sqlStore)
|
controller, err := NewController(sqlStore)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
organizationModule := implorganization.NewModule(implorganization.NewStore(sqlStore))
|
|
||||||
providerSettings := instrumentationtest.New().ToProviderSettings()
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
emailing, _ := noopemailing.New(context.Background(), providerSettings, emailing.Config{})
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
userModule := impluser.NewModule(impluser.NewStore(sqlStore, providerSettings), nil, emailing, providerSettings)
|
require.NoError(err)
|
||||||
user, apiErr := createTestUser(organizationModule, userModule)
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlStore), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{Provider: "signoz", Signoz: alertmanager.Signoz{PollInterval: 10 * time.Second, Config: alertmanagerserver.NewConfig()}}, sqlStore, orgGetter)
|
||||||
|
require.NoError(err)
|
||||||
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
|
emailing := emailingtest.New()
|
||||||
|
modules := signoz.NewModules(sqlStore, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
|
user, apiErr := createTestUser(modules.OrgSetter, modules.User)
|
||||||
require.Nil(apiErr)
|
require.Nil(apiErr)
|
||||||
|
|
||||||
// Attempting to disconnect a non-existent account should return error
|
// Attempting to disconnect a non-existent account should return error
|
||||||
@ -186,11 +208,16 @@ func TestConfigureService(t *testing.T) {
|
|||||||
controller, err := NewController(sqlStore)
|
controller, err := NewController(sqlStore)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
organizationModule := implorganization.NewModule(implorganization.NewStore(sqlStore))
|
|
||||||
providerSettings := instrumentationtest.New().ToProviderSettings()
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
emailing, _ := noopemailing.New(context.Background(), providerSettings, emailing.Config{})
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
userModule := impluser.NewModule(impluser.NewStore(sqlStore, providerSettings), nil, emailing, providerSettings)
|
require.NoError(err)
|
||||||
user, apiErr := createTestUser(organizationModule, userModule)
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlStore), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{Provider: "signoz", Signoz: alertmanager.Signoz{PollInterval: 10 * time.Second, Config: alertmanagerserver.NewConfig()}}, sqlStore, orgGetter)
|
||||||
|
require.NoError(err)
|
||||||
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
|
emailing := emailingtest.New()
|
||||||
|
modules := signoz.NewModules(sqlStore, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
|
user, apiErr := createTestUser(modules.OrgSetter, modules.User)
|
||||||
require.Nil(apiErr)
|
require.Nil(apiErr)
|
||||||
|
|
||||||
// create a connected account
|
// create a connected account
|
||||||
@ -305,7 +332,7 @@ func makeTestConnectedAccount(t *testing.T, orgId string, controller *Controller
|
|||||||
return acc
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestUser(organizationModule organization.Module, userModule user.Module) (*types.User, *model.ApiError) {
|
func createTestUser(organizationModule organization.Setter, userModule user.Module) (*types.User, *model.ApiError) {
|
||||||
// Create a test user for auth
|
// Create a test user for auth
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
organization := types.NewOrganization("test")
|
organization := types.NewOrganization("test")
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,851 @@
|
|||||||
|
{
|
||||||
|
"description": "View key AWS ECS metrics with an out of the box dashboard.\n",
|
||||||
|
"image":"data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%3Csvg%20width%3D%2280px%22%20height%3D%2280px%22%20viewBox%3D%220%200%2080%2080%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%3C!--%20Generator%3A%20Sketch%2064%20(93537)%20-%20https%3A%2F%2Fsketch.com%20--%3E%3Ctitle%3EIcon-Architecture%2F64%2FArch_Amazon-Elastic-Container-Service_64%3C%2Ftitle%3E%3Cdesc%3ECreated%20with%20Sketch.%3C%2Fdesc%3E%3Cdefs%3E%3ClinearGradient%20x1%3D%220%25%22%20y1%3D%22100%25%22%20x2%3D%22100%25%22%20y2%3D%220%25%22%20id%3D%22linearGradient-1%22%3E%3Cstop%20stop-color%3D%22%23C8511B%22%20offset%3D%220%25%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23FF9900%22%20offset%3D%22100%25%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Cg%20id%3D%22Icon-Architecture%2F64%2FArch_Amazon-Elastic-Container-Service_64%22%20stroke%3D%22none%22%20stroke-width%3D%221%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cg%20id%3D%22Icon-Architecture-BG%2F64%2FContainers%22%20fill%3D%22url(%23linearGradient-1)%22%3E%3Crect%20id%3D%22Rectangle%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2280%22%20height%3D%2280%22%3E%3C%2Frect%3E%3C%2Fg%3E%3Cpath%20d%3D%22M64%2C48.2340095%20L56%2C43.4330117%20L56%2C32.0000169%20C56%2C31.6440171%2055.812%2C31.3150172%2055.504%2C31.1360173%20L44%2C24.4260204%20L44%2C14.7520248%20L64%2C26.5710194%20L64%2C48.2340095%20Z%20M65.509%2C25.13902%20L43.509%2C12.139026%20C43.199%2C11.9560261%2042.818%2C11.9540261%2042.504%2C12.131026%20C42.193%2C12.3090259%2042%2C12.6410257%2042%2C13.0000256%20L42%2C25.0000201%20C42%2C25.3550199%2042.189%2C25.6840198%2042.496%2C25.8640197%20L54%2C32.5740166%20L54%2C44.0000114%20C54%2C44.3510113%2054.185%2C44.6770111%2054.486%2C44.857011%20L64.486%2C50.8570083%20C64.644%2C50.9520082%2064.822%2C51%2065%2C51%20C65.17%2C51%2065.34%2C50.9570082%2065.493%2C50.8700083%20C65.807%2C50.6930084%2066%2C50.3600085%2066%2C50%20L66%2C26.0000196%20C66%2C25.6460198%2065.814%2C25.31902%2065.509%2C25.13902%20L65.509%2C25.13902%20Z%20M40.445%2C66.863001%20L17%2C54.3990067%20L17%2C26.5710194%20L37%2C14.7520248%20L37%2C24.4510204%20L26.463%2C31.1560173%20C26.175%2C31.3400172%2026%2C31.6580171%2026%2C32.0000169%20L26%2C49.0000091%20C26%2C49.373009%2026.208%2C49.7150088%2026.538%2C49.8870087%20L39.991%2C56.8870055%20C40.28%2C57.0370055%2040.624%2C57.0380055%2040.912%2C56.8880055%20L53.964%2C50.1440086%20L61.996%2C54.9640064%20L40.445%2C66.863001%20Z%20M64.515%2C54.1420068%20L54.515%2C48.1420095%20C54.217%2C47.9640096%2053.849%2C47.9520096%2053.541%2C48.1120095%20L40.455%2C54.8730065%20L28%2C48.3930094%20L28%2C32.5490167%20L38.537%2C25.8440197%20C38.825%2C25.6600198%2039%2C25.3420199%2039%2C25.0000201%20L39%2C13.0000256%20C39%2C12.6410257%2038.808%2C12.3090259%2038.496%2C12.131026%20C38.184%2C11.9540261%2037.802%2C11.9560261%2037.491%2C12.139026%20L15.491%2C25.13902%20C15.187%2C25.31902%2015%2C25.6460198%2015%2C26.0000196%20L15%2C55%20C15%2C55.3690062%2015.204%2C55.7090061%2015.53%2C55.883006%20L39.984%2C68.8830001%20C40.131%2C68.961%2040.292%2C69%2040.453%2C69%20C40.62%2C69%2040.786%2C68.958%2040.937%2C68.8750001%20L64.484%2C55.875006%20C64.797%2C55.7020061%2064.993%2C55.3750062%2065.0001416%2C55.0180064%20C65.006%2C54.6600066%2064.821%2C54.3260067%2064.515%2C54.1420068%20L64.515%2C54.1420068%20Z%22%20id%3D%22Amazon-Elastic-Container-Service_Icon_64_Squid%22%20fill%3D%22%23FFFFFF%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E",
|
||||||
|
"layout": [
|
||||||
|
{
|
||||||
|
"h": 6,
|
||||||
|
"i": "f78becf8-0328-48b4-84b6-ff4dac325940",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 6,
|
||||||
|
"i": "2b4eac06-b426-4f78-b874-2e1734c4104b",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 6,
|
||||||
|
"i": "5bea2bc0-13a2-4937-bccb-60ffe8a43ad5",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 6,
|
||||||
|
"i": "6fac67b0-50ec-4b43-ac4b-320a303d0369",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"panelMap": {},
|
||||||
|
"tags": [],
|
||||||
|
"title": "AWS ECS Overview",
|
||||||
|
"uploadedGrafana": false,
|
||||||
|
"variables": {
|
||||||
|
"51f4fa2b-89c7-47c2-9795-f32cffaab985": {
|
||||||
|
"allSelected": false,
|
||||||
|
"customValue": "",
|
||||||
|
"description": "AWS Account ID",
|
||||||
|
"id": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
|
||||||
|
"key": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
|
||||||
|
"modificationUUID": "7b814d17-8fff-4ed6-a4ea-90e3b1a97584",
|
||||||
|
"multiSelect": false,
|
||||||
|
"name": "Account",
|
||||||
|
"order": 0,
|
||||||
|
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud.account.id') AS `cloud.account.id`\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_ECS_MemoryUtilization_max' GROUP BY `cloud.account.id`",
|
||||||
|
"showALLOption": false,
|
||||||
|
"sort": "DISABLED",
|
||||||
|
"textboxValue": "",
|
||||||
|
"type": "QUERY"
|
||||||
|
},
|
||||||
|
"9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0": {
|
||||||
|
"allSelected": false,
|
||||||
|
"customValue": "",
|
||||||
|
"description": "Account Region",
|
||||||
|
"id": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
|
||||||
|
"key": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
|
||||||
|
"modificationUUID": "3b5f499b-22a3-4c8a-847c-8d3811c9e6b2",
|
||||||
|
"multiSelect": false,
|
||||||
|
"name": "Region",
|
||||||
|
"order": 1,
|
||||||
|
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud.region') AS region\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_ECS_MemoryUtilization_max' AND JSONExtractString(labels, 'cloud.account.id') IN {{.Account}} GROUP BY region",
|
||||||
|
"showALLOption": false,
|
||||||
|
"sort": "ASC",
|
||||||
|
"textboxValue": "",
|
||||||
|
"type": "QUERY"
|
||||||
|
},
|
||||||
|
"bfbdbcbe-a168-4d81-b108-36339e249116": {
|
||||||
|
"allSelected": true,
|
||||||
|
"customValue": "",
|
||||||
|
"description": "ECS Cluster Name",
|
||||||
|
"id": "bfbdbcbe-a168-4d81-b108-36339e249116",
|
||||||
|
"key": "bfbdbcbe-a168-4d81-b108-36339e249116",
|
||||||
|
"modificationUUID": "9fb0d63c-ac6c-497d-82b3-17d95944e245",
|
||||||
|
"multiSelect": true,
|
||||||
|
"name": "Cluster",
|
||||||
|
"order": 2,
|
||||||
|
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'ClusterName') AS cluster\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_ECS_MemoryUtilization_max' AND JSONExtractString(labels, 'cloud.account.id') IN {{.Account}} AND JSONExtractString(labels, 'cloud.region') IN {{.Region}}\nGROUP BY cluster",
|
||||||
|
"showALLOption": true,
|
||||||
|
"sort": "ASC",
|
||||||
|
"textboxValue": "",
|
||||||
|
"type": "QUERY"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": "v4",
|
||||||
|
"widgets": [
|
||||||
|
{
|
||||||
|
"bucketCount": 30,
|
||||||
|
"bucketWidth": 0,
|
||||||
|
"columnUnits": {},
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "f78becf8-0328-48b4-84b6-ff4dac325940",
|
||||||
|
"isLogScale": false,
|
||||||
|
"isStacked": false,
|
||||||
|
"mergeAllActiveQueries": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "aws_ECS_MemoryUtilization_max--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "aws_ECS_MemoryUtilization_max",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "26ac617d",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.region--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.region",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Region"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "57172ed9",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.account.id--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.account.id",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "49b9f85e",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ClusterName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ClusterName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"$Cluster"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ServiceName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ServiceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ClusterName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ClusterName",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{ServiceName}} ({{ClusterName}})",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "avg",
|
||||||
|
"spaceAggregation": "max",
|
||||||
|
"stepInterval": 60,
|
||||||
|
"timeAggregation": "max"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "56068fdd-d523-4117-92fa-87c6518ad07c",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"selectedLogFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "body",
|
||||||
|
"type": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selectedTracesFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "serviceName--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "serviceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "name--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "durationNano--float64--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "durationNano",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "httpMethod--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "httpMethod",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "responseStatusCode--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "responseStatusCode",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"softMax": 0,
|
||||||
|
"softMin": 0,
|
||||||
|
"stackedBarChart": false,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Maximum Memory Utilization",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bucketCount": 30,
|
||||||
|
"bucketWidth": 0,
|
||||||
|
"columnUnits": {},
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "2b4eac06-b426-4f78-b874-2e1734c4104b",
|
||||||
|
"isLogScale": false,
|
||||||
|
"isStacked": false,
|
||||||
|
"mergeAllActiveQueries": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "aws_ECS_MemoryUtilization_min--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "aws_ECS_MemoryUtilization_min",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "min",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "cd4b8848",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.region--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.region",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Region"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "aa5115c6",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.account.id--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.account.id",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "f60677b6",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ClusterName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ClusterName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"$Cluster"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ServiceName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ServiceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ClusterName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ClusterName",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{ServiceName}} ({{ClusterName}})",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "avg",
|
||||||
|
"spaceAggregation": "min",
|
||||||
|
"stepInterval": 60,
|
||||||
|
"timeAggregation": "min"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "fb19342e-cbde-40d8-b12f-ad108698356b",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"selectedLogFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "body",
|
||||||
|
"type": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selectedTracesFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "serviceName--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "serviceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "name--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "durationNano--float64--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "durationNano",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "httpMethod--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "httpMethod",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "responseStatusCode--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "responseStatusCode",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"softMax": 0,
|
||||||
|
"softMin": 0,
|
||||||
|
"stackedBarChart": false,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Minimum Memory Utilization",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bucketCount": 30,
|
||||||
|
"bucketWidth": 0,
|
||||||
|
"columnUnits": {},
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "5bea2bc0-13a2-4937-bccb-60ffe8a43ad5",
|
||||||
|
"isLogScale": false,
|
||||||
|
"isStacked": false,
|
||||||
|
"mergeAllActiveQueries": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "aws_ECS_CPUUtilization_max--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "aws_ECS_CPUUtilization_max",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "2c13c8ee",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.region--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.region",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Region"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "f489f6a8",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.account.id--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.account.id",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "94012320",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ClusterName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ClusterName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"$Cluster"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ServiceName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ServiceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ClusterName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ClusterName",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{ServiceName}} ({{ClusterName}})",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "avg",
|
||||||
|
"spaceAggregation": "max",
|
||||||
|
"stepInterval": 60,
|
||||||
|
"timeAggregation": "max"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "273e0a76-c780-4b9a-9b03-2649d4227173",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"selectedLogFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "body",
|
||||||
|
"type": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selectedTracesFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "serviceName--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "serviceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "name--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "durationNano--float64--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "durationNano",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "httpMethod--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "httpMethod",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "responseStatusCode--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "responseStatusCode",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"softMax": 0,
|
||||||
|
"softMin": 0,
|
||||||
|
"stackedBarChart": false,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Maximum CPU Utilization",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bucketCount": 30,
|
||||||
|
"bucketWidth": 0,
|
||||||
|
"columnUnits": {},
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "6fac67b0-50ec-4b43-ac4b-320a303d0369",
|
||||||
|
"isLogScale": false,
|
||||||
|
"isStacked": false,
|
||||||
|
"mergeAllActiveQueries": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "aws_ECS_CPUUtilization_min--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "aws_ECS_CPUUtilization_min",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "min",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "758ba906",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.region--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.region",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Region"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4ffe6bf7",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.account.id--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.account.id",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "53d98059",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ClusterName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ClusterName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"$Cluster"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ServiceName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ServiceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "ClusterName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "ClusterName",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{ServiceName}} ({{ClusterName}})",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "avg",
|
||||||
|
"spaceAggregation": "min",
|
||||||
|
"stepInterval": 60,
|
||||||
|
"timeAggregation": "min"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "c89482b3-5a98-4e2c-be0d-ef036d7dac05",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"selectedLogFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "body",
|
||||||
|
"type": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selectedTracesFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "serviceName--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "serviceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "name--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "durationNano--float64--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "durationNano",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "httpMethod--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "httpMethod",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "responseStatusCode--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "responseStatusCode",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"softMax": 0,
|
||||||
|
"softMin": 0,
|
||||||
|
"stackedBarChart": false,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Minimum CPU Utilization",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,818 @@
|
|||||||
|
{
|
||||||
|
"description": "View key AWS SNS metrics with an out of the box dashboard.",
|
||||||
|
"image": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODBweCIgaGVpZ2h0PSI4MHB4IiB2aWV3Qm94PSIwIDAgODAgODAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDY0ICg5MzUzNykgLSBodHRwczovL3NrZXRjaC5jb20gLS0+CiAgICA8dGl0bGU+SWNvbi1BcmNoaXRlY3R1cmUvNjQvQXJjaF9BV1MtU2ltcGxlLU5vdGlmaWNhdGlvbi1TZXJ2aWNlXzY0PC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+CiAgICAgICAgPGxpbmVhckdyYWRpZW50IHgxPSIwJSIgeTE9IjEwMCUiIHgyPSIxMDAlIiB5Mj0iMCUiIGlkPSJsaW5lYXJHcmFkaWVudC0xIj4KICAgICAgICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0IwMDg0RCIgb2Zmc2V0PSIwJSI+PC9zdG9wPgogICAgICAgICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjRkY0RjhCIiBvZmZzZXQ9IjEwMCUiPjwvc3RvcD4KICAgICAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPC9kZWZzPgogICAgPGcgaWQ9Ikljb24tQXJjaGl0ZWN0dXJlLzY0L0FyY2hfQVdTLVNpbXBsZS1Ob3RpZmljYXRpb24tU2VydmljZV82NCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9Ikljb24tQXJjaGl0ZWN0dXJlLUJHLzY0L0FwcGxpY2F0aW9uLUludGVncmF0aW9uIiBmaWxsPSJ1cmwoI2xpbmVhckdyYWRpZW50LTEpIj4KICAgICAgICAgICAgPHJlY3QgaWQ9IlJlY3RhbmdsZSIgeD0iMCIgeT0iMCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIj48L3JlY3Q+CiAgICAgICAgPC9nPgogICAgICAgIDxwYXRoIGQ9Ik0xNywzOCBDMTguMTAzLDM4IDE5LDM4Ljg5NyAxOSw0MCBDMTksNDEuMTAzIDE4LjEwMyw0MiAxNyw0MiBDMTUuODk3LDQyIDE1LDQxLjEwMyAxNSw0MCBDMTUsMzguODk3IDE1Ljg5NywzOCAxNywzOCBMMTcsMzggWiBNNDEsNjQgQzI5LjMxNCw2NCAxOS4yODksNTUuNDY2IDE3LjE5NCw0My45OCBDMTguOTY1LDQzLjg5NCAyMC40MjcsNDIuNjU5IDIwLjg1Nyw0MSBMMjcsNDEgTDI3LDM5IEwyMC44NTcsMzkgQzIwLjQyNywzNy4zNDIgMTguOTY2LDM2LjEwNyAxNy4xOTUsMzYuMDIgQzE5LjI4NSwyNC43MSAyOS41MTEsMTYgNDEsMTYgQzQ1LjMxMywxNiA0OS44MzIsMTcuNjIyIDU0LjQyOSwyMC44MjEgTDU1LjU3MSwxOS4xNzkgQzUwLjYzMywxNS43NDMgNDUuNzMsMTQgNDEsMTQgQzI4LjI3LDE0IDE2Ljk0OSwyMy44NjUgMTUuMDYzLDM2LjUyMSBDMTMuODM5LDM3LjIwNyAxMywzOC41IDEzLDQwIEMxMyw0MS41IDEzLjgzOSw0Mi43OTMgMTUuMDYzLDQzLjQ3OCBDMTYuOTcsNTYuMzQxIDI4LjA1Niw2NiA0MSw2NiBDNDYuNDA3LDY2IDUxLjk0Miw2NC4xNTcgNTYuNTg1LDYwLjgxMSBMNTUuNDE1LDU5LjE4OSBDNTEuMTEsNjIuMjkyIDQ1Ljk5MSw2NCA0MSw2NCBMNDEsNjQgWiBNMzAuMTAxLDM2LjQ0MiBDMzEuOTU1LDM2Ljg5NSAzNC4yNzUsMzcgMzYsMzcgQzM3LjY0MiwzNyAzOS44MjMsMzYuOTA1IDQxLjYyOSwzNi41MDYgTDM3LjEwNSw0NS41NTMgQzM3LjAzNiw0NS42OTEgMzcsNDUuODQ1IDM3LDQ2IEwzNyw1MC40NTMgQzM2LjE5OSw1MC45NjQgMzQuODMzLDUxLjgxMiAzNCw1MS45ODYgTDM0LDQ2IEMzNCw0NS44NjggMzMuOTc0LDQ1LjczNyAzMy45MjMsNDUuNjE1IEwzMC4xMDEsMzYuNDQyIFogTTM2LDMzIEM0MC4wMjUsMzMgNDIuMTc0LDMzLjYwNCA0Mi44NDEsMzQgQzQyLjE3NCwzNC4zOTYgNDAuMDI1LDM1IDM2LDM1IEMzMS45NzUsMzUgMjkuODI2LDM0LjM5NiAyOS4xNTksMzQgQzI5LjgyNiwzMy42MDQgMzEuOTc1LDMzIDM2LDMzIEwzNiwzMyBaIE0zMyw1NCBMMzQsNTQgQzM0LjA0Myw1NCAzNC4wODYsNTMuOTk3IDM0LjEyOCw1My45OTIgQzM1LjM1Miw1My44MzMgMzYuOTA5LDUyLjg4NyAzOC4yNzIsNTIuMDEzIEwzOC41MzUsNTEuODQ1IEMzOC44MjQsNTEuNjYxIDM5LDUxLjM0MiAzOSw1MSBMMzksNDYuMjM2IEw0NC41NTksMzUuMTIgQzQ0LjgzMywzNC44MDEgNDUsMzQuNDM0IDQ1LDM0IEM0NSwzMS4zOSAzOS4zNjEsMzEgMzYsMzEgQzMyLjYzOSwzMSAyNywzMS4zOSAyNywzNCBDMjcsMzQuMzY2IDI3LjEyLDM0LjY4NCAyNy4zMiwzNC45NjcgTDMyLDQ2LjIgTDMyLDUzIEMzMiw1My41NTIgMzIuNDQ3LDU0IDMzLDU0IEwzMyw1NCBaIE02Miw1MyBDNjMuMTAzLDUzIDY0LDUzLjg5NyA2NCw1NSBDNjQsNTYuMTAzIDYzLjEwMyw1NyA2Miw1NyBDNjAuODk3LDU3IDYwLDU2LjEwMyA2MCw1NSBDNjAsNTMuODk3IDYwLjg5Nyw1MyA2Miw1MyBMNjIsNTMgWiBNNjIsMjMgQzYzLjEwMywyMyA2NCwyMy44OTcgNjQsMjUgQzY0LDI2LjEwMyA2My4xMDMsMjcgNjIsMjcgQzYwLjg5NywyNyA2MCwyNi4xMDMgNjAsMjUgQzYwLDIzLjg5NyA2MC44OTcsMjMgNjIsMjMgTDYyLDIzIFogTTY0LDM4IEM2NS4xMDMsMzggNjYsMzguODk3IDY2LDQwIEM2Niw0MS4xMDMgNjUuMTAzLDQyIDY0LDQyIEM2Mi44OTcsNDIgNjIsNDEuMTAzIDYyLDQwIEM2MiwzOC44OTcgNjIuODk3LDM4IDY0LDM4IEw2NCwzOCBaIE01NCw0MSBMNjAuMTQzLDQxIEM2MC41ODksNDIuNzIgNjIuMTQyLDQ0IDY0LDQ0IEM2Ni4yMDYsNDQgNjgsNDIuMjA2IDY4LDQwIEM2OCwzNy43OTQgNjYuMjA2LDM2IDY0LDM2IEM2Mi4xNDIsMzYgNjAuNTg5LDM3LjI4IDYwLjE0MywzOSBMNTQsMzkgTDU0LDI2IEw1OC4xNDMsMjYgQzU4LjU4OSwyNy43MiA2MC4xNDIsMjkgNjIsMjkgQzY0LjIwNiwyOSA2NiwyNy4yMDYgNjYsMjUgQzY2LDIyLjc5NCA2NC4yMDYsMjEgNjIsMjEgQzYwLjE0MiwyMSA1OC41ODksMjIuMjggNTguMTQzLDI0IEw1MywyNCBDNTIuNDQ3LDI0IDUyLDI0LjQ0OCA1MiwyNSBMNTIsMzkgTDQ1LDM5IEw0NSw0MSBMNTIsNDEgTDUyLDU1IEM1Miw1NS41NTIgNTIuNDQ3LDU2IDUzLDU2IEw1OC4xNDMsNTYgQzU4LjU4OSw1Ny43MiA2MC4xNDIsNTkgNjIsNTkgQzY0LjIwNiw1OSA2Niw1Ny4yMDYgNjYsNTUgQzY2LDUyLjc5NCA2NC4yMDYsNTEgNjIsNTEgQzYwLjE0Miw1MSA1OC41ODksNTIuMjggNTguMTQzLDU0IEw1NCw1NCBMNTQsNDEgWiIgaWQ9IkFXUy1TaW1wbGUtTm90aWZpY2F0aW9uLVNlcnZpY2VfSWNvbl82NF9TcXVpZCIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgPC9nPgo8L3N2Zz4=",
|
||||||
|
"layout": [
|
||||||
|
{
|
||||||
|
"h": 6,
|
||||||
|
"i": "4eb87f89-0213-4773-9b06-6aecc6701898",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 6,
|
||||||
|
"i": "7a010b4e-ea7c-4a45-a9eb-93af650c45b4",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 6,
|
||||||
|
"i": "2299d4e3-6c40-4bf2-a550-c7bb8a7acd38",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 6,
|
||||||
|
"i": "16eec8b7-de1a-4039-b180-24c7a6704b6e",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"panelMap": {},
|
||||||
|
"tags": [],
|
||||||
|
"title": "SNS Overview",
|
||||||
|
"uploadedGrafana": false,
|
||||||
|
"variables": {
|
||||||
|
"51f4fa2b-89c7-47c2-9795-f32cffaab985": {
|
||||||
|
"allSelected": false,
|
||||||
|
"customValue": "",
|
||||||
|
"description": "AWS Account ID",
|
||||||
|
"id": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
|
||||||
|
"key": "51f4fa2b-89c7-47c2-9795-f32cffaab985",
|
||||||
|
"modificationUUID": "b7a6b06b-fa1f-4fb8-b70e-6bd9b350f29e",
|
||||||
|
"multiSelect": false,
|
||||||
|
"name": "Account",
|
||||||
|
"order": 0,
|
||||||
|
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud.account.id') AS `cloud.account.id`\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_SNS_PublishSize_count' GROUP BY `cloud.account.id`",
|
||||||
|
"showALLOption": false,
|
||||||
|
"sort": "DISABLED",
|
||||||
|
"textboxValue": "",
|
||||||
|
"type": "QUERY"
|
||||||
|
},
|
||||||
|
"9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0": {
|
||||||
|
"allSelected": false,
|
||||||
|
"customValue": "",
|
||||||
|
"description": "Account Region",
|
||||||
|
"id": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
|
||||||
|
"key": "9faf0f4b-b245-4b3c-83a3-60cfa76dfeb0",
|
||||||
|
"modificationUUID": "8428a5de-bfd1-4a69-9601-63e3041cd556",
|
||||||
|
"multiSelect": false,
|
||||||
|
"name": "Region",
|
||||||
|
"order": 1,
|
||||||
|
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'cloud.region') AS region\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_SNS_PublishSize_count' AND JSONExtractString(labels, 'cloud.account.id') IN {{.Account}} GROUP BY region",
|
||||||
|
"showALLOption": false,
|
||||||
|
"sort": "ASC",
|
||||||
|
"textboxValue": "",
|
||||||
|
"type": "QUERY"
|
||||||
|
},
|
||||||
|
"bfbdbcbe-a168-4d81-b108-36339e249116": {
|
||||||
|
"allSelected": true,
|
||||||
|
"customValue": "",
|
||||||
|
"description": "SNS Topic Name",
|
||||||
|
"id": "bfbdbcbe-a168-4d81-b108-36339e249116",
|
||||||
|
"modificationUUID": "dfed7272-16dc-4eb6-99bf-7c82fc8e04f0",
|
||||||
|
"multiSelect": true,
|
||||||
|
"name": "Topic",
|
||||||
|
"order": 2,
|
||||||
|
"queryValue": "SELECT DISTINCT JSONExtractString(labels, 'TopicName') AS topic\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'aws_SNS_PublishSize_count' AND JSONExtractString(labels, 'cloud.account.id') IN {{.Account}} AND JSONExtractString(labels, 'cloud.region') IN {{.Region}}\nGROUP BY topic",
|
||||||
|
"showALLOption": true,
|
||||||
|
"sort": "ASC",
|
||||||
|
"textboxValue": "",
|
||||||
|
"type": "QUERY"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": "v4",
|
||||||
|
"widgets": [
|
||||||
|
{
|
||||||
|
"bucketCount": 30,
|
||||||
|
"bucketWidth": 0,
|
||||||
|
"columnUnits": {},
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "4eb87f89-0213-4773-9b06-6aecc6701898",
|
||||||
|
"isLogScale": false,
|
||||||
|
"isStacked": false,
|
||||||
|
"mergeAllActiveQueries": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "aws_SNS_NumberOfMessagesPublished_max--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "aws_SNS_NumberOfMessagesPublished_max",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "8fd51b53",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "TopicName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "TopicName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"$Topic"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b18187c3",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.region--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.region",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Region"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "eebe4578",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.account.id--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.account.id",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Account"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "TopicName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "TopicName",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{TopicName}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "avg",
|
||||||
|
"spaceAggregation": "max",
|
||||||
|
"stepInterval": 60,
|
||||||
|
"timeAggregation": "max"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "9c67615a-55f7-42da-835c-86922f2ff8bb",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"selectedLogFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "body",
|
||||||
|
"type": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selectedTracesFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "serviceName--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "serviceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "name--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "durationNano--float64--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "durationNano",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "httpMethod--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "httpMethod",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "responseStatusCode--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "responseStatusCode",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"softMax": 0,
|
||||||
|
"softMin": 0,
|
||||||
|
"stackedBarChart": false,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Number of Messages Published",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bucketCount": 30,
|
||||||
|
"bucketWidth": 0,
|
||||||
|
"columnUnits": {},
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "7a010b4e-ea7c-4a45-a9eb-93af650c45b4",
|
||||||
|
"isLogScale": false,
|
||||||
|
"isStacked": false,
|
||||||
|
"mergeAllActiveQueries": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "aws_SNS_PublishSize_max--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "aws_SNS_PublishSize_max",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "1aa0d1a9",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "TopicName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "TopicName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"$Topic"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "62255cff",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.region--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.region",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Region"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "17c7153e",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.account.id--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.account.id",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Account"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "TopicName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "TopicName",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{TopicName}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "avg",
|
||||||
|
"spaceAggregation": "max",
|
||||||
|
"stepInterval": 60,
|
||||||
|
"timeAggregation": "max"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "a635a15b-dfe6-4617-a82e-29d93e27deaf",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"selectedLogFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "body",
|
||||||
|
"type": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selectedTracesFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "serviceName--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "serviceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "name--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "durationNano--float64--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "durationNano",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "httpMethod--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "httpMethod",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "responseStatusCode--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "responseStatusCode",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"softMax": 0,
|
||||||
|
"softMin": 0,
|
||||||
|
"stackedBarChart": false,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Published Message Size",
|
||||||
|
"yAxisUnit": "decbytes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bucketCount": 30,
|
||||||
|
"bucketWidth": 0,
|
||||||
|
"columnUnits": {},
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "2299d4e3-6c40-4bf2-a550-c7bb8a7acd38",
|
||||||
|
"isLogScale": false,
|
||||||
|
"isStacked": false,
|
||||||
|
"mergeAllActiveQueries": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "aws_SNS_NumberOfNotificationsDelivered_max--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "aws_SNS_NumberOfNotificationsDelivered_max",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "c96a4ac0",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "TopicName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "TopicName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"$Topic"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8ca86829",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.region--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.region",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Region"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8a444f66",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.account.id--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.account.id",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Account"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "TopicName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "TopicName",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{TopicName}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "avg",
|
||||||
|
"spaceAggregation": "max",
|
||||||
|
"stepInterval": 60,
|
||||||
|
"timeAggregation": "max"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "0d2fc26c-9b21-4dfc-b631-64b7c8d3bd71",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"selectedLogFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "body",
|
||||||
|
"type": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selectedTracesFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "serviceName--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "serviceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "name--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "durationNano--float64--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "durationNano",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "httpMethod--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "httpMethod",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "responseStatusCode--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "responseStatusCode",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"softMax": 0,
|
||||||
|
"softMin": 0,
|
||||||
|
"stackedBarChart": false,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Number of Notifications Delivered",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bucketCount": 30,
|
||||||
|
"bucketWidth": 0,
|
||||||
|
"columnUnits": {},
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "16eec8b7-de1a-4039-b180-24c7a6704b6e",
|
||||||
|
"isLogScale": false,
|
||||||
|
"isStacked": false,
|
||||||
|
"mergeAllActiveQueries": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "aws_SNS_NumberOfNotificationsFailed_max--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "aws_SNS_NumberOfNotificationsFailed_max",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "6175f3d5",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "TopicName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "TopicName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"$Topic"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e2084931",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.region--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.region",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Region"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "0b05209a",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "cloud.account.id--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "cloud.account.id",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "$Account"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"functions": [],
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "TopicName--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "TopicName",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{TopicName}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "avg",
|
||||||
|
"spaceAggregation": "max",
|
||||||
|
"stepInterval": 60,
|
||||||
|
"timeAggregation": "max"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "526247af-6ac9-42ff-83e9-cce0e32a9e63",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"selectedLogFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "body",
|
||||||
|
"type": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selectedTracesFields": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "serviceName--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "serviceName",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "name--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "durationNano--float64--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "durationNano",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "httpMethod--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "httpMethod",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "responseStatusCode--string--tag--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "responseStatusCode",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"softMax": 0,
|
||||||
|
"softMin": 0,
|
||||||
|
"stackedBarChart": false,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Number of Notifications Failed",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -55,7 +55,6 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/query-service/app/queryBuilder"
|
"github.com/SigNoz/signoz/pkg/query-service/app/queryBuilder"
|
||||||
tracesV3 "github.com/SigNoz/signoz/pkg/query-service/app/traces/v3"
|
tracesV3 "github.com/SigNoz/signoz/pkg/query-service/app/traces/v3"
|
||||||
tracesV4 "github.com/SigNoz/signoz/pkg/query-service/app/traces/v4"
|
tracesV4 "github.com/SigNoz/signoz/pkg/query-service/app/traces/v4"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/auth"
|
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/contextlinks"
|
"github.com/SigNoz/signoz/pkg/query-service/contextlinks"
|
||||||
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
|
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/postprocess"
|
"github.com/SigNoz/signoz/pkg/query-service/postprocess"
|
||||||
@ -255,7 +254,7 @@ func NewAPIHandler(opts APIHandlerOpts) (*APIHandler, error) {
|
|||||||
aH.queryBuilder = queryBuilder.NewQueryBuilder(builderOpts)
|
aH.queryBuilder = queryBuilder.NewQueryBuilder(builderOpts)
|
||||||
|
|
||||||
// TODO(nitya): remote this in later for multitenancy.
|
// TODO(nitya): remote this in later for multitenancy.
|
||||||
orgs, err := opts.Signoz.Modules.Organization.GetAll(context.Background())
|
orgs, err := opts.Signoz.Modules.OrgGetter.ListByOwnedKeyRange(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Warn("unexpected error while fetching orgs while initializing base api handler", zap.Error(err))
|
zap.L().Warn("unexpected error while fetching orgs while initializing base api handler", zap.Error(err))
|
||||||
}
|
}
|
||||||
@ -2062,9 +2061,9 @@ func (aH *APIHandler) registerUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, apiErr := auth.Register(context.Background(), &req, aH.Signoz.Alertmanager, aH.Signoz.Modules.Organization, aH.Signoz.Modules.User, aH.Signoz.Modules.QuickFilter)
|
_, errv2 := aH.Signoz.Modules.User.Register(r.Context(), &req)
|
||||||
if apiErr != nil {
|
if errv2 != nil {
|
||||||
RespondError(w, apiErr, nil)
|
render.Error(w, errv2)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5230,3 +5229,30 @@ func (aH *APIHandler) getDomainInfo(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
aH.Respond(w, resp)
|
aH.Respond(w, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterTraceFunnelsRoutes adds trace funnels routes
|
||||||
|
func (aH *APIHandler) RegisterTraceFunnelsRoutes(router *mux.Router, am *middleware.AuthZ) {
|
||||||
|
// Main trace funnels router
|
||||||
|
traceFunnelsRouter := router.PathPrefix("/api/v1/trace-funnels").Subrouter()
|
||||||
|
|
||||||
|
// API endpoints
|
||||||
|
traceFunnelsRouter.HandleFunc("/new",
|
||||||
|
am.EditAccess(aH.Signoz.Handlers.TraceFunnel.New)).
|
||||||
|
Methods(http.MethodPost)
|
||||||
|
traceFunnelsRouter.HandleFunc("/list",
|
||||||
|
am.ViewAccess(aH.Signoz.Handlers.TraceFunnel.List)).
|
||||||
|
Methods(http.MethodGet)
|
||||||
|
traceFunnelsRouter.HandleFunc("/steps/update",
|
||||||
|
am.EditAccess(aH.Signoz.Handlers.TraceFunnel.UpdateSteps)).
|
||||||
|
Methods(http.MethodPut)
|
||||||
|
|
||||||
|
traceFunnelsRouter.HandleFunc("/{funnel_id}",
|
||||||
|
am.ViewAccess(aH.Signoz.Handlers.TraceFunnel.Get)).
|
||||||
|
Methods(http.MethodGet)
|
||||||
|
traceFunnelsRouter.HandleFunc("/{funnel_id}",
|
||||||
|
am.EditAccess(aH.Signoz.Handlers.TraceFunnel.Delete)).
|
||||||
|
Methods(http.MethodDelete)
|
||||||
|
traceFunnelsRouter.HandleFunc("/{funnel_id}",
|
||||||
|
am.EditAccess(aH.Signoz.Handlers.TraceFunnel.UpdateFunnel)).
|
||||||
|
Methods(http.MethodPut)
|
||||||
|
}
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/query-service/constants"
|
||||||
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -176,6 +178,19 @@ func HydrateFileUris(spec interface{}, fs embed.FS, basedir string) (interface{}
|
|||||||
if specMap, ok := spec.(map[string]interface{}); ok {
|
if specMap, ok := spec.(map[string]interface{}); ok {
|
||||||
result := map[string]interface{}{}
|
result := map[string]interface{}{}
|
||||||
for k, v := range specMap {
|
for k, v := range specMap {
|
||||||
|
// Check if this is a dashboards slice and if dot metrics are enabled
|
||||||
|
if k == "dashboards" && constants.IsDotMetricsEnabled {
|
||||||
|
if dashboards, ok := v.([]interface{}); ok {
|
||||||
|
for i, dashboard := range dashboards {
|
||||||
|
if dashboardUri, ok := dashboard.(string); ok {
|
||||||
|
if strings.HasPrefix(dashboardUri, "file://") {
|
||||||
|
dashboards[i] = strings.Replace(dashboardUri, ".json", "_dot.json", 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = dashboards
|
||||||
|
}
|
||||||
|
}
|
||||||
hydrated, err := HydrateFileUris(v, fs, basedir)
|
hydrated, err := HydrateFileUris(v, fs, basedir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -200,7 +215,6 @@ func HydrateFileUris(spec interface{}, fs embed.FS, basedir string) (interface{}
|
|||||||
}
|
}
|
||||||
|
|
||||||
return spec, nil
|
return spec, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readFileIfUri(fs embed.FS, maybeFileUri string, basedir string) (interface{}, error) {
|
func readFileIfUri(fs embed.FS, maybeFileUri string, basedir string) (interface{}, error) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,797 @@
|
|||||||
|
{
|
||||||
|
"id": "mongo-overview",
|
||||||
|
"description": "This dashboard provides a high-level overview of your MongoDB. It includes read/write performance, most-used replicas, collection metrics etc...",
|
||||||
|
"layout": [
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "0c3d2b15-89be-4d62-a821-b26d93332ed3",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "14504a3c-4a05-4d22-bab3-e22e94f51380",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "dcfb3829-c3f2-44bb-907d-8dc8a6dc4aab",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "bfc9e80b-02bf-4122-b3da-3dd943d35012",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "4c07a7d2-893a-46c2-bcdb-a19b6efeac3a",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "a5a64eec-1034-4aa6-8cb1-05673c4426c6",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "503af589-ef4d-4fe3-8934-c8f7eb480d9a",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 9
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "",
|
||||||
|
"tags": [
|
||||||
|
"mongo",
|
||||||
|
"database"
|
||||||
|
],
|
||||||
|
"title": "Mongo overview",
|
||||||
|
"variables": {
|
||||||
|
"a2c21714-a814-4d31-9b56-7367c3208801": {
|
||||||
|
"allSelected": true,
|
||||||
|
"customValue": "",
|
||||||
|
"description": "List of hosts sending mongo metrics",
|
||||||
|
"id": "a2c21714-a814-4d31-9b56-7367c3208801",
|
||||||
|
"modificationUUID": "448e675a-4531-45b1-b434-a9ee809470d6",
|
||||||
|
"multiSelect": true,
|
||||||
|
"name": "host.name",
|
||||||
|
"order": 0,
|
||||||
|
"queryValue": "SELECT JSONExtractString(labels, 'host.name') AS `host.name`\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'mongodb_memory_usage'\nGROUP BY `host.name`",
|
||||||
|
"selectedValue": [
|
||||||
|
"Srikanths-MacBook-Pro.local"
|
||||||
|
],
|
||||||
|
"showALLOption": true,
|
||||||
|
"sort": "ASC",
|
||||||
|
"textboxValue": "",
|
||||||
|
"type": "QUERY"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgets": [
|
||||||
|
{
|
||||||
|
"description": "Total number of operations",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "4c07a7d2-893a-46c2-bcdb-a19b6efeac3a",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "mongodb.operation.count--float64--Sum--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "mongodb.operation.count",
|
||||||
|
"type": "Sum"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum_rate",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "a468a30b",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "operation--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "operation",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{operation}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "7da5d899-8b06-4139-9a89-47baf9551ff8",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Operations count",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "The total time spent performing operations.",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "bfc9e80b-02bf-4122-b3da-3dd943d35012",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "mongodb.operation.time--float64--Sum--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "mongodb.operation.time",
|
||||||
|
"type": "Sum"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum_rate",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "31be3166",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "operation--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "operation",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{operation}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "2ca35957-894a-46ae-a2a6-95d7e400d8e1",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Total operations time",
|
||||||
|
"yAxisUnit": "ms"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "The number of cache operations",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "dcfb3829-c3f2-44bb-907d-8dc8a6dc4aab",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "mongodb.cache.operations--float64--Sum--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "mongodb.cache.operations",
|
||||||
|
"type": "Sum"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum_rate",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "01b45814",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "type--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "type",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "{{type}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "bb439198-dcf5-4767-b0d0-ab5785159b8d",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Cache operations",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "14504a3c-4a05-4d22-bab3-e22e94f51380",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "mongodb.operation.latency.time--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "mongodb.operation.latency.time",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "2e165319",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "operation--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "operation",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "read"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "888e920b",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Latency",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "4a9cafe8-778b-476c-b825-c04e165bf285",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Read latency",
|
||||||
|
"yAxisUnit": "µs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "a5a64eec-1034-4aa6-8cb1-05673c4426c6",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "mongodb.operation.latency.time--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "mongodb.operation.latency.time",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "53b37ca7",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9862c46c",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "operation--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "operation",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "write"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Latency",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "446827eb-a4f2-4ff3-966b-fb65288c983b",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Write latency",
|
||||||
|
"yAxisUnit": "µs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "503af589-ef4d-4fe3-8934-c8f7eb480d9a",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "mongodb.operation.latency.time--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "mongodb.operation.latency.time",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "c33ad4b6",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c70ecfd0",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "operation--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "operation",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "=",
|
||||||
|
"value": "command"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Latency",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "7b7b977d-0921-4552-8cfe-d82dfde63ef4",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Command latency",
|
||||||
|
"yAxisUnit": "µs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "0c3d2b15-89be-4d62-a821-b26d93332ed3",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "mongodb.network.io.receive--float64--Sum--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "mongodb.network.io.receive",
|
||||||
|
"type": "Sum"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "avg",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "5c9d7fe3",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Bytes received :: {{host.name}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "mongodb.network.io.transmit--float64--Sum--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "mongodb.network.io.transmit",
|
||||||
|
"type": "Sum"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "avg",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "B",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "96520885",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Bytes transmitted :: {{host.name}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "B",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "41eea5bc-f9cf-45c2-92fb-ef226d6b540b",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Network IO",
|
||||||
|
"yAxisUnit": "bytes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,924 @@
|
|||||||
|
{
|
||||||
|
"id": "redis-overview",
|
||||||
|
"description": "This dashboard shows the Redis instance overview. It includes latency, hit/miss rate, connections, and memory information.\n",
|
||||||
|
"layout": [
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "d4c164bc-8fc2-4dbc-aadd-8d17479ca649",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "2fbaef0d-3cdb-4ce3-aa3c-9bbbb41786d9",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 3,
|
||||||
|
"y": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "f5ee1511-0d2b-4404-9ce0-e991837decc2",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "b19c7058-b806-4ea2-974a-ca555b168991",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "bf0deeeb-e926-4234-944c-82bacd96af47",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "a77227c7-16f5-4353-952e-b183c715a61c",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "9698cee2-b1f3-4c0b-8c9f-3da4f0e05f17",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "64a5f303-d7db-44ff-9a0e-948e5c653320",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h": 3,
|
||||||
|
"i": "3e80a918-69af-4c9a-bc57-a94e1d41b05c",
|
||||||
|
"moved": false,
|
||||||
|
"static": false,
|
||||||
|
"w": 6,
|
||||||
|
"x": 6,
|
||||||
|
"y": 12
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "",
|
||||||
|
"tags": [
|
||||||
|
"redis",
|
||||||
|
"database"
|
||||||
|
],
|
||||||
|
"title": "Redis overview",
|
||||||
|
"variables": {
|
||||||
|
"94f19b3c-ad9f-4b47-a9b2-f312c09fa965": {
|
||||||
|
"allSelected": true,
|
||||||
|
"customValue": "",
|
||||||
|
"description": "List of hosts sending Redis metrics",
|
||||||
|
"id": "94f19b3c-ad9f-4b47-a9b2-f312c09fa965",
|
||||||
|
"key": "94f19b3c-ad9f-4b47-a9b2-f312c09fa965",
|
||||||
|
"modificationUUID": "4c5b0c03-9cbc-425b-8d8e-7152e5c39ba8",
|
||||||
|
"multiSelect": true,
|
||||||
|
"name": "host.name",
|
||||||
|
"order": 0,
|
||||||
|
"queryValue": "SELECT JSONExtractString(labels, 'host.name') AS `host.name`\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'redis.cpu.time'\nGROUP BY `host.name`",
|
||||||
|
"selectedValue": [
|
||||||
|
"Srikanths-MacBook-Pro.local"
|
||||||
|
],
|
||||||
|
"showALLOption": true,
|
||||||
|
"sort": "ASC",
|
||||||
|
"textboxValue": "",
|
||||||
|
"type": "QUERY"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgets": [
|
||||||
|
{
|
||||||
|
"description": "Rate successful lookup of keys in the main dictionary",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "a77227c7-16f5-4353-952e-b183c715a61c",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "redis.keyspace.hits--float64--Sum--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "redis.keyspace.hits",
|
||||||
|
"type": "Sum"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum_rate",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "e99669ea",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Hit/s across all hosts",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "42c9c117-bfaf-49f7-b528-aad099392295",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Hits/s",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Number of clients pending on a blocking call",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "bf0deeeb-e926-4234-944c-82bacd96af47",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "redis.clients.blocked--float64--Sum--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "redis.clients.blocked",
|
||||||
|
"type": "Sum"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "97247f25",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Blocked clients across all hosts",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "b77a9e11-fb98-4a95-88a8-c3ad25c14369",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Clients blocked",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "b19c7058-b806-4ea2-974a-ca555b168991",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "",
|
||||||
|
"id": "redis.db.keys------false",
|
||||||
|
"isColumn": false,
|
||||||
|
"key": "redis.db.keys",
|
||||||
|
"type": ""
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [],
|
||||||
|
"having": [],
|
||||||
|
"legend": "",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "b77a9e11-fb98-4a95-88a8-c3ad25c14369",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Keyspace Keys",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Number of changes since the last dump",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "f5ee1511-0d2b-4404-9ce0-e991837decc2",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "redis.rdb.changes_since_last_save--float64--Sum--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "redis.rdb.changes_since_last_save",
|
||||||
|
"type": "Sum"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "d4aef346",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Number of unsaved changes",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "32cedddf-606d-4de1-8c1d-4b7049e6430c",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Unsaved changes",
|
||||||
|
"yAxisUnit": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "2fbaef0d-3cdb-4ce3-aa3c-9bbbb41786d9",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "redis.commands--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "redis.commands",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "458dc402",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [],
|
||||||
|
"having": [],
|
||||||
|
"legend": "ops/s",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "c70de4dd-a68a-42df-a249-6610c296709c",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Command/s",
|
||||||
|
"yAxisUnit": "ops"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "d4c164bc-8fc2-4dbc-aadd-8d17479ca649",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "redis.memory.used--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "redis.memory.used",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "394a537e",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Used::{{host.name}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "redis.maxmemory--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "redis.maxmemory",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "max",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "B",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "0c0754da",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Max::{{host.name}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "B",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "2f47df76-f09e-4152-8623-971f0fe66bfe",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Memory usage",
|
||||||
|
"yAxisUnit": "bytes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "9698cee2-b1f3-4c0b-8c9f-3da4f0e05f17",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "redis.memory.rss--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "redis.memory.rss",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "4dc9ae49",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Rss::{{host.name}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "fddd043c-1385-481c-9f4c-381f261e1dd9",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "RSS Memory",
|
||||||
|
"yAxisUnit": "bytes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "64a5f303-d7db-44ff-9a0e-948e5c653320",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "redis.memory.fragmentation_ratio--float64--Gauge--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "redis.memory.fragmentation_ratio",
|
||||||
|
"type": "Gauge"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "avg",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "79dc25f3",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Rss::{{host.name}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "3e802b07-0249-4d79-a5c7-6580ab535ad0",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Fragmentation ratio",
|
||||||
|
"yAxisUnit": "short"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Number of evicted keys due to maxmemory limit",
|
||||||
|
"fillSpans": false,
|
||||||
|
"id": "3e80a918-69af-4c9a-bc57-a94e1d41b05c",
|
||||||
|
"isStacked": false,
|
||||||
|
"nullZeroValues": "zero",
|
||||||
|
"opacity": "1",
|
||||||
|
"panelTypes": "graph",
|
||||||
|
"query": {
|
||||||
|
"builder": {
|
||||||
|
"queryData": [
|
||||||
|
{
|
||||||
|
"aggregateAttribute": {
|
||||||
|
"dataType": "float64",
|
||||||
|
"id": "redis.keys.evicted--float64--Sum--true",
|
||||||
|
"isColumn": true,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "redis.keys.evicted",
|
||||||
|
"type": "Sum"
|
||||||
|
},
|
||||||
|
"aggregateOperator": "sum_rate",
|
||||||
|
"dataSource": "metrics",
|
||||||
|
"disabled": false,
|
||||||
|
"expression": "A",
|
||||||
|
"filters": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "53d189ac",
|
||||||
|
"key": {
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
"op": "in",
|
||||||
|
"value": [
|
||||||
|
"{{.host.name}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"op": "AND"
|
||||||
|
},
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"dataType": "string",
|
||||||
|
"id": "host.name--string--tag--false",
|
||||||
|
"isColumn": false,
|
||||||
|
"isJSON": false,
|
||||||
|
"key": "host.name",
|
||||||
|
"type": "tag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"having": [],
|
||||||
|
"legend": "Rss::{{host.name}}",
|
||||||
|
"limit": null,
|
||||||
|
"orderBy": [],
|
||||||
|
"queryName": "A",
|
||||||
|
"reduceTo": "sum",
|
||||||
|
"stepInterval": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryFormulas": []
|
||||||
|
},
|
||||||
|
"clickhouse_sql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "15d1d9d7-eb10-464b-aa7b-33ff211996f7",
|
||||||
|
"promql": [
|
||||||
|
{
|
||||||
|
"disabled": false,
|
||||||
|
"legend": "",
|
||||||
|
"name": "A",
|
||||||
|
"query": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queryType": "builder"
|
||||||
|
},
|
||||||
|
"softMax": null,
|
||||||
|
"softMin": null,
|
||||||
|
"thresholds": [],
|
||||||
|
"timePreferance": "GLOBAL_TIME",
|
||||||
|
"title": "Eviction rate",
|
||||||
|
"yAxisUnit": "short"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -3,12 +3,18 @@ package integrations
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/emailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing/noopemailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerserver"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
||||||
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/signoz"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@ -19,11 +25,14 @@ func TestIntegrationLifecycle(t *testing.T) {
|
|||||||
mgr, store := NewTestIntegrationsManager(t)
|
mgr, store := NewTestIntegrationsManager(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
organizationModule := implorganization.NewModule(implorganization.NewStore(store))
|
|
||||||
providerSettings := instrumentationtest.New().ToProviderSettings()
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
emailing, _ := noopemailing.New(context.Background(), providerSettings, emailing.Config{})
|
sharder, _ := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
userModule := impluser.NewModule(impluser.NewStore(store, providerSettings), nil, emailing, providerSettings)
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(store), sharder)
|
||||||
user, apiErr := createTestUser(organizationModule, userModule)
|
alertmanager, _ := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{Provider: "signoz", Signoz: alertmanager.Signoz{PollInterval: 10 * time.Second, Config: alertmanagerserver.NewConfig()}}, store, orgGetter)
|
||||||
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
|
emailing := emailingtest.New()
|
||||||
|
modules := signoz.NewModules(store, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
|
user, apiErr := createTestUser(modules.OrgSetter, modules.User)
|
||||||
if apiErr != nil {
|
if apiErr != nil {
|
||||||
t.Fatalf("could not create test user: %v", apiErr)
|
t.Fatalf("could not create test user: %v", apiErr)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ func NewTestIntegrationsManager(t *testing.T) (*Manager, sqlstore.SQLStore) {
|
|||||||
}, testDB
|
}, testDB
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestUser(organizationModule organization.Module, userModule user.Module) (*types.User, *model.ApiError) {
|
func createTestUser(organizationModule organization.Setter, userModule user.Module) (*types.User, *model.ApiError) {
|
||||||
// Create a test user for auth
|
// Create a test user for auth
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
organization := types.NewOrganization("test")
|
organization := types.NewOrganization("test")
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/apis/fields"
|
"github.com/SigNoz/signoz/pkg/apis/fields"
|
||||||
"github.com/SigNoz/signoz/pkg/http/middleware"
|
"github.com/SigNoz/signoz/pkg/http/middleware"
|
||||||
"github.com/SigNoz/signoz/pkg/licensing/nooplicensing"
|
"github.com/SigNoz/signoz/pkg/licensing/nooplicensing"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/agentConf"
|
"github.com/SigNoz/signoz/pkg/query-service/agentConf"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/app/clickhouseReader"
|
"github.com/SigNoz/signoz/pkg/query-service/app/clickhouseReader"
|
||||||
@ -101,6 +102,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
serverOptions.SigNoz.SQLStore,
|
serverOptions.SigNoz.SQLStore,
|
||||||
serverOptions.SigNoz.TelemetryStore,
|
serverOptions.SigNoz.TelemetryStore,
|
||||||
serverOptions.SigNoz.Prometheus,
|
serverOptions.SigNoz.Prometheus,
|
||||||
|
serverOptions.SigNoz.Modules.OrgGetter,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -194,7 +196,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
|
|||||||
&opAmpModel.AllAgents, agentConfMgr,
|
&opAmpModel.AllAgents, agentConfMgr,
|
||||||
)
|
)
|
||||||
|
|
||||||
orgs, err := apiHandler.Signoz.Modules.Organization.GetAll(context.Background())
|
orgs, err := apiHandler.Signoz.Modules.OrgGetter.ListByOwnedKeyRange(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -212,14 +214,14 @@ func (s *Server) createPrivateServer(api *APIHandler) (*http.Server, error) {
|
|||||||
|
|
||||||
r := NewRouter()
|
r := NewRouter()
|
||||||
|
|
||||||
r.Use(middleware.NewAuth(s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
r.Use(middleware.NewAuth(s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}, s.serverOptions.SigNoz.Sharder, s.serverOptions.SigNoz.Instrumentation.Logger()).Wrap)
|
||||||
r.Use(middleware.NewTimeout(s.serverOptions.SigNoz.Instrumentation.Logger(),
|
r.Use(middleware.NewTimeout(s.serverOptions.SigNoz.Instrumentation.Logger(),
|
||||||
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Default,
|
s.serverOptions.Config.APIServer.Timeout.Default,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Max,
|
s.serverOptions.Config.APIServer.Timeout.Max,
|
||||||
).Wrap)
|
).Wrap)
|
||||||
r.Use(middleware.NewAnalytics().Wrap)
|
r.Use(middleware.NewAnalytics().Wrap)
|
||||||
r.Use(middleware.NewAPIKey(s.serverOptions.SigNoz.SQLStore, []string{"SIGNOZ-API-KEY"}, s.serverOptions.SigNoz.Instrumentation.Logger()).Wrap)
|
r.Use(middleware.NewAPIKey(s.serverOptions.SigNoz.SQLStore, []string{"SIGNOZ-API-KEY"}, s.serverOptions.SigNoz.Instrumentation.Logger(), s.serverOptions.SigNoz.Sharder).Wrap)
|
||||||
r.Use(middleware.NewLogging(s.serverOptions.SigNoz.Instrumentation.Logger(), s.serverOptions.Config.APIServer.Logging.ExcludedRoutes).Wrap)
|
r.Use(middleware.NewLogging(s.serverOptions.SigNoz.Instrumentation.Logger(), s.serverOptions.Config.APIServer.Logging.ExcludedRoutes).Wrap)
|
||||||
|
|
||||||
api.RegisterPrivateRoutes(r)
|
api.RegisterPrivateRoutes(r)
|
||||||
@ -243,14 +245,14 @@ func (s *Server) createPrivateServer(api *APIHandler) (*http.Server, error) {
|
|||||||
func (s *Server) createPublicServer(api *APIHandler, web web.Web) (*http.Server, error) {
|
func (s *Server) createPublicServer(api *APIHandler, web web.Web) (*http.Server, error) {
|
||||||
r := NewRouter()
|
r := NewRouter()
|
||||||
|
|
||||||
r.Use(middleware.NewAuth(s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
r.Use(middleware.NewAuth(s.serverOptions.Jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}, s.serverOptions.SigNoz.Sharder, s.serverOptions.SigNoz.Instrumentation.Logger()).Wrap)
|
||||||
r.Use(middleware.NewTimeout(s.serverOptions.SigNoz.Instrumentation.Logger(),
|
r.Use(middleware.NewTimeout(s.serverOptions.SigNoz.Instrumentation.Logger(),
|
||||||
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
s.serverOptions.Config.APIServer.Timeout.ExcludedRoutes,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Default,
|
s.serverOptions.Config.APIServer.Timeout.Default,
|
||||||
s.serverOptions.Config.APIServer.Timeout.Max,
|
s.serverOptions.Config.APIServer.Timeout.Max,
|
||||||
).Wrap)
|
).Wrap)
|
||||||
r.Use(middleware.NewAnalytics().Wrap)
|
r.Use(middleware.NewAnalytics().Wrap)
|
||||||
r.Use(middleware.NewAPIKey(s.serverOptions.SigNoz.SQLStore, []string{"SIGNOZ-API-KEY"}, s.serverOptions.SigNoz.Instrumentation.Logger()).Wrap)
|
r.Use(middleware.NewAPIKey(s.serverOptions.SigNoz.SQLStore, []string{"SIGNOZ-API-KEY"}, s.serverOptions.SigNoz.Instrumentation.Logger(), s.serverOptions.SigNoz.Sharder).Wrap)
|
||||||
r.Use(middleware.NewLogging(s.serverOptions.SigNoz.Instrumentation.Logger(), s.serverOptions.Config.APIServer.Logging.ExcludedRoutes).Wrap)
|
r.Use(middleware.NewLogging(s.serverOptions.SigNoz.Instrumentation.Logger(), s.serverOptions.Config.APIServer.Logging.ExcludedRoutes).Wrap)
|
||||||
|
|
||||||
am := middleware.NewAuthZ(s.serverOptions.SigNoz.Instrumentation.Logger())
|
am := middleware.NewAuthZ(s.serverOptions.SigNoz.Instrumentation.Logger())
|
||||||
@ -267,6 +269,7 @@ func (s *Server) createPublicServer(api *APIHandler, web web.Web) (*http.Server,
|
|||||||
api.RegisterMessagingQueuesRoutes(r, am)
|
api.RegisterMessagingQueuesRoutes(r, am)
|
||||||
api.RegisterThirdPartyApiRoutes(r, am)
|
api.RegisterThirdPartyApiRoutes(r, am)
|
||||||
api.MetricExplorerRoutes(r, am)
|
api.MetricExplorerRoutes(r, am)
|
||||||
|
api.RegisterTraceFunnelsRoutes(r, am)
|
||||||
|
|
||||||
c := cors.New(cors.Options{
|
c := cors.New(cors.Options{
|
||||||
AllowedOrigins: []string{"*"},
|
AllowedOrigins: []string{"*"},
|
||||||
@ -416,6 +419,7 @@ func makeRulesManager(
|
|||||||
sqlstore sqlstore.SQLStore,
|
sqlstore sqlstore.SQLStore,
|
||||||
telemetryStore telemetrystore.TelemetryStore,
|
telemetryStore telemetrystore.TelemetryStore,
|
||||||
prometheus prometheus.Prometheus,
|
prometheus prometheus.Prometheus,
|
||||||
|
orgGetter organization.Getter,
|
||||||
) (*rules.Manager, error) {
|
) (*rules.Manager, error) {
|
||||||
// create manager opts
|
// create manager opts
|
||||||
managerOpts := &rules.ManagerOptions{
|
managerOpts := &rules.ManagerOptions{
|
||||||
@ -428,6 +432,7 @@ func makeRulesManager(
|
|||||||
Cache: cache,
|
Cache: cache,
|
||||||
EvalDelay: constants.GetEvalDelay(),
|
EvalDelay: constants.GetEvalDelay(),
|
||||||
SQLStore: sqlstore,
|
SQLStore: sqlstore,
|
||||||
|
OrgGetter: orgGetter,
|
||||||
}
|
}
|
||||||
|
|
||||||
// create Manager
|
// create Manager
|
||||||
|
@ -87,7 +87,7 @@ func existsSubQueryForFixedColumn(key v3.AttributeKey, op v3.FilterOperator) (st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildTracesFilterQuery(fs *v3.FilterSet) (string, error) {
|
func BuildTracesFilterQuery(fs *v3.FilterSet) (string, error) {
|
||||||
var conditions []string
|
var conditions []string
|
||||||
|
|
||||||
if fs != nil && len(fs.Items) != 0 {
|
if fs != nil && len(fs.Items) != 0 {
|
||||||
@ -167,7 +167,7 @@ func handleEmptyValuesInGroupBy(groupBy []v3.AttributeKey) (string, error) {
|
|||||||
Operator: "AND",
|
Operator: "AND",
|
||||||
Items: filterItems,
|
Items: filterItems,
|
||||||
}
|
}
|
||||||
return buildTracesFilterQuery(&filterSet)
|
return BuildTracesFilterQuery(&filterSet)
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
@ -248,7 +248,7 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, panelType v3.
|
|||||||
|
|
||||||
timeFilter := fmt.Sprintf("(timestamp >= '%d' AND timestamp <= '%d') AND (ts_bucket_start >= %d AND ts_bucket_start <= %d)", tracesStart, tracesEnd, bucketStart, bucketEnd)
|
timeFilter := fmt.Sprintf("(timestamp >= '%d' AND timestamp <= '%d') AND (ts_bucket_start >= %d AND ts_bucket_start <= %d)", tracesStart, tracesEnd, bucketStart, bucketEnd)
|
||||||
|
|
||||||
filterSubQuery, err := buildTracesFilterQuery(mq.Filters)
|
filterSubQuery, err := BuildTracesFilterQuery(mq.Filters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ func Test_buildTracesFilterQuery(t *testing.T) {
|
|||||||
want: "",
|
want: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Test buildTracesFilterQuery in, nin",
|
name: "Test BuildTracesFilterQuery in, nin",
|
||||||
args: args{
|
args: args{
|
||||||
fs: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
fs: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
||||||
{Key: v3.AttributeKey{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: []interface{}{"GET", "POST"}, Operator: v3.FilterOperatorIn},
|
{Key: v3.AttributeKey{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: []interface{}{"GET", "POST"}, Operator: v3.FilterOperatorIn},
|
||||||
@ -226,7 +226,7 @@ func Test_buildTracesFilterQuery(t *testing.T) {
|
|||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Test buildTracesFilterQuery not eq, neq, gt, lt, gte, lte",
|
name: "Test BuildTracesFilterQuery not eq, neq, gt, lt, gte, lte",
|
||||||
args: args{
|
args: args{
|
||||||
fs: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
fs: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
|
||||||
{Key: v3.AttributeKey{Key: "duration", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag}, Value: 102, Operator: v3.FilterOperatorEqual},
|
{Key: v3.AttributeKey{Key: "duration", DataType: v3.AttributeKeyDataTypeInt64, Type: v3.AttributeKeyTypeTag}, Value: 102, Operator: v3.FilterOperatorEqual},
|
||||||
@ -274,13 +274,13 @@ func Test_buildTracesFilterQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := buildTracesFilterQuery(tt.args.fs)
|
got, err := BuildTracesFilterQuery(tt.args.fs)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("buildTracesFilterQuery() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("BuildTracesFilterQuery() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if got != tt.want {
|
if got != tt.want {
|
||||||
t.Errorf("buildTracesFilterQuery() = %v, want %v", got, tt.want)
|
t.Errorf("BuildTracesFilterQuery() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
|
||||||
"github.com/SigNoz/signoz/pkg/modules/organization"
|
|
||||||
"github.com/SigNoz/signoz/pkg/modules/quickfilter"
|
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
|
||||||
"github.com/SigNoz/signoz/pkg/valuer"
|
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/model"
|
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RegisterOrgAndFirstUser(ctx context.Context, req *types.PostableRegisterOrgAndAdmin, organizationModule organization.Module, userModule user.Module) (*types.User, *model.ApiError) {
|
|
||||||
if req.Email == "" {
|
|
||||||
return nil, model.BadRequest(model.ErrEmailRequired{})
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Password == "" {
|
|
||||||
return nil, model.BadRequest(model.ErrPasswordRequired{})
|
|
||||||
}
|
|
||||||
|
|
||||||
organization := types.NewOrganization(req.OrgDisplayName)
|
|
||||||
err := organizationModule.Create(ctx, organization)
|
|
||||||
if err != nil {
|
|
||||||
return nil, model.InternalError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := types.NewUser(req.Name, req.Email, types.RoleAdmin.String(), organization.ID.StringValue())
|
|
||||||
if err != nil {
|
|
||||||
return nil, model.InternalError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
password, err := types.NewFactorPassword(req.Password)
|
|
||||||
if err != nil {
|
|
||||||
return nil, model.InternalError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err = userModule.CreateUserWithPassword(ctx, user, password)
|
|
||||||
if err != nil {
|
|
||||||
return nil, model.InternalError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// First user registration
|
|
||||||
func Register(ctx context.Context, req *types.PostableRegisterOrgAndAdmin, alertmanager alertmanager.Alertmanager, organizationModule organization.Module, userModule user.Module, quickfiltermodule quickfilter.Module) (*types.User, *model.ApiError) {
|
|
||||||
user, err := RegisterOrgAndFirstUser(ctx, req, organizationModule, userModule)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := alertmanager.SetDefaultConfig(ctx, user.OrgID); err != nil {
|
|
||||||
return nil, model.InternalError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quickfiltermodule.SetDefaultConfig(ctx, valuer.MustNewUUID(user.OrgID)); err != nil {
|
|
||||||
return nil, model.InternalError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
"github.com/SigNoz/signoz/pkg/licensing"
|
"github.com/SigNoz/signoz/pkg/licensing"
|
||||||
"github.com/SigNoz/signoz/pkg/licensing/nooplicensing"
|
"github.com/SigNoz/signoz/pkg/licensing/nooplicensing"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/app"
|
"github.com/SigNoz/signoz/pkg/query-service/app"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/constants"
|
"github.com/SigNoz/signoz/pkg/query-service/constants"
|
||||||
"github.com/SigNoz/signoz/pkg/signoz"
|
"github.com/SigNoz/signoz/pkg/signoz"
|
||||||
@ -121,7 +122,7 @@ func main() {
|
|||||||
zeus.Config{},
|
zeus.Config{},
|
||||||
noopzeus.NewProviderFactory(),
|
noopzeus.NewProviderFactory(),
|
||||||
licensing.Config{},
|
licensing.Config{},
|
||||||
func(_ sqlstore.SQLStore, _ zeus.Zeus) factory.ProviderFactory[licensing.Licensing, licensing.Config] {
|
func(_ sqlstore.SQLStore, _ zeus.Zeus, _ organization.Getter) factory.ProviderFactory[licensing.Licensing, licensing.Config] {
|
||||||
return nooplicensing.NewFactory()
|
return nooplicensing.NewFactory()
|
||||||
},
|
},
|
||||||
signoz.NewEmailingProviderFactories(),
|
signoz.NewEmailingProviderFactories(),
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// custom errors related to registration
|
|
||||||
type ErrFeatureUnavailable struct {
|
|
||||||
Key string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (errFeatureUnavailable ErrFeatureUnavailable) Error() string {
|
|
||||||
return fmt.Sprintf("feature unavailable: %s", errFeatureUnavailable.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrEmailRequired struct{}
|
|
||||||
|
|
||||||
func (errEmailRequired ErrEmailRequired) Error() string {
|
|
||||||
return "email is required"
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrPasswordRequired struct{}
|
|
||||||
|
|
||||||
func (errPasswordRequired ErrPasswordRequired) Error() string {
|
|
||||||
return "password is required"
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrSignupFailed struct{}
|
|
||||||
|
|
||||||
func (errSignupFailed ErrSignupFailed) Error() string {
|
|
||||||
return "failed to register user"
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrNoOrgFound struct{}
|
|
||||||
|
|
||||||
func (errNoOrgFound ErrNoOrgFound) Error() string {
|
|
||||||
return "no org found"
|
|
||||||
}
|
|
@ -19,6 +19,7 @@ import (
|
|||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/alertmanager"
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/cache"
|
"github.com/SigNoz/signoz/pkg/cache"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/interfaces"
|
"github.com/SigNoz/signoz/pkg/query-service/interfaces"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/model"
|
"github.com/SigNoz/signoz/pkg/query-service/model"
|
||||||
@ -95,6 +96,7 @@ type ManagerOptions struct {
|
|||||||
PrepareTestRuleFunc func(opts PrepareTestRuleOptions) (int, *model.ApiError)
|
PrepareTestRuleFunc func(opts PrepareTestRuleOptions) (int, *model.ApiError)
|
||||||
Alertmanager alertmanager.Alertmanager
|
Alertmanager alertmanager.Alertmanager
|
||||||
SQLStore sqlstore.SQLStore
|
SQLStore sqlstore.SQLStore
|
||||||
|
OrgGetter organization.Getter
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Manager manages recording and alerting rules.
|
// The Manager manages recording and alerting rules.
|
||||||
@ -116,6 +118,7 @@ type Manager struct {
|
|||||||
|
|
||||||
alertmanager alertmanager.Alertmanager
|
alertmanager alertmanager.Alertmanager
|
||||||
sqlstore sqlstore.SQLStore
|
sqlstore sqlstore.SQLStore
|
||||||
|
orgGetter organization.Getter
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultOptions(o *ManagerOptions) *ManagerOptions {
|
func defaultOptions(o *ManagerOptions) *ManagerOptions {
|
||||||
@ -210,6 +213,7 @@ func NewManager(o *ManagerOptions) (*Manager, error) {
|
|||||||
prepareTestRuleFunc: o.PrepareTestRuleFunc,
|
prepareTestRuleFunc: o.PrepareTestRuleFunc,
|
||||||
alertmanager: o.Alertmanager,
|
alertmanager: o.Alertmanager,
|
||||||
sqlstore: o.SQLStore,
|
sqlstore: o.SQLStore,
|
||||||
|
orgGetter: o.OrgGetter,
|
||||||
}
|
}
|
||||||
|
|
||||||
return m, nil
|
return m, nil
|
||||||
@ -239,14 +243,14 @@ func (m *Manager) Pause(b bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) initiate(ctx context.Context) error {
|
func (m *Manager) initiate(ctx context.Context) error {
|
||||||
orgIDs, err := m.ruleStore.ListOrgs(ctx)
|
orgs, err := m.orgGetter.ListByOwnedKeyRange(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var loadErrors []error
|
var loadErrors []error
|
||||||
for _, orgID := range orgIDs {
|
for _, org := range orgs {
|
||||||
storedRules, err := m.ruleStore.GetStoredRules(ctx, orgID.StringValue())
|
storedRules, err := m.ruleStore.GetStoredRules(ctx, org.ID.StringValue())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -279,7 +283,7 @@ func (m *Manager) initiate(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !parsedRule.Disabled {
|
if !parsedRule.Disabled {
|
||||||
err := m.addTask(ctx, orgID, parsedRule, taskName)
|
err := m.addTask(ctx, org.ID, parsedRule, taskName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Error("failed to load the rule definition", zap.String("name", taskName), zap.Error(err))
|
zap.L().Error("failed to load the rule definition", zap.String("name", taskName), zap.Error(err))
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/emailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing/noopemailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerserver"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/http/middleware"
|
"github.com/SigNoz/signoz/pkg/http/middleware"
|
||||||
@ -304,16 +308,22 @@ func NewFilterSuggestionsTestBed(t *testing.T) *FilterSuggestionsTestBed {
|
|||||||
mockClickhouse.MatchExpectationsInOrder(false)
|
mockClickhouse.MatchExpectationsInOrder(false)
|
||||||
|
|
||||||
providerSettings := instrumentationtest.New().ToProviderSettings()
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
emailing, _ := noopemailing.New(context.Background(), providerSettings, emailing.Config{})
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(testDB), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{Signoz: alertmanager.Signoz{PollInterval: 10 * time.Second, Config: alertmanagerserver.NewConfig()}}, testDB, orgGetter)
|
||||||
|
require.NoError(t, err)
|
||||||
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
modules := signoz.NewModules(testDB, jwt, emailing, providerSettings)
|
emailing := emailingtest.New()
|
||||||
|
modules := signoz.NewModules(testDB, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
|
handlers := signoz.NewHandlers(modules)
|
||||||
|
|
||||||
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
||||||
Reader: reader,
|
Reader: reader,
|
||||||
JWT: jwt,
|
JWT: jwt,
|
||||||
Signoz: &signoz.SigNoz{
|
Signoz: &signoz.SigNoz{
|
||||||
Modules: modules,
|
Modules: modules,
|
||||||
Handlers: signoz.NewHandlers(modules),
|
Handlers: handlers,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -322,13 +332,12 @@ func NewFilterSuggestionsTestBed(t *testing.T) *FilterSuggestionsTestBed {
|
|||||||
|
|
||||||
router := app.NewRouter()
|
router := app.NewRouter()
|
||||||
//add the jwt middleware
|
//add the jwt middleware
|
||||||
router.Use(middleware.NewAuth(jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
router.Use(middleware.NewAuth(jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}, sharder, instrumentationtest.New().Logger()).Wrap)
|
||||||
am := middleware.NewAuthZ(instrumentationtest.New().Logger())
|
am := middleware.NewAuthZ(instrumentationtest.New().Logger())
|
||||||
apiHandler.RegisterRoutes(router, am)
|
apiHandler.RegisterRoutes(router, am)
|
||||||
apiHandler.RegisterQueryRangeV3Routes(router, am)
|
apiHandler.RegisterQueryRangeV3Routes(router, am)
|
||||||
|
|
||||||
organizationModule := implorganization.NewModule(implorganization.NewStore(testDB))
|
user, apiErr := createTestUser(modules.OrgSetter, modules.User)
|
||||||
user, apiErr := createTestUser(organizationModule, modules.User)
|
|
||||||
if apiErr != nil {
|
if apiErr != nil {
|
||||||
t.Fatalf("could not create a test user: %v", apiErr)
|
t.Fatalf("could not create a test user: %v", apiErr)
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/emailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing/noopemailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerserver"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
||||||
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||||
@ -26,6 +28,8 @@ import (
|
|||||||
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
|
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/queryBuilderToExpr"
|
"github.com/SigNoz/signoz/pkg/query-service/queryBuilderToExpr"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/utils"
|
"github.com/SigNoz/signoz/pkg/query-service/utils"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||||
"github.com/SigNoz/signoz/pkg/signoz"
|
"github.com/SigNoz/signoz/pkg/signoz"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
@ -480,9 +484,14 @@ func NewTestbedWithoutOpamp(t *testing.T, sqlStore sqlstore.SQLStore) *LogPipeli
|
|||||||
}
|
}
|
||||||
|
|
||||||
providerSettings := instrumentationtest.New().ToProviderSettings()
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
emailing, _ := noopemailing.New(context.Background(), providerSettings, emailing.Config{})
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
jwt := authtypes.NewJWT("", 10*time.Minute, 30*time.Minute)
|
require.NoError(t, err)
|
||||||
modules := signoz.NewModules(sqlStore, jwt, emailing, providerSettings)
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlStore), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{Signoz: alertmanager.Signoz{PollInterval: 10 * time.Second, Config: alertmanagerserver.NewConfig()}}, sqlStore, orgGetter)
|
||||||
|
require.NoError(t, err)
|
||||||
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
|
emailing := emailingtest.New()
|
||||||
|
modules := signoz.NewModules(sqlStore, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
handlers := signoz.NewHandlers(modules)
|
handlers := signoz.NewHandlers(modules)
|
||||||
|
|
||||||
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
||||||
@ -497,8 +506,7 @@ func NewTestbedWithoutOpamp(t *testing.T, sqlStore sqlstore.SQLStore) *LogPipeli
|
|||||||
t.Fatalf("could not create a new ApiHandler: %v", err)
|
t.Fatalf("could not create a new ApiHandler: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
organizationModule := implorganization.NewModule(implorganization.NewStore(sqlStore))
|
user, apiErr := createTestUser(modules.OrgSetter, modules.User)
|
||||||
user, apiErr := createTestUser(organizationModule, modules.User)
|
|
||||||
if apiErr != nil {
|
if apiErr != nil {
|
||||||
t.Fatalf("could not create a test user: %v", apiErr)
|
t.Fatalf("could not create a test user: %v", apiErr)
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/emailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing/noopemailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerserver"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/http/middleware"
|
"github.com/SigNoz/signoz/pkg/http/middleware"
|
||||||
@ -365,9 +369,14 @@ func NewCloudIntegrationsTestBed(t *testing.T, testDB sqlstore.SQLStore) *CloudI
|
|||||||
mockClickhouse.MatchExpectationsInOrder(false)
|
mockClickhouse.MatchExpectationsInOrder(false)
|
||||||
|
|
||||||
providerSettings := instrumentationtest.New().ToProviderSettings()
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
emailing, _ := noopemailing.New(context.Background(), providerSettings, emailing.Config{})
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
jwt := authtypes.NewJWT("", 10*time.Minute, 30*time.Minute)
|
require.NoError(t, err)
|
||||||
modules := signoz.NewModules(testDB, jwt, emailing, providerSettings)
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(testDB), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{Signoz: alertmanager.Signoz{PollInterval: 10 * time.Second, Config: alertmanagerserver.NewConfig()}}, testDB, orgGetter)
|
||||||
|
require.NoError(t, err)
|
||||||
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
|
emailing := emailingtest.New()
|
||||||
|
modules := signoz.NewModules(testDB, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
handlers := signoz.NewHandlers(modules)
|
handlers := signoz.NewHandlers(modules)
|
||||||
|
|
||||||
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
||||||
@ -384,13 +393,12 @@ func NewCloudIntegrationsTestBed(t *testing.T, testDB sqlstore.SQLStore) *CloudI
|
|||||||
}
|
}
|
||||||
|
|
||||||
router := app.NewRouter()
|
router := app.NewRouter()
|
||||||
router.Use(middleware.NewAuth(jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
router.Use(middleware.NewAuth(jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}, sharder, instrumentationtest.New().Logger()).Wrap)
|
||||||
am := middleware.NewAuthZ(instrumentationtest.New().Logger())
|
am := middleware.NewAuthZ(instrumentationtest.New().Logger())
|
||||||
apiHandler.RegisterRoutes(router, am)
|
apiHandler.RegisterRoutes(router, am)
|
||||||
apiHandler.RegisterCloudIntegrationsRoutes(router, am)
|
apiHandler.RegisterCloudIntegrationsRoutes(router, am)
|
||||||
|
|
||||||
organizationModule := implorganization.NewModule(implorganization.NewStore(testDB))
|
user, apiErr := createTestUser(modules.OrgSetter, modules.User)
|
||||||
user, apiErr := createTestUser(organizationModule, modules.User)
|
|
||||||
if apiErr != nil {
|
if apiErr != nil {
|
||||||
t.Fatalf("could not create a test user: %v", apiErr)
|
t.Fatalf("could not create a test user: %v", apiErr)
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/emailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing/noopemailing"
|
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerserver"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
||||||
"github.com/SigNoz/signoz/pkg/http/middleware"
|
"github.com/SigNoz/signoz/pkg/http/middleware"
|
||||||
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||||
@ -22,6 +23,8 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/query-service/model"
|
"github.com/SigNoz/signoz/pkg/query-service/model"
|
||||||
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
|
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
|
||||||
"github.com/SigNoz/signoz/pkg/query-service/utils"
|
"github.com/SigNoz/signoz/pkg/query-service/utils"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||||
"github.com/SigNoz/signoz/pkg/signoz"
|
"github.com/SigNoz/signoz/pkg/signoz"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
@ -571,9 +574,14 @@ func NewIntegrationsTestBed(t *testing.T, testDB sqlstore.SQLStore) *Integration
|
|||||||
}
|
}
|
||||||
|
|
||||||
providerSettings := instrumentationtest.New().ToProviderSettings()
|
providerSettings := instrumentationtest.New().ToProviderSettings()
|
||||||
emailing, _ := noopemailing.New(context.Background(), providerSettings, emailing.Config{})
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
jwt := authtypes.NewJWT("", 10*time.Minute, 30*time.Minute)
|
require.NoError(t, err)
|
||||||
modules := signoz.NewModules(testDB, jwt, emailing, providerSettings)
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(testDB), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{Signoz: alertmanager.Signoz{PollInterval: 10 * time.Second, Config: alertmanagerserver.NewConfig()}}, testDB, orgGetter)
|
||||||
|
require.NoError(t, err)
|
||||||
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
|
emailing := emailingtest.New()
|
||||||
|
modules := signoz.NewModules(testDB, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
handlers := signoz.NewHandlers(modules)
|
handlers := signoz.NewHandlers(modules)
|
||||||
|
|
||||||
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
apiHandler, err := app.NewAPIHandler(app.APIHandlerOpts{
|
||||||
@ -592,13 +600,12 @@ func NewIntegrationsTestBed(t *testing.T, testDB sqlstore.SQLStore) *Integration
|
|||||||
}
|
}
|
||||||
|
|
||||||
router := app.NewRouter()
|
router := app.NewRouter()
|
||||||
router.Use(middleware.NewAuth(jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}).Wrap)
|
router.Use(middleware.NewAuth(jwt, []string{"Authorization", "Sec-WebSocket-Protocol"}, sharder, instrumentationtest.New().Logger()).Wrap)
|
||||||
am := middleware.NewAuthZ(instrumentationtest.New().Logger())
|
am := middleware.NewAuthZ(instrumentationtest.New().Logger())
|
||||||
apiHandler.RegisterRoutes(router, am)
|
apiHandler.RegisterRoutes(router, am)
|
||||||
apiHandler.RegisterIntegrationRoutes(router, am)
|
apiHandler.RegisterIntegrationRoutes(router, am)
|
||||||
|
|
||||||
organizationModule := implorganization.NewModule(implorganization.NewStore(testDB))
|
user, apiErr := createTestUser(modules.OrgSetter, modules.User)
|
||||||
user, apiErr := createTestUser(organizationModule, modules.User)
|
|
||||||
if apiErr != nil {
|
if apiErr != nil {
|
||||||
t.Fatalf("could not create a test user: %v", apiErr)
|
t.Fatalf("could not create a test user: %v", apiErr)
|
||||||
}
|
}
|
||||||
|
@ -147,11 +147,11 @@ func makeTestSignozLog(
|
|||||||
return testLog
|
return testLog
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestUser(organizationModule organization.Module, userModule user.Module) (*types.User, *model.ApiError) {
|
func createTestUser(orgSetter organization.Setter, userModule user.Module) (*types.User, *model.ApiError) {
|
||||||
// Create a test user for auth
|
// Create a test user for auth
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
organization := types.NewOrganization("test")
|
organization := types.NewOrganization("test")
|
||||||
err := organizationModule.Create(ctx, organization)
|
err := orgSetter.Create(ctx, organization)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, model.InternalError(err)
|
return nil, model.InternalError(err)
|
||||||
}
|
}
|
||||||
|
@ -88,9 +88,9 @@ func buildSingleFilterCondition(key string, op v3.FilterOperator, fmtVal string,
|
|||||||
case v3.FilterOperatorLessThanOrEq:
|
case v3.FilterOperatorLessThanOrEq:
|
||||||
return fmt.Sprintf("%s <= %s", keyCondition, fmtVal), nil
|
return fmt.Sprintf("%s <= %s", keyCondition, fmtVal), nil
|
||||||
case v3.FilterOperatorContains:
|
case v3.FilterOperatorContains:
|
||||||
return fmt.Sprintf("like(%s, %s)", keyCondition, fmtVal), nil
|
return fmt.Sprintf("ilike(%s, %s)", keyCondition, fmtVal), nil
|
||||||
case v3.FilterOperatorNotContains:
|
case v3.FilterOperatorNotContains:
|
||||||
return fmt.Sprintf("notLike(%s, %s)", keyCondition, fmtVal), nil
|
return fmt.Sprintf("notILike(%s, %s)", keyCondition, fmtVal), nil
|
||||||
case v3.FilterOperatorExists:
|
case v3.FilterOperatorExists:
|
||||||
return fmt.Sprintf("has(JSONExtractKeys(labels), '%s')", key), nil
|
return fmt.Sprintf("has(JSONExtractKeys(labels), '%s')", key), nil
|
||||||
case v3.FilterOperatorNotExists:
|
case v3.FilterOperatorNotExists:
|
||||||
|
@ -67,6 +67,7 @@ func NewTestSqliteDB(t *testing.T) (sqlStore sqlstore.SQLStore, testDBFilePath s
|
|||||||
sqlmigration.NewAuthRefactorFactory(sqlStore),
|
sqlmigration.NewAuthRefactorFactory(sqlStore),
|
||||||
sqlmigration.NewMigratePATToFactorAPIKey(sqlStore),
|
sqlmigration.NewMigratePATToFactorAPIKey(sqlStore),
|
||||||
sqlmigration.NewUpdateApiMonitoringFiltersFactory(sqlStore),
|
sqlmigration.NewUpdateApiMonitoringFiltersFactory(sqlStore),
|
||||||
|
sqlmigration.NewAddKeyOrganizationFactory(sqlStore),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/types"
|
|
||||||
ruletypes "github.com/SigNoz/signoz/pkg/types/ruletypes"
|
ruletypes "github.com/SigNoz/signoz/pkg/types/ruletypes"
|
||||||
"github.com/SigNoz/signoz/pkg/valuer"
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
@ -118,27 +117,3 @@ func (r *rule) GetRuleUUID(ctx context.Context, ruleID int) (*ruletypes.RuleHist
|
|||||||
}
|
}
|
||||||
return ruleHistory, nil
|
return ruleHistory, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rule) ListOrgs(ctx context.Context) ([]valuer.UUID, error) {
|
|
||||||
orgIDStrs := make([]string, 0)
|
|
||||||
err := r.sqlstore.
|
|
||||||
BunDB().
|
|
||||||
NewSelect().
|
|
||||||
Model(new(types.Organization)).
|
|
||||||
Column("id").
|
|
||||||
Scan(ctx, &orgIDStrs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
orgIDs := make([]valuer.UUID, len(orgIDStrs))
|
|
||||||
for idx, orgIDStr := range orgIDStrs {
|
|
||||||
orgID, err := valuer.NewUUID(orgIDStr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
orgIDs[idx] = orgID
|
|
||||||
}
|
|
||||||
|
|
||||||
return orgIDs, nil
|
|
||||||
}
|
|
||||||
|
32
pkg/sharder/config.go
Normal file
32
pkg/sharder/config.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package sharder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Provider string `mapstructure:"provider"`
|
||||||
|
Single Single `mapstructure:"single"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Single struct {
|
||||||
|
OrgID valuer.UUID `mapstructure:"org_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfigFactory() factory.ConfigFactory {
|
||||||
|
return factory.NewConfigFactory(factory.MustNewName("sharder"), newConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConfig() factory.Config {
|
||||||
|
return &Config{
|
||||||
|
Provider: "noop",
|
||||||
|
Single: Single{
|
||||||
|
OrgID: valuer.UUID{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) Validate() error {
|
||||||
|
return nil
|
||||||
|
}
|
33
pkg/sharder/noopsharder/provider.go
Normal file
33
pkg/sharder/noopsharder/provider.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package noopsharder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type provider struct {
|
||||||
|
settings factory.ScopedProviderSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFactory() factory.ProviderFactory[sharder.Sharder, sharder.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("noop"), New)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(ctx context.Context, providerSettings factory.ProviderSettings, config sharder.Config) (sharder.Sharder, error) {
|
||||||
|
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/sharder/noopsharder")
|
||||||
|
|
||||||
|
return &provider{
|
||||||
|
settings: settings,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *provider) GetMyOwnedKeyRange(ctx context.Context) (uint32, uint32, error) {
|
||||||
|
return 0, math.MaxUint32, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *provider) IsMyOwnedKey(ctx context.Context, key uint32) error {
|
||||||
|
return nil
|
||||||
|
}
|
13
pkg/sharder/sharder.go
Normal file
13
pkg/sharder/sharder.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package sharder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Sharder interface {
|
||||||
|
// Returns the keys owned by the current instance.
|
||||||
|
GetMyOwnedKeyRange(context.Context) (uint32, uint32, error)
|
||||||
|
|
||||||
|
// Returns true if the key is owned by the current instance.
|
||||||
|
IsMyOwnedKey(context.Context, uint32) error
|
||||||
|
}
|
43
pkg/sharder/singlesharder/provider.go
Normal file
43
pkg/sharder/singlesharder/provider.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package singlesharder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type provider struct {
|
||||||
|
settings factory.ScopedProviderSettings
|
||||||
|
orgID valuer.UUID
|
||||||
|
orgIDKey uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFactory() factory.ProviderFactory[sharder.Sharder, sharder.Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("single"), New)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(ctx context.Context, providerSettings factory.ProviderSettings, config sharder.Config) (sharder.Sharder, error) {
|
||||||
|
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/sharder/singlesharder")
|
||||||
|
|
||||||
|
return &provider{
|
||||||
|
settings: settings,
|
||||||
|
orgID: config.Single.OrgID,
|
||||||
|
orgIDKey: types.NewOrganizationKey(config.Single.OrgID),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *provider) GetMyOwnedKeyRange(ctx context.Context) (uint32, uint32, error) {
|
||||||
|
return provider.orgIDKey, provider.orgIDKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *provider) IsMyOwnedKey(ctx context.Context, key uint32) error {
|
||||||
|
if key == provider.orgIDKey {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Newf(errors.TypeForbidden, errors.CodeForbidden, "key %d for org %s is not owned by my current instance", key, provider.orgID)
|
||||||
|
}
|
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
"github.com/SigNoz/signoz/pkg/instrumentation"
|
"github.com/SigNoz/signoz/pkg/instrumentation"
|
||||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlmigrator"
|
"github.com/SigNoz/signoz/pkg/sqlmigrator"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
@ -62,6 +63,9 @@ type Config struct {
|
|||||||
|
|
||||||
// Emailing config
|
// Emailing config
|
||||||
Emailing emailing.Config `mapstructure:"emailing" yaml:"emailing"`
|
Emailing emailing.Config `mapstructure:"emailing" yaml:"emailing"`
|
||||||
|
|
||||||
|
// Sharder config
|
||||||
|
Sharder sharder.Config `mapstructure:"sharder" yaml:"sharder"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeprecatedFlags are the flags that are deprecated and scheduled for removal.
|
// DeprecatedFlags are the flags that are deprecated and scheduled for removal.
|
||||||
@ -86,6 +90,7 @@ func NewConfig(ctx context.Context, resolverConfig config.ResolverConfig, deprec
|
|||||||
prometheus.NewConfigFactory(),
|
prometheus.NewConfigFactory(),
|
||||||
alertmanager.NewConfigFactory(),
|
alertmanager.NewConfigFactory(),
|
||||||
emailing.NewConfigFactory(),
|
emailing.NewConfigFactory(),
|
||||||
|
sharder.NewConfigFactory(),
|
||||||
}
|
}
|
||||||
|
|
||||||
conf, err := config.New(ctx, resolverConfig, configFactories)
|
conf, err := config.New(ctx, resolverConfig, configFactories)
|
||||||
|
@ -13,6 +13,8 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/modules/quickfilter/implquickfilter"
|
"github.com/SigNoz/signoz/pkg/modules/quickfilter/implquickfilter"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/savedview"
|
"github.com/SigNoz/signoz/pkg/modules/savedview"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/savedview/implsavedview"
|
"github.com/SigNoz/signoz/pkg/modules/savedview/implsavedview"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/tracefunnel"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/tracefunnel/impltracefunnel"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
|
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
|
||||||
)
|
)
|
||||||
@ -25,16 +27,18 @@ type Handlers struct {
|
|||||||
Apdex apdex.Handler
|
Apdex apdex.Handler
|
||||||
Dashboard dashboard.Handler
|
Dashboard dashboard.Handler
|
||||||
QuickFilter quickfilter.Handler
|
QuickFilter quickfilter.Handler
|
||||||
|
TraceFunnel tracefunnel.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandlers(modules Modules) Handlers {
|
func NewHandlers(modules Modules) Handlers {
|
||||||
return Handlers{
|
return Handlers{
|
||||||
Organization: implorganization.NewHandler(modules.Organization),
|
Organization: implorganization.NewHandler(modules.OrgGetter, modules.OrgSetter),
|
||||||
Preference: implpreference.NewHandler(modules.Preference),
|
Preference: implpreference.NewHandler(modules.Preference),
|
||||||
User: impluser.NewHandler(modules.User),
|
User: impluser.NewHandler(modules.User),
|
||||||
SavedView: implsavedview.NewHandler(modules.SavedView),
|
SavedView: implsavedview.NewHandler(modules.SavedView),
|
||||||
Apdex: implapdex.NewHandler(modules.Apdex),
|
Apdex: implapdex.NewHandler(modules.Apdex),
|
||||||
Dashboard: impldashboard.NewHandler(modules.Dashboard),
|
Dashboard: impldashboard.NewHandler(modules.Dashboard),
|
||||||
QuickFilter: implquickfilter.NewHandler(modules.QuickFilter),
|
QuickFilter: implquickfilter.NewHandler(modules.QuickFilter),
|
||||||
|
TraceFunnel: impltracefunnel.NewHandler(modules.TraceFunnel),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,40 @@
|
|||||||
package signoz
|
package signoz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/DATA-DOG/go-sqlmock"
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
||||||
"github.com/SigNoz/signoz/pkg/factory/factorytest"
|
"github.com/SigNoz/signoz/pkg/factory/factorytest"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstoretest"
|
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstoretest"
|
||||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is a test to ensure that all fields of the handlers are initialized.
|
// This is a test to ensure that all fields of the handlers are initialized.
|
||||||
// It also helps us catch these errors at compile time instead of runtime.
|
// It also helps us catch these errors at compile time instead of runtime.
|
||||||
func TestNewHandlers(t *testing.T) {
|
func TestNewHandlers(t *testing.T) {
|
||||||
sqlstore := sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual)
|
sqlstore := sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual)
|
||||||
|
providerSettings := factorytest.NewSettings()
|
||||||
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlstore), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{}, sqlstore, orgGetter)
|
||||||
|
require.NoError(t, err)
|
||||||
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
emailing := emailingtest.New()
|
emailing := emailingtest.New()
|
||||||
providerSettings := factorytest.NewSettings()
|
modules := NewModules(sqlstore, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
|
|
||||||
modules := NewModules(sqlstore, jwt, emailing, providerSettings)
|
|
||||||
handlers := NewHandlers(modules)
|
handlers := NewHandlers(modules)
|
||||||
|
|
||||||
reflectVal := reflect.ValueOf(handlers)
|
reflectVal := reflect.ValueOf(handlers)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package signoz
|
package signoz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing"
|
"github.com/SigNoz/signoz/pkg/emailing"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/apdex"
|
"github.com/SigNoz/signoz/pkg/modules/apdex"
|
||||||
@ -15,6 +16,8 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/modules/quickfilter/implquickfilter"
|
"github.com/SigNoz/signoz/pkg/modules/quickfilter/implquickfilter"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/savedview"
|
"github.com/SigNoz/signoz/pkg/modules/savedview"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/savedview/implsavedview"
|
"github.com/SigNoz/signoz/pkg/modules/savedview/implsavedview"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/tracefunnel"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/tracefunnel/impltracefunnel"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user"
|
"github.com/SigNoz/signoz/pkg/modules/user"
|
||||||
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
|
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
@ -23,23 +26,37 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Modules struct {
|
type Modules struct {
|
||||||
Organization organization.Module
|
OrgGetter organization.Getter
|
||||||
Preference preference.Module
|
OrgSetter organization.Setter
|
||||||
User user.Module
|
Preference preference.Module
|
||||||
SavedView savedview.Module
|
User user.Module
|
||||||
Apdex apdex.Module
|
SavedView savedview.Module
|
||||||
Dashboard dashboard.Module
|
Apdex apdex.Module
|
||||||
QuickFilter quickfilter.Module
|
Dashboard dashboard.Module
|
||||||
|
QuickFilter quickfilter.Module
|
||||||
|
TraceFunnel tracefunnel.Module
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewModules(sqlstore sqlstore.SQLStore, jwt *authtypes.JWT, emailing emailing.Emailing, providerSettings factory.ProviderSettings) Modules {
|
func NewModules(
|
||||||
|
sqlstore sqlstore.SQLStore,
|
||||||
|
jwt *authtypes.JWT,
|
||||||
|
emailing emailing.Emailing,
|
||||||
|
providerSettings factory.ProviderSettings,
|
||||||
|
orgGetter organization.Getter,
|
||||||
|
alertmanager alertmanager.Alertmanager,
|
||||||
|
) Modules {
|
||||||
|
quickfilter := implquickfilter.NewModule(implquickfilter.NewStore(sqlstore))
|
||||||
|
orgSetter := implorganization.NewSetter(implorganization.NewStore(sqlstore), alertmanager, quickfilter)
|
||||||
|
user := impluser.NewModule(impluser.NewStore(sqlstore, providerSettings), jwt, emailing, providerSettings, orgSetter)
|
||||||
return Modules{
|
return Modules{
|
||||||
Organization: implorganization.NewModule(implorganization.NewStore(sqlstore)),
|
OrgGetter: orgGetter,
|
||||||
Preference: implpreference.NewModule(implpreference.NewStore(sqlstore), preferencetypes.NewDefaultPreferenceMap()),
|
OrgSetter: orgSetter,
|
||||||
SavedView: implsavedview.NewModule(sqlstore),
|
Preference: implpreference.NewModule(implpreference.NewStore(sqlstore), preferencetypes.NewDefaultPreferenceMap()),
|
||||||
Apdex: implapdex.NewModule(sqlstore),
|
SavedView: implsavedview.NewModule(sqlstore),
|
||||||
Dashboard: impldashboard.NewModule(sqlstore),
|
Apdex: implapdex.NewModule(sqlstore),
|
||||||
User: impluser.NewModule(impluser.NewStore(sqlstore, providerSettings), jwt, emailing, providerSettings),
|
Dashboard: impldashboard.NewModule(sqlstore),
|
||||||
QuickFilter: implquickfilter.NewModule(implquickfilter.NewStore(sqlstore)),
|
User: user,
|
||||||
|
QuickFilter: quickfilter,
|
||||||
|
TraceFunnel: impltracefunnel.NewModule(impltracefunnel.NewStore(sqlstore)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,39 @@
|
|||||||
package signoz
|
package signoz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/DATA-DOG/go-sqlmock"
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager"
|
||||||
|
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
|
||||||
"github.com/SigNoz/signoz/pkg/factory/factorytest"
|
"github.com/SigNoz/signoz/pkg/factory/factorytest"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstoretest"
|
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstoretest"
|
||||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is a test to ensure that all fields of the modules are initialized.
|
// This is a test to ensure that all fields of the modules are initialized.
|
||||||
// It also helps us catch these errors at compile time instead of runtime.
|
// It also helps us catch these errors at compile time instead of runtime.
|
||||||
func TestNewModules(t *testing.T) {
|
func TestNewModules(t *testing.T) {
|
||||||
sqlstore := sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual)
|
sqlstore := sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual)
|
||||||
|
providerSettings := factorytest.NewSettings()
|
||||||
|
sharder, err := noopsharder.New(context.TODO(), providerSettings, sharder.Config{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlstore), sharder)
|
||||||
|
alertmanager, err := signozalertmanager.New(context.TODO(), providerSettings, alertmanager.Config{}, sqlstore, orgGetter)
|
||||||
|
require.NoError(t, err)
|
||||||
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
jwt := authtypes.NewJWT("", 1*time.Hour, 1*time.Hour)
|
||||||
emailing := emailingtest.New()
|
emailing := emailingtest.New()
|
||||||
providerSettings := factorytest.NewSettings()
|
modules := NewModules(sqlstore, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
modules := NewModules(sqlstore, jwt, emailing, providerSettings)
|
|
||||||
|
|
||||||
reflectVal := reflect.ValueOf(modules)
|
reflectVal := reflect.ValueOf(modules)
|
||||||
for i := 0; i < reflectVal.NumField(); i++ {
|
for i := 0; i < reflectVal.NumField(); i++ {
|
||||||
|
@ -11,8 +11,12 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/emailing/noopemailing"
|
"github.com/SigNoz/signoz/pkg/emailing/noopemailing"
|
||||||
"github.com/SigNoz/signoz/pkg/emailing/smtpemailing"
|
"github.com/SigNoz/signoz/pkg/emailing/smtpemailing"
|
||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||||
"github.com/SigNoz/signoz/pkg/prometheus/clickhouseprometheus"
|
"github.com/SigNoz/signoz/pkg/prometheus/clickhouseprometheus"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder/singlesharder"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore/sqlitesqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore/sqlitesqlstore"
|
||||||
@ -83,6 +87,8 @@ func NewSQLMigrationProviderFactories(sqlstore sqlstore.SQLStore) factory.NamedM
|
|||||||
sqlmigration.NewUpdateLicenseFactory(sqlstore),
|
sqlmigration.NewUpdateLicenseFactory(sqlstore),
|
||||||
sqlmigration.NewMigratePATToFactorAPIKey(sqlstore),
|
sqlmigration.NewMigratePATToFactorAPIKey(sqlstore),
|
||||||
sqlmigration.NewUpdateApiMonitoringFiltersFactory(sqlstore),
|
sqlmigration.NewUpdateApiMonitoringFiltersFactory(sqlstore),
|
||||||
|
sqlmigration.NewAddKeyOrganizationFactory(sqlstore),
|
||||||
|
sqlmigration.NewAddTraceFunnelsFactory(sqlstore),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,10 +104,10 @@ func NewPrometheusProviderFactories(telemetryStore telemetrystore.TelemetryStore
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAlertmanagerProviderFactories(sqlstore sqlstore.SQLStore) factory.NamedMap[factory.ProviderFactory[alertmanager.Alertmanager, alertmanager.Config]] {
|
func NewAlertmanagerProviderFactories(sqlstore sqlstore.SQLStore, orgGetter organization.Getter) factory.NamedMap[factory.ProviderFactory[alertmanager.Alertmanager, alertmanager.Config]] {
|
||||||
return factory.MustNewNamedMap(
|
return factory.MustNewNamedMap(
|
||||||
legacyalertmanager.NewFactory(sqlstore),
|
legacyalertmanager.NewFactory(sqlstore, orgGetter),
|
||||||
signozalertmanager.NewFactory(sqlstore),
|
signozalertmanager.NewFactory(sqlstore, orgGetter),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,3 +117,10 @@ func NewEmailingProviderFactories() factory.NamedMap[factory.ProviderFactory[ema
|
|||||||
smtpemailing.NewFactory(),
|
smtpemailing.NewFactory(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewSharderProviderFactories() factory.NamedMap[factory.ProviderFactory[sharder.Sharder, sharder.Config]] {
|
||||||
|
return factory.MustNewNamedMap(
|
||||||
|
singlesharder.NewFactory(),
|
||||||
|
noopsharder.NewFactory(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/DATA-DOG/go-sqlmock"
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstoretest"
|
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstoretest"
|
||||||
"github.com/SigNoz/signoz/pkg/telemetrystore"
|
"github.com/SigNoz/signoz/pkg/telemetrystore"
|
||||||
@ -40,10 +41,15 @@ func TestNewProviderFactories(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
assert.NotPanics(t, func() {
|
assert.NotPanics(t, func() {
|
||||||
NewAlertmanagerProviderFactories(sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual))
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual)), nil)
|
||||||
|
NewAlertmanagerProviderFactories(sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual), orgGetter)
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NotPanics(t, func() {
|
assert.NotPanics(t, func() {
|
||||||
NewEmailingProviderFactories()
|
NewEmailingProviderFactories()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
NewSharderProviderFactories()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,10 @@ import (
|
|||||||
"github.com/SigNoz/signoz/pkg/factory"
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
"github.com/SigNoz/signoz/pkg/instrumentation"
|
"github.com/SigNoz/signoz/pkg/instrumentation"
|
||||||
"github.com/SigNoz/signoz/pkg/licensing"
|
"github.com/SigNoz/signoz/pkg/licensing"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization"
|
||||||
|
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
|
||||||
"github.com/SigNoz/signoz/pkg/prometheus"
|
"github.com/SigNoz/signoz/pkg/prometheus"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sharder"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlmigrator"
|
"github.com/SigNoz/signoz/pkg/sqlmigrator"
|
||||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
@ -33,6 +36,7 @@ type SigNoz struct {
|
|||||||
Zeus zeus.Zeus
|
Zeus zeus.Zeus
|
||||||
Licensing licensing.Licensing
|
Licensing licensing.Licensing
|
||||||
Emailing emailing.Emailing
|
Emailing emailing.Emailing
|
||||||
|
Sharder sharder.Sharder
|
||||||
Modules Modules
|
Modules Modules
|
||||||
Handlers Handlers
|
Handlers Handlers
|
||||||
}
|
}
|
||||||
@ -44,7 +48,7 @@ func New(
|
|||||||
zeusConfig zeus.Config,
|
zeusConfig zeus.Config,
|
||||||
zeusProviderFactory factory.ProviderFactory[zeus.Zeus, zeus.Config],
|
zeusProviderFactory factory.ProviderFactory[zeus.Zeus, zeus.Config],
|
||||||
licenseConfig licensing.Config,
|
licenseConfig licensing.Config,
|
||||||
licenseProviderFactoryCb func(sqlstore.SQLStore, zeus.Zeus) factory.ProviderFactory[licensing.Licensing, licensing.Config],
|
licenseProviderFactoryCb func(sqlstore.SQLStore, zeus.Zeus, organization.Getter) factory.ProviderFactory[licensing.Licensing, licensing.Config],
|
||||||
emailingProviderFactories factory.NamedMap[factory.ProviderFactory[emailing.Emailing, emailing.Config]],
|
emailingProviderFactories factory.NamedMap[factory.ProviderFactory[emailing.Emailing, emailing.Config]],
|
||||||
cacheProviderFactories factory.NamedMap[factory.ProviderFactory[cache.Cache, cache.Config]],
|
cacheProviderFactories factory.NamedMap[factory.ProviderFactory[cache.Cache, cache.Config]],
|
||||||
webProviderFactories factory.NamedMap[factory.ProviderFactory[web.Web, web.Config]],
|
webProviderFactories factory.NamedMap[factory.ProviderFactory[web.Web, web.Config]],
|
||||||
@ -162,19 +166,34 @@ func New(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize sharder from the available sharder provider factories
|
||||||
|
sharder, err := factory.NewProviderFromNamedMap(
|
||||||
|
ctx,
|
||||||
|
providerSettings,
|
||||||
|
config.Sharder,
|
||||||
|
NewSharderProviderFactories(),
|
||||||
|
config.Sharder.Provider,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize organization getter
|
||||||
|
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlstore), sharder)
|
||||||
|
|
||||||
// Initialize alertmanager from the available alertmanager provider factories
|
// Initialize alertmanager from the available alertmanager provider factories
|
||||||
alertmanager, err := factory.NewProviderFromNamedMap(
|
alertmanager, err := factory.NewProviderFromNamedMap(
|
||||||
ctx,
|
ctx,
|
||||||
providerSettings,
|
providerSettings,
|
||||||
config.Alertmanager,
|
config.Alertmanager,
|
||||||
NewAlertmanagerProviderFactories(sqlstore),
|
NewAlertmanagerProviderFactories(sqlstore, orgGetter),
|
||||||
config.Alertmanager.Provider,
|
config.Alertmanager.Provider,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
licensingProviderFactory := licenseProviderFactoryCb(sqlstore, zeus)
|
licensingProviderFactory := licenseProviderFactoryCb(sqlstore, zeus, orgGetter)
|
||||||
licensing, err := licensingProviderFactory.New(
|
licensing, err := licensingProviderFactory.New(
|
||||||
ctx,
|
ctx,
|
||||||
providerSettings,
|
providerSettings,
|
||||||
@ -185,7 +204,7 @@ func New(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize all modules
|
// Initialize all modules
|
||||||
modules := NewModules(sqlstore, jwt, emailing, providerSettings)
|
modules := NewModules(sqlstore, jwt, emailing, providerSettings, orgGetter, alertmanager)
|
||||||
|
|
||||||
// Initialize all handlers for the modules
|
// Initialize all handlers for the modules
|
||||||
handlers := NewHandlers(modules)
|
handlers := NewHandlers(modules)
|
||||||
@ -212,6 +231,7 @@ func New(
|
|||||||
Zeus: zeus,
|
Zeus: zeus,
|
||||||
Licensing: licensing,
|
Licensing: licensing,
|
||||||
Emailing: emailing,
|
Emailing: emailing,
|
||||||
|
Sharder: sharder,
|
||||||
Modules: modules,
|
Modules: modules,
|
||||||
Handlers: handlers,
|
Handlers: handlers,
|
||||||
}, nil
|
}, nil
|
||||||
|
112
pkg/sqlmigration/036_add_key_organization.go
Normal file
112
pkg/sqlmigration/036_add_key_organization.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package sqlmigration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"hash/fnv"
|
||||||
|
|
||||||
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
)
|
||||||
|
|
||||||
|
type addKeyOrganization struct {
|
||||||
|
sqlstore sqlstore.SQLStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddKeyOrganizationFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_key_organization"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||||
|
return newAddKeyOrganization(ctx, providerSettings, config, sqlstore)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddKeyOrganization(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore) (SQLMigration, error) {
|
||||||
|
return &addKeyOrganization{
|
||||||
|
sqlstore: sqlstore,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addKeyOrganization) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addKeyOrganization) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
ok, err := migration.sqlstore.Dialect().ColumnExists(ctx, db, "organizations", "key")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := db.BeginTx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err := tx.
|
||||||
|
NewAddColumn().
|
||||||
|
Table("organizations").
|
||||||
|
ColumnExpr("key BIGINT").
|
||||||
|
Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var existingOrgIDs []string
|
||||||
|
if err := tx.NewSelect().
|
||||||
|
Table("organizations").
|
||||||
|
Column("id").
|
||||||
|
Scan(ctx, &existingOrgIDs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, orgID := range existingOrgIDs {
|
||||||
|
key := migration.getHash(ctx, orgID)
|
||||||
|
if _, err := tx.
|
||||||
|
NewUpdate().
|
||||||
|
Table("organizations").
|
||||||
|
Set("key = ?", key).
|
||||||
|
Where("id = ?", orgID).
|
||||||
|
Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := tx.
|
||||||
|
NewCreateIndex().
|
||||||
|
Unique().
|
||||||
|
IfNotExists().
|
||||||
|
Index("idx_unique_key").
|
||||||
|
Table("organizations").
|
||||||
|
Column("key").
|
||||||
|
Exec(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addKeyOrganization) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addKeyOrganization) getHash(_ context.Context, orgID string) uint32 {
|
||||||
|
hasher := fnv.New32a()
|
||||||
|
|
||||||
|
// Hasher never returns err.
|
||||||
|
_, _ = hasher.Write([]byte(orgID))
|
||||||
|
return hasher.Sum32()
|
||||||
|
}
|
89
pkg/sqlmigration/037_add_trace_funnels.go
Normal file
89
pkg/sqlmigration/037_add_trace_funnels.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package sqlmigration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/SigNoz/signoz/pkg/factory"
|
||||||
|
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||||
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
|
"github.com/SigNoz/signoz/pkg/valuer"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/migrate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// funnel Core Data Structure (funnel and funnelStep)
|
||||||
|
type funnel struct {
|
||||||
|
bun.BaseModel `bun:"table:trace_funnel"`
|
||||||
|
types.Identifiable // funnel id
|
||||||
|
types.TimeAuditable
|
||||||
|
types.UserAuditable
|
||||||
|
Name string `json:"funnel_name" bun:"name,type:text,notnull"` // funnel name
|
||||||
|
Description string `json:"description" bun:"description,type:text"` // funnel description
|
||||||
|
OrgID valuer.UUID `json:"org_id" bun:"org_id,type:varchar,notnull"`
|
||||||
|
Steps []funnelStep `json:"steps" bun:"steps,type:text,notnull"`
|
||||||
|
Tags string `json:"tags" bun:"tags,type:text"`
|
||||||
|
CreatedByUser *types.User `json:"user" bun:"rel:belongs-to,join:created_by=id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type funnelStep struct {
|
||||||
|
types.Identifiable
|
||||||
|
Name string `json:"name,omitempty"` // step name
|
||||||
|
Description string `json:"description,omitempty"` // step description
|
||||||
|
Order int64 `json:"step_order"`
|
||||||
|
ServiceName string `json:"service_name"`
|
||||||
|
SpanName string `json:"span_name"`
|
||||||
|
Filters string `json:"filters,omitempty"`
|
||||||
|
LatencyPointer string `json:"latency_pointer,omitempty"`
|
||||||
|
LatencyType string `json:"latency_type,omitempty"`
|
||||||
|
HasErrors bool `json:"has_errors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type addTraceFunnels struct {
|
||||||
|
sqlstore sqlstore.SQLStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddTraceFunnelsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||||
|
return factory.NewProviderFactory(factory.MustNewName("add_trace_funnels"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||||
|
return newAddTraceFunnels(ctx, providerSettings, config, sqlstore)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddTraceFunnels(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore) (SQLMigration, error) {
|
||||||
|
return &addTraceFunnels{sqlstore: sqlstore}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addTraceFunnels) Register(migrations *migrate.Migrations) error {
|
||||||
|
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addTraceFunnels) Up(ctx context.Context, db *bun.DB) error {
|
||||||
|
tx, err := db.BeginTx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = tx.NewCreateTable().
|
||||||
|
Model(new(funnel)).
|
||||||
|
ForeignKey(`("org_id") REFERENCES "organizations" ("id") ON DELETE CASCADE`).
|
||||||
|
IfNotExists().
|
||||||
|
Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (migration *addTraceFunnels) Down(ctx context.Context, db *bun.DB) error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -369,9 +369,6 @@ type ConfigStore interface {
|
|||||||
// Get returns the config for the given orgID
|
// Get returns the config for the given orgID
|
||||||
Get(context.Context, string) (*Config, error)
|
Get(context.Context, string) (*Config, error)
|
||||||
|
|
||||||
// ListOrgs returns the list of orgs
|
|
||||||
ListOrgs(context.Context) ([]string, error)
|
|
||||||
|
|
||||||
// CreateChannel creates a new channel.
|
// CreateChannel creates a new channel.
|
||||||
CreateChannel(context.Context, *Channel, ...StoreOption) error
|
CreateChannel(context.Context, *Channel, ...StoreOption) error
|
||||||
|
|
||||||
|
15
pkg/types/apdextypes/settings.go
Normal file
15
pkg/types/apdextypes/settings.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package apdextypes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/SigNoz/signoz/pkg/types"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Settings struct {
|
||||||
|
bun.BaseModel `bun:"table:apdex_setting"`
|
||||||
|
types.Identifiable
|
||||||
|
OrgID string `bun:"org_id,type:text" json:"orgId"`
|
||||||
|
ServiceName string `bun:"service_name,type:text" json:"serviceName"`
|
||||||
|
Threshold float64 `bun:"threshold,type:float,notnull" json:"threshold"`
|
||||||
|
ExcludeStatusCodes string `bun:"exclude_status_codes,type:text,notnull" json:"excludeStatusCodes"`
|
||||||
|
}
|
@ -87,9 +87,6 @@ func GetActiveLicenseFromStorableLicenses(storableLicenses []*StorableLicense, o
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if license.Status == "INVALID" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if activeLicense == nil &&
|
if activeLicense == nil &&
|
||||||
(license.ValidFrom != 0) &&
|
(license.ValidFrom != 0) &&
|
||||||
(license.ValidUntil == -1 || license.ValidUntil > time.Now().Unix()) {
|
(license.ValidUntil == -1 || license.ValidUntil > time.Now().Unix()) {
|
||||||
@ -383,7 +380,4 @@ type Store interface {
|
|||||||
GetFeature(context.Context, string) (*featuretypes.StorableFeature, error)
|
GetFeature(context.Context, string) (*featuretypes.StorableFeature, error)
|
||||||
GetAllFeatures(context.Context) ([]*featuretypes.StorableFeature, error)
|
GetAllFeatures(context.Context) ([]*featuretypes.StorableFeature, error)
|
||||||
UpdateFeature(context.Context, *featuretypes.StorableFeature) error
|
UpdateFeature(context.Context, *featuretypes.StorableFeature) error
|
||||||
|
|
||||||
// ListOrganizations returns the list of orgs
|
|
||||||
ListOrganizations(context.Context) ([]valuer.UUID, error)
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"hash/fnv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SigNoz/signoz/pkg/errors"
|
"github.com/SigNoz/signoz/pkg/errors"
|
||||||
@ -20,13 +21,15 @@ type Organization struct {
|
|||||||
Identifiable
|
Identifiable
|
||||||
Name string `bun:"name,type:text,nullzero" json:"name"`
|
Name string `bun:"name,type:text,nullzero" json:"name"`
|
||||||
Alias string `bun:"alias,type:text,nullzero" json:"alias"`
|
Alias string `bun:"alias,type:text,nullzero" json:"alias"`
|
||||||
|
Key uint32 `bun:"key,type:bigint,notnull" json:"key"`
|
||||||
DisplayName string `bun:"display_name,type:text,notnull" json:"displayName"`
|
DisplayName string `bun:"display_name,type:text,notnull" json:"displayName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOrganization(displayName string) *Organization {
|
func NewOrganization(displayName string) *Organization {
|
||||||
|
id := valuer.GenerateUUID()
|
||||||
return &Organization{
|
return &Organization{
|
||||||
Identifiable: Identifiable{
|
Identifiable: Identifiable{
|
||||||
ID: valuer.GenerateUUID(),
|
ID: id,
|
||||||
},
|
},
|
||||||
TimeAuditable: TimeAuditable{
|
TimeAuditable: TimeAuditable{
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
@ -34,22 +37,23 @@ func NewOrganization(displayName string) *Organization {
|
|||||||
},
|
},
|
||||||
// Name: "default/main", TODO: take the call and uncomment this later
|
// Name: "default/main", TODO: take the call and uncomment this later
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
|
Key: NewOrganizationKey(id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApdexSettings struct {
|
func NewOrganizationKey(orgID valuer.UUID) uint32 {
|
||||||
bun.BaseModel `bun:"table:apdex_setting"`
|
hasher := fnv.New32a()
|
||||||
Identifiable
|
|
||||||
OrgID string `bun:"org_id,type:text" json:"orgId"`
|
// Hasher never returns err.
|
||||||
ServiceName string `bun:"service_name,type:text" json:"serviceName"`
|
_, _ = hasher.Write([]byte(orgID.String()))
|
||||||
Threshold float64 `bun:"threshold,type:float,notnull" json:"threshold"`
|
return hasher.Sum32()
|
||||||
ExcludeStatusCodes string `bun:"exclude_status_codes,type:text,notnull" json:"excludeStatusCodes"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type OrganizationStore interface {
|
type OrganizationStore interface {
|
||||||
Create(context.Context, *Organization) error
|
Create(context.Context, *Organization) error
|
||||||
Get(context.Context, valuer.UUID) (*Organization, error)
|
Get(context.Context, valuer.UUID) (*Organization, error)
|
||||||
GetAll(context.Context) ([]*Organization, error)
|
GetAll(context.Context) ([]*Organization, error)
|
||||||
|
ListByKeyRange(context.Context, uint32, uint32) ([]*Organization, error)
|
||||||
Update(context.Context, *Organization) error
|
Update(context.Context, *Organization) error
|
||||||
Delete(context.Context, valuer.UUID) error
|
Delete(context.Context, valuer.UUID) error
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user