add daily active counts to stats (#38842)

* add daily active counts to stats

* standardize on int64, update tests
This commit is contained in:
Dan Cech 2021-09-13 10:29:35 -04:00 committed by GitHub
parent baff8fe39d
commit 9dfd469afc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 36 deletions

View File

@ -52,6 +52,9 @@ func (uss *UsageStatsService) GetUsageReport(ctx context.Context) (UsageReport,
metrics["stats.dashboards.count"] = statsQuery.Result.Dashboards
metrics["stats.users.count"] = statsQuery.Result.Users
metrics["stats.admins.count"] = statsQuery.Result.Admins
metrics["stats.editors.count"] = statsQuery.Result.Editors
metrics["stats.viewers.count"] = statsQuery.Result.Viewers
metrics["stats.orgs.count"] = statsQuery.Result.Orgs
metrics["stats.playlist.count"] = statsQuery.Result.Playlists
metrics["stats.plugins.apps.count"] = uss.PluginManager.AppCount()
@ -59,6 +62,15 @@ func (uss *UsageStatsService) GetUsageReport(ctx context.Context) (UsageReport,
metrics["stats.plugins.datasources.count"] = uss.PluginManager.DataSourceCount()
metrics["stats.alerts.count"] = statsQuery.Result.Alerts
metrics["stats.active_users.count"] = statsQuery.Result.ActiveUsers
metrics["stats.active_admins.count"] = statsQuery.Result.ActiveAdmins
metrics["stats.active_editors.count"] = statsQuery.Result.ActiveEditors
metrics["stats.active_viewers.count"] = statsQuery.Result.ActiveViewers
metrics["stats.active_sessions.count"] = statsQuery.Result.ActiveSessions
metrics["stats.daily_active_users.count"] = statsQuery.Result.DailyActiveUsers
metrics["stats.daily_active_admins.count"] = statsQuery.Result.DailyActiveAdmins
metrics["stats.daily_active_editors.count"] = statsQuery.Result.DailyActiveEditors
metrics["stats.daily_active_viewers.count"] = statsQuery.Result.DailyActiveViewers
metrics["stats.daily_active_sessions.count"] = statsQuery.Result.DailyActiveSessions
metrics["stats.datasources.count"] = statsQuery.Result.Datasources
metrics["stats.stars.count"] = statsQuery.Result.Stars
metrics["stats.folders.count"] = statsQuery.Result.Folders

View File

@ -47,7 +47,19 @@ func TestMetrics(t *testing.T) {
Dashboards: 1,
Datasources: 2,
Users: 3,
Admins: 31,
Editors: 32,
Viewers: 33,
ActiveUsers: 4,
ActiveAdmins: 21,
ActiveEditors: 22,
ActiveViewers: 23,
ActiveSessions: 24,
DailyActiveUsers: 25,
DailyActiveAdmins: 26,
DailyActiveEditors: 27,
DailyActiveViewers: 28,
DailyActiveSessions: 29,
Orgs: 5,
Playlists: 6,
Alerts: 7,
@ -298,6 +310,9 @@ func TestMetrics(t *testing.T) {
metrics := j.Get("metrics")
assert.Equal(t, getSystemStatsQuery.Result.Dashboards, metrics.Get("stats.dashboards.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.Users, metrics.Get("stats.users.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.Admins, metrics.Get("stats.admins.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.Editors, metrics.Get("stats.editors.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.Viewers, metrics.Get("stats.viewers.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.Orgs, metrics.Get("stats.orgs.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.Playlists, metrics.Get("stats.playlist.count").MustInt64())
assert.Equal(t, uss.PluginManager.AppCount(), metrics.Get("stats.plugins.apps.count").MustInt())
@ -305,6 +320,15 @@ func TestMetrics(t *testing.T) {
assert.Equal(t, uss.PluginManager.DataSourceCount(), metrics.Get("stats.plugins.datasources.count").MustInt())
assert.Equal(t, getSystemStatsQuery.Result.Alerts, metrics.Get("stats.alerts.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.ActiveUsers, metrics.Get("stats.active_users.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.ActiveAdmins, metrics.Get("stats.active_admins.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.ActiveEditors, metrics.Get("stats.active_editors.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.ActiveViewers, metrics.Get("stats.active_viewers.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.ActiveSessions, metrics.Get("stats.active_sessions.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.DailyActiveUsers, metrics.Get("stats.daily_active_users.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.DailyActiveAdmins, metrics.Get("stats.daily_active_admins.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.DailyActiveEditors, metrics.Get("stats.daily_active_editors.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.DailyActiveViewers, metrics.Get("stats.daily_active_viewers.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.DailyActiveSessions, metrics.Get("stats.daily_active_sessions.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.Datasources, metrics.Get("stats.datasources.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.Stars, metrics.Get("stats.stars.count").MustInt64())
assert.Equal(t, getSystemStatsQuery.Result.Folders, metrics.Get("stats.folders.count").MustInt64())

View File

@ -5,6 +5,7 @@ type SystemStats struct {
Datasources int64
Users int64
ActiveUsers int64
DailyActiveUsers int64
Orgs int64
Playlists int64
Alerts int64
@ -25,14 +26,17 @@ type SystemStats struct {
DashboardsViewersCanAdmin int64
FoldersViewersCanEdit int64
FoldersViewersCanAdmin int64
Admins int
Editors int
Viewers int
ActiveAdmins int
ActiveEditors int
ActiveViewers int
ActiveSessions int
Admins int64
Editors int64
Viewers int64
ActiveAdmins int64
ActiveEditors int64
ActiveViewers int64
ActiveSessions int64
DailyActiveAdmins int64
DailyActiveEditors int64
DailyActiveViewers int64
DailyActiveSessions int64
}
type DataSourceStats struct {
@ -68,23 +72,28 @@ type GetAlertNotifierUsageStatsQuery struct {
}
type AdminStats struct {
Orgs int `json:"orgs"`
Dashboards int `json:"dashboards"`
Snapshots int `json:"snapshots"`
Tags int `json:"tags"`
Datasources int `json:"datasources"`
Playlists int `json:"playlists"`
Stars int `json:"stars"`
Alerts int `json:"alerts"`
Users int `json:"users"`
Admins int `json:"admins"`
Editors int `json:"editors"`
Viewers int `json:"viewers"`
ActiveUsers int `json:"activeUsers"`
ActiveAdmins int `json:"activeAdmins"`
ActiveEditors int `json:"activeEditors"`
ActiveViewers int `json:"activeViewers"`
ActiveSessions int `json:"activeSessions"`
Orgs int64 `json:"orgs"`
Dashboards int64 `json:"dashboards"`
Snapshots int64 `json:"snapshots"`
Tags int64 `json:"tags"`
Datasources int64 `json:"datasources"`
Playlists int64 `json:"playlists"`
Stars int64 `json:"stars"`
Alerts int64 `json:"alerts"`
Users int64 `json:"users"`
Admins int64 `json:"admins"`
Editors int64 `json:"editors"`
Viewers int64 `json:"viewers"`
ActiveUsers int64 `json:"activeUsers"`
ActiveAdmins int64 `json:"activeAdmins"`
ActiveEditors int64 `json:"activeEditors"`
ActiveViewers int64 `json:"activeViewers"`
ActiveSessions int64 `json:"activeSessions"`
DailyActiveUsers int64 `json:"dailyActiveUsers"`
DailyActiveAdmins int64 `json:"dailyActiveAdmins"`
DailyActiveEditors int64 `json:"dailyActiveEditors"`
DailyActiveViewers int64 `json:"dailyActiveViewers"`
DailyActiveSessions int64 `json:"dailyActiveSessions"`
}
type GetAdminStatsQuery struct {

View File

@ -19,6 +19,7 @@ func init() {
}
const activeUserTimeLimit = time.Hour * 24 * 30
const dailyActiveUserTimeLimit = time.Hour * 24
func GetAlertNotifiersUsageStats(ctx context.Context, query *models.GetAlertNotifierUsageStatsQuery) error {
var rawSQL = `SELECT COUNT(*) AS count, type FROM ` + dialect.Quote("alert_notification") + ` GROUP BY type`
@ -54,6 +55,9 @@ func GetSystemStats(query *models.GetSystemStatsQuery) error {
activeUserDeadlineDate := time.Now().Add(-activeUserTimeLimit)
sb.Write(`(SELECT COUNT(*) FROM `+dialect.Quote("user")+` WHERE last_seen_at > ?) AS active_users,`, activeUserDeadlineDate)
dailyActiveUserDeadlineDate := time.Now().Add(-dailyActiveUserTimeLimit)
sb.Write(`(SELECT COUNT(*) FROM `+dialect.Quote("user")+` WHERE last_seen_at > ?) AS daily_active_users,`, dailyActiveUserDeadlineDate)
sb.Write(`(SELECT COUNT(id) FROM `+dialect.Quote("dashboard")+` WHERE is_folder = ?) AS dashboards,`, dialect.BooleanStr(false))
sb.Write(`(SELECT COUNT(id) FROM `+dialect.Quote("dashboard")+` WHERE is_folder = ?) AS folders,`, dialect.BooleanStr(true))
@ -112,7 +116,10 @@ func roleCounterSQL() string {
strconv.FormatInt(userStatsCache.total.Viewers, 10) + ` AS viewers, ` +
strconv.FormatInt(userStatsCache.active.Admins, 10) + ` AS active_admins, ` +
strconv.FormatInt(userStatsCache.active.Editors, 10) + ` AS active_editors, ` +
strconv.FormatInt(userStatsCache.active.Viewers, 10) + ` AS active_viewers`
strconv.FormatInt(userStatsCache.active.Viewers, 10) + ` AS active_viewers, ` +
strconv.FormatInt(userStatsCache.dailyActive.Admins, 10) + ` AS daily_active_admins, ` +
strconv.FormatInt(userStatsCache.dailyActive.Editors, 10) + ` AS daily_active_editors, ` +
strconv.FormatInt(userStatsCache.dailyActive.Viewers, 10) + ` AS daily_active_viewers`
return sqlQuery
}
@ -131,6 +138,7 @@ func viewersPermissionsCounterSQL(statName string, isFolder bool, permission mod
func GetAdminStats(query *models.GetAdminStatsQuery) error {
activeEndDate := time.Now().Add(-activeUserTimeLimit)
dailyActiveEndDate := time.Now().Add(-dailyActiveUserTimeLimit)
var rawSQL = `SELECT
(
@ -173,14 +181,22 @@ func GetAdminStats(query *models.GetAdminStatsQuery) error {
SELECT COUNT(*)
FROM ` + dialect.Quote("user") + ` WHERE last_seen_at > ?
) AS active_users,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("user") + ` WHERE last_seen_at > ?
) AS daily_active_users,
` + roleCounterSQL() + `,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("user_auth_token") + ` WHERE rotated_at > ?
) AS active_sessions`
) AS active_sessions,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("user_auth_token") + ` WHERE rotated_at > ?
) AS daily_active_sessions`
var stats models.AdminStats
_, err := x.SQL(rawSQL, activeEndDate, activeEndDate.Unix()).Get(&stats)
_, err := x.SQL(rawSQL, activeEndDate, dailyActiveEndDate, activeEndDate.Unix(), dailyActiveEndDate.Unix()).Get(&stats)
if err != nil {
return err
}
@ -216,8 +232,9 @@ func updateUserRoleCountsIfNecessary(ctx context.Context, forced bool) error {
}
type memoUserStats struct {
active models.UserStats
total models.UserStats
active models.UserStats
dailyActive models.UserStats
total models.UserStats
memoized time.Time
}
@ -230,7 +247,7 @@ var (
func updateUserRoleCounts(ctx context.Context) error {
query := `
SELECT role AS bitrole, active, COUNT(role) AS count FROM
(SELECT last_seen_at>? AS active, SUM(role) AS role
(SELECT last_seen_at>? AS active, last_seen_at>? AS daily_active, SUM(role) AS role
FROM (SELECT
u.id,
CASE org_user.role
@ -242,18 +259,20 @@ SELECT role AS bitrole, active, COUNT(role) AS count FROM
FROM ` + dialect.Quote("user") + ` AS u INNER JOIN org_user ON org_user.user_id = u.id
GROUP BY u.id, u.last_seen_at, org_user.role) AS t2
GROUP BY id, last_seen_at) AS t1
GROUP BY active, role;`
GROUP BY active, daily_active, role;`
activeUserDeadline := time.Now().Add(-activeUserTimeLimit)
dailyActiveUserDeadline := time.Now().Add(-dailyActiveUserTimeLimit)
type rolebitmap struct {
Active bool
Bitrole int64
Count int64
Active bool
DailyActive bool
Bitrole int64
Count int64
}
bitmap := []rolebitmap{}
err := x.Context(ctx).SQL(query, activeUserDeadline).Find(&bitmap)
err := x.Context(ctx).SQL(query, activeUserDeadline, dailyActiveUserDeadline).Find(&bitmap)
if err != nil {
return err
}
@ -271,6 +290,9 @@ GROUP BY active, role;`
if role.Active {
memo.active = addToStats(memo.active, roletype, role.Count)
}
if role.DailyActive {
memo.dailyActive = addToStats(memo.dailyActive, roletype, role.Count)
}
}
userStatsCache = memo