mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 04:04:00 -06:00
Alerting: Fix stats that display alert count when using unified alerting (#64852)
* Alerting: Fix stats when using unified alerting
This commit is contained in:
parent
f4c62a5c5d
commit
02a8f62021
@ -13,12 +13,13 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/services/stats/statsimpl"
|
"github.com/grafana/grafana/pkg/services/stats/statsimpl"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConcurrentUsersMetrics(t *testing.T) {
|
func TestConcurrentUsersMetrics(t *testing.T) {
|
||||||
sqlStore, cfg := db.InitTestDBwithCfg(t)
|
sqlStore, cfg := db.InitTestDBwithCfg(t)
|
||||||
statsService := statsimpl.ProvideService(sqlStore)
|
statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore)
|
||||||
s := createService(t, cfg, sqlStore, statsService)
|
s := createService(t, cfg, sqlStore, statsService)
|
||||||
|
|
||||||
createConcurrentTokens(t, sqlStore)
|
createConcurrentTokens(t, sqlStore)
|
||||||
@ -36,7 +37,7 @@ func TestConcurrentUsersMetrics(t *testing.T) {
|
|||||||
|
|
||||||
func TestConcurrentUsersStats(t *testing.T) {
|
func TestConcurrentUsersStats(t *testing.T) {
|
||||||
sqlStore, cfg := db.InitTestDBwithCfg(t)
|
sqlStore, cfg := db.InitTestDBwithCfg(t)
|
||||||
statsService := statsimpl.ProvideService(sqlStore)
|
statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore)
|
||||||
s := createService(t, cfg, sqlStore, statsService)
|
s := createService(t, cfg, sqlStore, statsService)
|
||||||
|
|
||||||
createConcurrentTokens(t, sqlStore)
|
createConcurrentTokens(t, sqlStore)
|
||||||
|
@ -338,7 +338,7 @@ func (ng *AlertNG) Run(ctx context.Context) error {
|
|||||||
return children.Wait()
|
return children.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisabled returns true if the alerting service is disable for this instance.
|
// IsDisabled returns true if the alerting service is disabled for this instance.
|
||||||
func (ng *AlertNG) IsDisabled() bool {
|
func (ng *AlertNG) IsDisabled() bool {
|
||||||
if ng.Cfg == nil {
|
if ng.Cfg == nil {
|
||||||
return true
|
return true
|
||||||
|
@ -2,6 +2,7 @@ package statsimpl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -11,16 +12,20 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
"github.com/grafana/grafana/pkg/services/stats"
|
"github.com/grafana/grafana/pkg/services/stats"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
const activeUserTimeLimit = time.Hour * 24 * 30
|
const activeUserTimeLimit = time.Hour * 24 * 30
|
||||||
const dailyActiveUserTimeLimit = time.Hour * 24
|
const dailyActiveUserTimeLimit = time.Hour * 24
|
||||||
|
|
||||||
func ProvideService(db db.DB) stats.Service {
|
func ProvideService(cfg *setting.Cfg, db db.DB) stats.Service {
|
||||||
return &sqlStatsService{db: db}
|
return &sqlStatsService{cfg: cfg, db: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
type sqlStatsService struct{ db db.DB }
|
type sqlStatsService struct {
|
||||||
|
db db.DB
|
||||||
|
cfg *setting.Cfg
|
||||||
|
}
|
||||||
|
|
||||||
func (ss *sqlStatsService) GetAlertNotifiersUsageStats(ctx context.Context, query *stats.GetAlertNotifierUsageStatsQuery) error {
|
func (ss *sqlStatsService) GetAlertNotifiersUsageStats(ctx context.Context, query *stats.GetAlertNotifierUsageStatsQuery) error {
|
||||||
return ss.db.WithDbSession(ctx, func(dbSession *db.Session) error {
|
return ss.db.WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||||
@ -173,6 +178,11 @@ func (ss *sqlStatsService) GetAdminStats(ctx context.Context, query *stats.GetAd
|
|||||||
dailyActiveEndDate := now.Add(-dailyActiveUserTimeLimit)
|
dailyActiveEndDate := now.Add(-dailyActiveUserTimeLimit)
|
||||||
monthlyActiveEndDate := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
monthlyActiveEndDate := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
||||||
|
|
||||||
|
alertsQuery := fmt.Sprintf("SELECT COUNT(*) FROM %s", dialect.Quote("alert"))
|
||||||
|
if ss.IsUnifiedAlertingEnabled() {
|
||||||
|
alertsQuery = fmt.Sprintf("SELECT COUNT(*) FROM %s", dialect.Quote("alert_rule"))
|
||||||
|
}
|
||||||
|
|
||||||
var rawSQL = `SELECT
|
var rawSQL = `SELECT
|
||||||
(
|
(
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
@ -202,10 +212,7 @@ func (ss *sqlStatsService) GetAdminStats(ctx context.Context, query *stats.GetAd
|
|||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM ` + dialect.Quote("star") + `
|
FROM ` + dialect.Quote("star") + `
|
||||||
) AS stars,
|
) AS stars,
|
||||||
(
|
(` + alertsQuery + ` ) AS alerts,
|
||||||
SELECT COUNT(*)
|
|
||||||
FROM ` + dialect.Quote("alert") + `
|
|
||||||
) AS alerts,
|
|
||||||
(
|
(
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM ` + dialect.Quote("user") + ` WHERE ` + notServiceAccount(dialect) + `
|
FROM ` + dialect.Quote("user") + ` WHERE ` + notServiceAccount(dialect) + `
|
||||||
@ -258,6 +265,10 @@ func (ss *sqlStatsService) GetSystemUserCountStats(ctx context.Context, query *s
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ss *sqlStatsService) IsUnifiedAlertingEnabled() bool {
|
||||||
|
return ss.cfg != nil && ss.cfg.UnifiedAlerting.IsEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
func (ss *sqlStatsService) updateUserRoleCountsIfNecessary(ctx context.Context, forced bool) error {
|
func (ss *sqlStatsService) updateUserRoleCountsIfNecessary(ctx context.Context, forced bool) error {
|
||||||
memoizationPeriod := time.Now().Add(-userStatsCacheLimetime)
|
memoizationPeriod := time.Now().Add(-userStatsCacheLimetime)
|
||||||
if forced || userStatsCache.memoized.Before(memoizationPeriod) {
|
if forced || userStatsCache.memoized.Before(memoizationPeriod) {
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
|
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/services/user/userimpl"
|
"github.com/grafana/grafana/pkg/services/user/userimpl"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIntegrationStatsDataAccess(t *testing.T) {
|
func TestIntegrationStatsDataAccess(t *testing.T) {
|
||||||
@ -122,7 +123,7 @@ func TestIntegration_GetAdminStats(t *testing.T) {
|
|||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
db := sqlstore.InitTestDB(t)
|
db := sqlstore.InitTestDB(t)
|
||||||
statsService := ProvideService(db)
|
statsService := ProvideService(&setting.Cfg{}, db)
|
||||||
|
|
||||||
query := stats.GetAdminStatsQuery{}
|
query := stats.GetAdminStatsQuery{}
|
||||||
err := statsService.GetAdminStats(context.Background(), &query)
|
err := statsService.GetAdminStats(context.Background(), &query)
|
||||||
|
92
pkg/tests/api/stats/admin_test.go
Normal file
92
pkg/tests/api/stats/admin_test.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||||
|
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
|
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
|
||||||
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
|
"github.com/grafana/grafana/pkg/services/user/userimpl"
|
||||||
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIntegrationAdminStats(t *testing.T) {
|
||||||
|
t.Run("with unified alerting enabled", func(t *testing.T) {
|
||||||
|
url := grafanaSetup(t, testinfra.GrafanaOpts{
|
||||||
|
DisableLegacyAlerting: true,
|
||||||
|
EnableUnifiedAlerting: true,
|
||||||
|
AppModeProduction: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// nolint:gosec
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
defer func() {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
}()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("with legacy alerting enabled", func(t *testing.T) {
|
||||||
|
url := grafanaSetup(t, testinfra.GrafanaOpts{
|
||||||
|
DisableLegacyAlerting: false,
|
||||||
|
EnableUnifiedAlerting: false,
|
||||||
|
AppModeProduction: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// nolint:gosec
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
defer func() {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
}()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// grafanaSetup creates the grafana server, user and returns the URL with credentials of the api/admin/stats endpoint.
|
||||||
|
func grafanaSetup(t *testing.T, opts testinfra.GrafanaOpts) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
testinfra.SQLiteIntegrationTest(t)
|
||||||
|
|
||||||
|
// Setup Grafana and its Database
|
||||||
|
dir, path := testinfra.CreateGrafDir(t, opts)
|
||||||
|
|
||||||
|
grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path)
|
||||||
|
|
||||||
|
// Create a user to make authenticated requests
|
||||||
|
createUser(t, store, user.CreateUserCommand{
|
||||||
|
DefaultOrgRole: string(org.RoleAdmin),
|
||||||
|
Login: "grafana",
|
||||||
|
Password: "password",
|
||||||
|
IsAdmin: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return fmt.Sprintf("http://%s:%s@%s/api/admin/stats", "grafana", "password", grafanaListedAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createUser(t *testing.T, store *sqlstore.SQLStore, cmd user.CreateUserCommand) int64 {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
store.Cfg.AutoAssignOrg = true
|
||||||
|
store.Cfg.AutoAssignOrgId = 1
|
||||||
|
|
||||||
|
quotaService := quotaimpl.ProvideService(store, store.Cfg)
|
||||||
|
orgService, err := orgimpl.ProvideService(store, store.Cfg, quotaService)
|
||||||
|
require.NoError(t, err)
|
||||||
|
usrSvc, err := userimpl.ProvideService(store, orgService, store.Cfg, nil, nil, quotaService, supportbundlestest.NewFakeBundleService())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
u, err := usrSvc.Create(context.Background(), &cmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return u.ID
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user