From c260c319eede99513e234f0e16391706e51f1552 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Thu, 21 Jan 2016 01:48:29 -0800 Subject: [PATCH 01/18] Started Grafana stats poc --- .../app/core/components/sidemenu/sidemenu.ts | 7 +++ public/app/core/routes/all.js | 4 ++ public/app/features/admin/adminStatsCtrl.js | 24 +++++++++ public/app/features/admin/all.js | 1 + public/app/features/admin/partials/stats.html | 53 +++++++++++++++++++ 5 files changed, 89 insertions(+) create mode 100644 public/app/features/admin/adminStatsCtrl.js create mode 100644 public/app/features/admin/partials/stats.html diff --git a/public/app/core/components/sidemenu/sidemenu.ts b/public/app/core/components/sidemenu/sidemenu.ts index d2a640c1345..8f0c57bfade 100644 --- a/public/app/core/components/sidemenu/sidemenu.ts +++ b/public/app/core/components/sidemenu/sidemenu.ts @@ -107,6 +107,12 @@ export class SideMenuCtrl { url: this.getUrl("/admin/settings"), }); + this.mainLinks.push({ + text: "Grafana stats", + icon: "fa fa-fw fa-bar-chart", + url: this.getUrl("/admin/stats"), + }); + this.mainLinks.push({ text: "Global Users", icon: "fa fa-fw fa-user", @@ -118,6 +124,7 @@ export class SideMenuCtrl { icon: "fa fa-fw fa-users", url: this.getUrl("/admin/orgs"), }); + } updateMenu() { diff --git a/public/app/core/routes/all.js b/public/app/core/routes/all.js index cc4d73ef708..bc71a63a094 100644 --- a/public/app/core/routes/all.js +++ b/public/app/core/routes/all.js @@ -112,6 +112,10 @@ define([ templateUrl: 'app/features/admin/partials/edit_org.html', controller : 'AdminEditOrgCtrl', }) + .when('/admin/stats', { + templateUrl: 'app/features/admin/partials/stats.html', + controller : 'AdminStatsCtrl', + }) .when('/login', { templateUrl: 'app/partials/login.html', controller : 'LoginCtrl', diff --git a/public/app/features/admin/adminStatsCtrl.js b/public/app/features/admin/adminStatsCtrl.js new file mode 100644 index 00000000000..94b40b59591 --- /dev/null +++ b/public/app/features/admin/adminStatsCtrl.js @@ -0,0 +1,24 @@ +define([ + 'angular', +], +function (angular) { + 'use strict'; + + var module = angular.module('grafana.controllers'); + + module.controller('AdminStatsCtrl', function($scope) { + + $scope.init = function() { + $scope.getStats(); + }; + + $scope.getStats = function() { +// backendSrv.get('/api/admin/stats').then(function(stats) { +// $scope.stats = stats; +// }); + }; + + $scope.init(); + + }); +}); diff --git a/public/app/features/admin/all.js b/public/app/features/admin/all.js index 14bff249b0e..786210f064f 100644 --- a/public/app/features/admin/all.js +++ b/public/app/features/admin/all.js @@ -4,4 +4,5 @@ define([ './adminEditOrgCtrl', './adminEditUserCtrl', './adminSettingsCtrl', + './adminStatsCtrl', ], function () {}); diff --git a/public/app/features/admin/partials/stats.html b/public/app/features/admin/partials/stats.html new file mode 100644 index 00000000000..048be83c83e --- /dev/null +++ b/public/app/features/admin/partials/stats.html @@ -0,0 +1,53 @@ + + + +
+
+

+ Stats +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameValue
Total dashboards213
Total users97
Total organizations4
Total playlists12
Total snapshots64
Total dashboard tags15
Total starred dashboards131
Total panels2739
+
+
From c7fae5386daf060d848bc840a33cbe60aef1457d Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Sun, 24 Jan 2016 11:01:33 -0800 Subject: [PATCH 02/18] Added backend API for stats --- pkg/api/{admin_settings.go => admin.go} | 14 ++++++++ pkg/api/api.go | 2 ++ pkg/models/stats.go | 15 ++++++++ pkg/services/sqlstore/stats.go | 47 +++++++++++++++++++++++++ 4 files changed, 78 insertions(+) rename pkg/api/{admin_settings.go => admin.go} (65%) diff --git a/pkg/api/admin_settings.go b/pkg/api/admin.go similarity index 65% rename from pkg/api/admin_settings.go rename to pkg/api/admin.go index 1f800cfe558..1264cfa12eb 100644 --- a/pkg/api/admin_settings.go +++ b/pkg/api/admin.go @@ -5,6 +5,8 @@ import ( "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" ) func AdminGetSettings(c *middleware.Context) { @@ -27,3 +29,15 @@ func AdminGetSettings(c *middleware.Context) { c.JSON(200, settings) } + +func AdminGetStats(c *middleware.Context) { + + statsQuery := m.GetAdminStatsQuery{} + + if err := bus.Dispatch(&statsQuery); err != nil { + c.JsonApiErr(500, "Failed to get admin stats from database", err) + return + } + + c.JSON(200, statsQuery.Result) +} diff --git a/pkg/api/api.go b/pkg/api/api.go index ea434ed71da..7a4fc684497 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -40,6 +40,7 @@ func Register(r *macaron.Macaron) { r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index) r.Get("/admin/orgs", reqGrafanaAdmin, Index) r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index) + r.Get("/admin/stats", reqGrafanaAdmin, Index) r.Get("/apps", reqSignedIn, Index) r.Get("/apps/edit/*", reqSignedIn, Index) @@ -210,6 +211,7 @@ func Register(r *macaron.Macaron) { r.Delete("/users/:id", AdminDeleteUser) r.Get("/users/:id/quotas", wrap(GetUserQuotas)) r.Put("/users/:id/quotas/:target", bind(m.UpdateUserQuotaCmd{}), wrap(UpdateUserQuota)) + r.Get("/stats", AdminGetStats) }, reqGrafanaAdmin) // rendering diff --git a/pkg/models/stats.go b/pkg/models/stats.go index 6a060137ac7..8fd7614ffd2 100644 --- a/pkg/models/stats.go +++ b/pkg/models/stats.go @@ -18,3 +18,18 @@ type GetSystemStatsQuery struct { type GetDataSourceStatsQuery struct { Result []*DataSourceStats } + +type AdminStats struct { + UserCount int + OrgCount int + DashboardCount int + DBSnapshotCount int + DBTagCount int + DataSourceCount int + PlaylistCount int + StarredDBCount int +} + +type GetAdminStatsQuery struct { + Result *AdminStats +} diff --git a/pkg/services/sqlstore/stats.go b/pkg/services/sqlstore/stats.go index 044aa185f19..c57128bc76a 100644 --- a/pkg/services/sqlstore/stats.go +++ b/pkg/services/sqlstore/stats.go @@ -8,6 +8,7 @@ import ( func init() { bus.AddHandler("sql", GetSystemStats) bus.AddHandler("sql", GetDataSourceStats) + bus.AddHandler("sql", GetAdminStats) } func GetDataSourceStats(query *m.GetDataSourceStatsQuery) error { @@ -46,3 +47,49 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error { query.Result = &stats return err } + +func GetAdminStats(query *m.GetAdminStatsQuery) error { + var rawSql = `SELECT + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("user") + ` + ) AS user_count, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("org") + ` + ) AS org_count, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("dashboard") + ` + ) AS dashboard_count, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("dashboard_snapshot") + ` + ) AS db_snapshot_count, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("dashboard_tag") + ` + ) AS db_tag_count, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("data_source") + ` + ) AS datasource_count, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("playlist") + ` + ) AS playlist_count, + ( + SELECT DISTINCT(dashboard_id) + FROM ` + dialect.Quote("star") + ` + ) AS starred_db_count + ` + + var stats m.AdminStats + _, err := x.Sql(rawSql).Get(&stats) + if err != nil { + return err + } + + query.Result = &stats + return err +} From da67afa51ede6e72ac61f7e499d0a704390c11cb Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Sun, 24 Jan 2016 21:18:17 -0800 Subject: [PATCH 03/18] Fixed api bugs, stats endpoint working --- pkg/api/admin.go | 18 +++++++++--------- pkg/api/api.go | 4 ++-- pkg/models/stats.go | 18 +++++++++--------- pkg/services/sqlstore/stats.go | 22 +++++++++++----------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/pkg/api/admin.go b/pkg/api/admin.go index 1264cfa12eb..d7f5a240416 100644 --- a/pkg/api/admin.go +++ b/pkg/api/admin.go @@ -3,10 +3,10 @@ package api import ( "strings" + "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/bus" - m "github.com/grafana/grafana/pkg/models" ) func AdminGetSettings(c *middleware.Context) { @@ -32,12 +32,12 @@ func AdminGetSettings(c *middleware.Context) { func AdminGetStats(c *middleware.Context) { - statsQuery := m.GetAdminStatsQuery{} - - if err := bus.Dispatch(&statsQuery); err != nil { - c.JsonApiErr(500, "Failed to get admin stats from database", err) - return - } + statsQuery := m.GetAdminStatsQuery{} - c.JSON(200, statsQuery.Result) + if err := bus.Dispatch(&statsQuery); err != nil { + c.JsonApiErr(500, "Failed to get admin stats from database", err) + return + } + + c.JSON(200, statsQuery.Result) } diff --git a/pkg/api/api.go b/pkg/api/api.go index 7a4fc684497..32ccd5dc793 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -40,7 +40,7 @@ func Register(r *macaron.Macaron) { r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index) r.Get("/admin/orgs", reqGrafanaAdmin, Index) r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index) - r.Get("/admin/stats", reqGrafanaAdmin, Index) + r.Get("/admin/stats", reqGrafanaAdmin, Index) r.Get("/apps", reqSignedIn, Index) r.Get("/apps/edit/*", reqSignedIn, Index) @@ -211,7 +211,7 @@ func Register(r *macaron.Macaron) { r.Delete("/users/:id", AdminDeleteUser) r.Get("/users/:id/quotas", wrap(GetUserQuotas)) r.Put("/users/:id/quotas/:target", bind(m.UpdateUserQuotaCmd{}), wrap(UpdateUserQuota)) - r.Get("/stats", AdminGetStats) + r.Get("/stats", AdminGetStats) }, reqGrafanaAdmin) // rendering diff --git a/pkg/models/stats.go b/pkg/models/stats.go index 8fd7614ffd2..6d8618d6ddf 100644 --- a/pkg/models/stats.go +++ b/pkg/models/stats.go @@ -20,16 +20,16 @@ type GetDataSourceStatsQuery struct { } type AdminStats struct { - UserCount int - OrgCount int - DashboardCount int - DBSnapshotCount int - DBTagCount int - DataSourceCount int - PlaylistCount int - StarredDBCount int + UserCount int `json:"user_count"` + OrgCount int `json:"org_count"` + DashboardCount int `json:"dashboard_count"` + DbSnapshotCount int `json:"db_snapshot_count"` + DbTagCount int `json:"db_tag_count"` + DataSourceCount int `json:"data_source_count"` + PlaylistCount int `json:"playlist_count"` + StarredDbCount int `json:"starred_db_count"` } type GetAdminStatsQuery struct { - Result *AdminStats + Result *AdminStats } diff --git a/pkg/services/sqlstore/stats.go b/pkg/services/sqlstore/stats.go index c57128bc76a..3c9325fa149 100644 --- a/pkg/services/sqlstore/stats.go +++ b/pkg/services/sqlstore/stats.go @@ -8,7 +8,7 @@ import ( func init() { bus.AddHandler("sql", GetSystemStats) bus.AddHandler("sql", GetDataSourceStats) - bus.AddHandler("sql", GetAdminStats) + bus.AddHandler("sql", GetAdminStats) } func GetDataSourceStats(query *m.GetDataSourceStatsQuery) error { @@ -49,7 +49,7 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error { } func GetAdminStats(query *m.GetAdminStatsQuery) error { - var rawSql = `SELECT + var rawSql = `SELECT ( SELECT COUNT(*) FROM ` + dialect.Quote("user") + ` @@ -73,23 +73,23 @@ func GetAdminStats(query *m.GetAdminStatsQuery) error { ( SELECT COUNT(*) FROM ` + dialect.Quote("data_source") + ` - ) AS datasource_count, + ) AS data_source_count, ( SELECT COUNT(*) FROM ` + dialect.Quote("playlist") + ` ) AS playlist_count, ( - SELECT DISTINCT(dashboard_id) + SELECT COUNT (DISTINCT ` + dialect.Quote("dashboard_id") + ` ) FROM ` + dialect.Quote("star") + ` ) AS starred_db_count ` - var stats m.AdminStats - _, err := x.Sql(rawSql).Get(&stats) - if err != nil { - return err - } + var stats m.AdminStats + _, err := x.Sql(rawSql).Get(&stats) + if err != nil { + return err + } - query.Result = &stats - return err + query.Result = &stats + return err } From 4c12703e0c756af1b9ec00ac8da1f4d23f11e11c Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Sun, 24 Jan 2016 21:39:30 -0800 Subject: [PATCH 04/18] Integrated angularjs with go api --- public/app/features/admin/adminStatsCtrl.js | 8 +++---- public/app/features/admin/partials/stats.html | 22 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/public/app/features/admin/adminStatsCtrl.js b/public/app/features/admin/adminStatsCtrl.js index 94b40b59591..217429d1253 100644 --- a/public/app/features/admin/adminStatsCtrl.js +++ b/public/app/features/admin/adminStatsCtrl.js @@ -6,16 +6,16 @@ function (angular) { var module = angular.module('grafana.controllers'); - module.controller('AdminStatsCtrl', function($scope) { + module.controller('AdminStatsCtrl', function($scope, backendSrv) { $scope.init = function() { $scope.getStats(); }; $scope.getStats = function() { -// backendSrv.get('/api/admin/stats').then(function(stats) { -// $scope.stats = stats; -// }); + backendSrv.get('/api/admin/stats').then(function(stats) { + $scope.stats = stats; + }); }; $scope.init(); diff --git a/public/app/features/admin/partials/stats.html b/public/app/features/admin/partials/stats.html index 048be83c83e..0df6d251f5c 100644 --- a/public/app/features/admin/partials/stats.html +++ b/public/app/features/admin/partials/stats.html @@ -17,35 +17,35 @@ Total dashboards - 213 + {{stats.dashboard_count}} Total users - 97 + {{stats.user_count}} Total organizations - 4 + {{stats.org_count}} + + + Total datasources + {{stats.data_source_count}} Total playlists - 12 + {{stats.playlist_count}} Total snapshots - 64 + {{stats.db_snapshot_count}} Total dashboard tags - 15 + {{stats.db_tag_count}} Total starred dashboards - 131 - - - Total panels - 2739 + {{stats.starred_db_count}} From a621c0d27356321da6e71d766a24aa583dfc1320 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 25 Jan 2016 00:02:05 -0800 Subject: [PATCH 05/18] Added docs for stats api --- docs/sources/reference/http_api.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/sources/reference/http_api.md b/docs/sources/reference/http_api.md index 7cdd8a872d5..a7ae066a8db 100644 --- a/docs/sources/reference/http_api.md +++ b/docs/sources/reference/http_api.md @@ -1422,6 +1422,33 @@ Keys: } } +### Grafana Stats + +`GET /api/admin/stats` + +**Example Request**: + + GET /api/admin/stats + Accept: application/json + Content-Type: application/json + Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +**Example Response**: + + HTTP/1.1 200 + Content-Type: application/json + + { + "user_count":2, + "org_count":1, + "dashboard_count":4, + "db_snapshot_count":2, + "db_tag_count":6, + "data_source_count":1, + "playlist_count":1, + "starred_db_count":2 + } + ### Global Users `POST /api/admin/users` From 2190392e052221905eba1b6f164ddc9574d92c9a Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 25 Jan 2016 00:39:31 -0800 Subject: [PATCH 06/18] Added grafana_admins count --- docs/sources/reference/http_api.md | 3 ++- pkg/models/stats.go | 17 +++++++++-------- pkg/services/sqlstore/stats.go | 6 +++++- public/app/features/admin/partials/stats.html | 11 +++++++++-- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/docs/sources/reference/http_api.md b/docs/sources/reference/http_api.md index a7ae066a8db..4b0dff6c4b6 100644 --- a/docs/sources/reference/http_api.md +++ b/docs/sources/reference/http_api.md @@ -1446,7 +1446,8 @@ Keys: "db_tag_count":6, "data_source_count":1, "playlist_count":1, - "starred_db_count":2 + "starred_db_count":2, + "grafana_admin_count":2 } ### Global Users diff --git a/pkg/models/stats.go b/pkg/models/stats.go index 6d8618d6ddf..4b1d863d1d2 100644 --- a/pkg/models/stats.go +++ b/pkg/models/stats.go @@ -20,14 +20,15 @@ type GetDataSourceStatsQuery struct { } type AdminStats struct { - UserCount int `json:"user_count"` - OrgCount int `json:"org_count"` - DashboardCount int `json:"dashboard_count"` - DbSnapshotCount int `json:"db_snapshot_count"` - DbTagCount int `json:"db_tag_count"` - DataSourceCount int `json:"data_source_count"` - PlaylistCount int `json:"playlist_count"` - StarredDbCount int `json:"starred_db_count"` + UserCount int `json:"user_count"` + OrgCount int `json:"org_count"` + DashboardCount int `json:"dashboard_count"` + DbSnapshotCount int `json:"db_snapshot_count"` + DbTagCount int `json:"db_tag_count"` + DataSourceCount int `json:"data_source_count"` + PlaylistCount int `json:"playlist_count"` + StarredDbCount int `json:"starred_db_count"` + GrafanaAdminCount int `json:"grafana_admin_count"` } type GetAdminStatsQuery struct { diff --git a/pkg/services/sqlstore/stats.go b/pkg/services/sqlstore/stats.go index 3c9325fa149..ad1d87299b1 100644 --- a/pkg/services/sqlstore/stats.go +++ b/pkg/services/sqlstore/stats.go @@ -81,7 +81,11 @@ func GetAdminStats(query *m.GetAdminStatsQuery) error { ( SELECT COUNT (DISTINCT ` + dialect.Quote("dashboard_id") + ` ) FROM ` + dialect.Quote("star") + ` - ) AS starred_db_count + ) AS starred_db_count, + ( + SELECT SUM ( ` + dialect.Quote("is_admin") + ` ) + FROM ` + dialect.Quote("user") + ` + ) AS grafana_admin_count ` var stats m.AdminStats diff --git a/public/app/features/admin/partials/stats.html b/public/app/features/admin/partials/stats.html index 0df6d251f5c..3743b0c81b8 100644 --- a/public/app/features/admin/partials/stats.html +++ b/public/app/features/admin/partials/stats.html @@ -1,10 +1,13 @@ - + +

- Stats + Overview

@@ -23,6 +26,10 @@ + + + + From 442db7fee1cc87a04fd95477b8a432784311f448 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 25 Jan 2016 14:30:36 -0800 Subject: [PATCH 07/18] Changed sql query for grafana_admin_count --- pkg/services/sqlstore/stats.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/services/sqlstore/stats.go b/pkg/services/sqlstore/stats.go index ad1d87299b1..a2e61aa0c3e 100644 --- a/pkg/services/sqlstore/stats.go +++ b/pkg/services/sqlstore/stats.go @@ -83,8 +83,9 @@ func GetAdminStats(query *m.GetAdminStatsQuery) error { FROM ` + dialect.Quote("star") + ` ) AS starred_db_count, ( - SELECT SUM ( ` + dialect.Quote("is_admin") + ` ) + SELECT COUNT(*) FROM ` + dialect.Quote("user") + ` + WHERE ` + dialect.Quote("is_admin") + ` = 1 ) AS grafana_admin_count ` From 29185eeef78f54e59cf2a91b6bed0017a9c87edd Mon Sep 17 00:00:00 2001 From: Pablo Fischer Date: Tue, 26 Jan 2016 00:12:56 +0000 Subject: [PATCH 08/18] If OpenTSDB is 3rd-party hosted (or by another team) and does not support OPTIONS, send the request as POST (urlencoded) --- public/app/plugins/datasource/opentsdb/datasource.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/app/plugins/datasource/opentsdb/datasource.js b/public/app/plugins/datasource/opentsdb/datasource.js index d7cc354861f..f4680038e8d 100644 --- a/public/app/plugins/datasource/opentsdb/datasource.js +++ b/public/app/plugins/datasource/opentsdb/datasource.js @@ -72,6 +72,9 @@ function (angular, _, dateMath) { data: reqBody }; + // In case the backend is 3rd-party hosted and does not suport OPTIONS, urlencoded requests + // go as POST rather than OPTIONS+POST + options.headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; return backendSrv.datasourceRequest(options); }; From 07fee0a810f0e0a2f6058ec6be8df5e1d9863508 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 25 Jan 2016 17:49:39 -0800 Subject: [PATCH 09/18] Converted adminStatsCtrl to typescript --- public/app/core/routes/all.js | 1 + public/app/features/admin/adminStatsCtrl.js | 24 ------------------- public/app/features/admin/adminStatsCtrl.ts | 18 ++++++++++++++ public/app/features/admin/partials/stats.html | 20 ++++++++-------- 4 files changed, 29 insertions(+), 34 deletions(-) delete mode 100644 public/app/features/admin/adminStatsCtrl.js create mode 100644 public/app/features/admin/adminStatsCtrl.ts diff --git a/public/app/core/routes/all.js b/public/app/core/routes/all.js index bc71a63a094..d9726ee782c 100644 --- a/public/app/core/routes/all.js +++ b/public/app/core/routes/all.js @@ -115,6 +115,7 @@ define([ .when('/admin/stats', { templateUrl: 'app/features/admin/partials/stats.html', controller : 'AdminStatsCtrl', + controllerAs: 'ctrl', }) .when('/login', { templateUrl: 'app/partials/login.html', diff --git a/public/app/features/admin/adminStatsCtrl.js b/public/app/features/admin/adminStatsCtrl.js deleted file mode 100644 index 217429d1253..00000000000 --- a/public/app/features/admin/adminStatsCtrl.js +++ /dev/null @@ -1,24 +0,0 @@ -define([ - 'angular', -], -function (angular) { - 'use strict'; - - var module = angular.module('grafana.controllers'); - - module.controller('AdminStatsCtrl', function($scope, backendSrv) { - - $scope.init = function() { - $scope.getStats(); - }; - - $scope.getStats = function() { - backendSrv.get('/api/admin/stats').then(function(stats) { - $scope.stats = stats; - }); - }; - - $scope.init(); - - }); -}); diff --git a/public/app/features/admin/adminStatsCtrl.ts b/public/app/features/admin/adminStatsCtrl.ts new file mode 100644 index 00000000000..0331524dcc7 --- /dev/null +++ b/public/app/features/admin/adminStatsCtrl.ts @@ -0,0 +1,18 @@ +// + +import angular from 'angular'; + +export class AdminStatsCtrl { + stats: any; + + /** @ngInject */ + constructor(private backendSrv: any) {} + + init() { + this.backendSrv.get('/api/admin/stats').then(stats => { + this.stats = stats; + }); + } +} + +angular.module('grafana.controllers').controller('AdminStatsCtrl', AdminStatsCtrl); diff --git a/public/app/features/admin/partials/stats.html b/public/app/features/admin/partials/stats.html index 3743b0c81b8..4949e71e441 100644 --- a/public/app/features/admin/partials/stats.html +++ b/public/app/features/admin/partials/stats.html @@ -5,7 +5,7 @@
-
+

Overview

@@ -20,39 +20,39 @@
- + - + - + - + - + - + - + - + - +
Total users {{stats.user_count}}
Total grafana admins{{stats.grafana_admin_count}}
Total organizations {{stats.org_count}}
Total dashboards{{stats.dashboard_count}}{{ctrl.stats.dashboard_count}}
Total users{{stats.user_count}}{{ctrl.stats.user_count}}
Total grafana admins{{stats.grafana_admin_count}}{{ctrl.stats.grafana_admin_count}}
Total organizations{{stats.org_count}}{{ctrl.stats.org_count}}
Total datasources{{stats.data_source_count}}{{ctrl.stats.data_source_count}}
Total playlists{{stats.playlist_count}}{{ctrl.stats.playlist_count}}
Total snapshots{{stats.db_snapshot_count}}{{ctrl.stats.db_snapshot_count}}
Total dashboard tags{{stats.db_tag_count}}{{ctrl.stats.db_tag_count}}
Total starred dashboards{{stats.starred_db_count}}{{ctrl.stats.starred_db_count}}
From e59b0c0694106e2fb131c54ebd03c950756b447d Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 25 Jan 2016 18:10:48 -0800 Subject: [PATCH 10/18] Fixed ts file comment --- public/app/features/admin/adminStatsCtrl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/admin/adminStatsCtrl.ts b/public/app/features/admin/adminStatsCtrl.ts index 0331524dcc7..aa3ed6de343 100644 --- a/public/app/features/admin/adminStatsCtrl.ts +++ b/public/app/features/admin/adminStatsCtrl.ts @@ -1,4 +1,4 @@ -// +/// import angular from 'angular'; From f43e1ab2ff544114b24933ed2ae65a6284f50233 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Wed, 27 Jan 2016 17:20:03 +0100 Subject: [PATCH 11/18] fix(graph): narrow panels shows right date format on x-axis fixes #3852. The function that calculates the date format for the x-axis on a panel takes the panel width into account and can be wrong for certain date ranges if the panel is too narrow. E.g. can show dates in format %m/%d %H:%M when it should show it as %H:%M --- public/app/plugins/panel/graph/graph.js | 13 ++++--- .../plugins/panel/graph/specs/graph_specs.ts | 36 ++++++++++++++++--- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/public/app/plugins/panel/graph/graph.js b/public/app/plugins/panel/graph/graph.js index 1ebf75d9e73..257ddb875b1 100755 --- a/public/app/plugins/panel/graph/graph.js +++ b/public/app/plugins/panel/graph/graph.js @@ -296,7 +296,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) { max: max, label: "Datetime", ticks: ticks, - timeformat: time_format(scope.interval, ticks, min, max), + timeformat: time_format(ticks, min, max), }; } @@ -436,20 +436,23 @@ function (angular, $, moment, _, kbn, GraphTooltip) { }; } - function time_format(interval, ticks, min, max) { + function time_format(ticks, min, max) { if (min && max && ticks) { - var secPerTick = ((max - min) / ticks) / 1000; + var range = max - min; + var secPerTick = (range/ticks) / 1000; + var oneDay = 86400000; + var oneYear = 31536000000; if (secPerTick <= 45) { return "%H:%M:%S"; } - if (secPerTick <= 7200) { + if (secPerTick <= 7200 || range <= oneDay) { return "%H:%M"; } if (secPerTick <= 80000) { return "%m/%d %H:%M"; } - if (secPerTick <= 2419200) { + if (secPerTick <= 2419200 || range <= oneYear) { return "%m/%d"; } return "%Y-%m"; diff --git a/public/app/plugins/panel/graph/specs/graph_specs.ts b/public/app/plugins/panel/graph/specs/graph_specs.ts index e07033583b7..fa1d01a88f8 100644 --- a/public/app/plugins/panel/graph/specs/graph_specs.ts +++ b/public/app/plugins/panel/graph/specs/graph_specs.ts @@ -7,12 +7,13 @@ import angular from 'angular'; import $ from 'jquery'; import helpers from '../../../../../test/specs/helpers'; import TimeSeries from '../../../../core/time_series2'; +import moment from 'moment'; describe('grafanaGraph', function() { beforeEach(angularMocks.module('grafana.directives')); - function graphScenario(desc, func) { + function graphScenario(desc, func, elementWidth = 500) { describe(desc, function() { var ctx: any = {}; @@ -24,7 +25,7 @@ describe('grafanaGraph', function() { beforeEach(angularMocks.inject(function($rootScope, $compile) { var scope = $rootScope.$new(); - var element = angular.element("
"); + var element = angular.element("
"); scope.height = '200px'; scope.panel = { @@ -43,8 +44,8 @@ describe('grafanaGraph', function() { scope.hiddenSeries = {}; scope.dashboard = { timezone: 'browser' }; scope.range = { - from: new Date('2014-08-09 10:00:00'), - to: new Date('2014-09-09 13:00:00') + from: moment([2015, 1, 1, 10]), + to: moment([2015, 1, 1, 22]) }; ctx.data = []; ctx.data.push(new TimeSeries({ @@ -227,4 +228,31 @@ describe('grafanaGraph', function() { expect(axis.tickFormatter(100, axis)).to.be("100%"); }); }); + + graphScenario('when panel too narrow to show x-axis dates in same granularity as wide panels', function(ctx) { + describe('and the range is less than 24 hours', function() { + ctx.setup(function(scope) { + scope.range.from = moment([2015, 1, 1, 10]); + scope.range.to = moment([2015, 1, 1, 22]); + }); + + it('should format dates as hours minutes', function() { + var axis = ctx.plotOptions.xaxis; + expect(axis.timeformat).to.be('%H:%M'); + }); + }); + + describe('and the range is less than one year', function() { + ctx.setup(function(scope) { + scope.range.from = moment([2015, 1, 1]); + scope.range.to = moment([2015, 11, 20]); + }); + + it('should format dates as month days', function() { + var axis = ctx.plotOptions.xaxis; + expect(axis.timeformat).to.be('%m/%d'); + }); + }); + + }, 10); }); From 75ab2e026d51ac2e5dda5b16ce573064e5f1b389 Mon Sep 17 00:00:00 2001 From: sgarg7 Date: Wed, 27 Jan 2016 10:37:25 -0500 Subject: [PATCH 12/18] test(spelling): fix spelling/typo in string --- .../app/plugins/datasource/opentsdb/specs/datasource-specs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts b/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts index b1ad1b93737..6f8b8917588 100644 --- a/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts +++ b/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts @@ -36,14 +36,14 @@ describe('opentsdb', function() { expect(requestOptions.params.q).to.be('pew'); }); - it('tag_names(cpu) should generate looku query', function() { + it('tag_names(cpu) should generate lookup query', function() { ctx.ds.metricFindQuery('tag_names(cpu)').then(function(data) { results = data; }); ctx.$rootScope.$apply(); expect(requestOptions.url).to.be('/api/search/lookup'); expect(requestOptions.params.m).to.be('cpu'); }); - it('tag_values(cpu, test) should generate looku query', function() { + it('tag_values(cpu, test) should generate lookup query', function() { ctx.ds.metricFindQuery('tag_values(cpu, hostname)').then(function(data) { results = data; }); ctx.$rootScope.$apply(); expect(requestOptions.url).to.be('/api/search/lookup'); From 448437c342df630a01d54845521bd09c1e9619f5 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Wed, 27 Jan 2016 20:18:35 +0100 Subject: [PATCH 13/18] feat(circleci): triggers grafana packer after successful build Only triggers for main grafana repo (not forks) and when the master branch is built. --- circle.yml | 7 +++++++ trigger_grafana_packer.sh | 10 ++++++++++ 2 files changed, 17 insertions(+) create mode 100755 trigger_grafana_packer.sh diff --git a/circle.yml b/circle.yml index a3280ae18e5..22dab8ab893 100644 --- a/circle.yml +++ b/circle.yml @@ -27,3 +27,10 @@ test: # js tests - ./node_modules/grunt-cli/bin/grunt test - npm run coveralls + +deployment: + master: + branch: master + owner: grafana + commands: + - ./trigger_grafana_packer.sh ${TRIGGER_GRAFANA_PACKER_CIRCLECI_TOKEN} diff --git a/trigger_grafana_packer.sh b/trigger_grafana_packer.sh new file mode 100755 index 00000000000..e4a33a00221 --- /dev/null +++ b/trigger_grafana_packer.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +_circle_token=$1 + +trigger_build_url=https://circleci.com/api/v1/project/grafana/grafana-packer/tree/master?circle-token=${_circle_token} + +curl \ +--header "Accept: application/json" \ +--header "Content-Type: application/json" \ +--request POST ${trigger_build_url} \ No newline at end of file From c8727db03ba132ddaeb7284ab7ccb6a7b5ceb600 Mon Sep 17 00:00:00 2001 From: Utkarsh Bhatnagar Date: Wed, 27 Jan 2016 14:47:58 -0800 Subject: [PATCH 14/18] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e97ab145c61..afdf52c47c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ * **Sessions**: Support for memcached as session storage, closes [#3458](https://github.com/grafana/grafana/pull/3458) * **mysql**: Grafana now supports ssl for mysql, closes [#3584](https://github.com/grafana/grafana/pull/3584) * **snapshot**: Annotations are now included in snapshots, closes [#3635](https://github.com/grafana/grafana/pull/3635) +* **Admin**: Admin can now have global overview of Grafana setup, closes [#3812](https://github.com/grafana/grafana/issues/3812) ### Bug fixes * **Playlist**: Fix for memory leak when running a playlist, closes [#3794](https://github.com/grafana/grafana/pull/3794) From 1210fca8e5eae430d7abcd893453f1d5e0bd0cc1 Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 28 Jan 2016 01:11:26 +0100 Subject: [PATCH 15/18] fix(singlestat): fix bug in threshold calculations --- public/app/plugins/panel/singlestat/module.ts | 2 +- .../panel/singlestat/specs/singlestat_panel_spec.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index 0a171207bcf..faf88e691e4 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -221,7 +221,7 @@ function singleStatPanel($location, linkSrv, $timeout, templateSrv) { function getColorForValue(data, value) { for (var i = data.thresholds.length; i > 0; i--) { - if (value >= data.thresholds[i]) { + if (value >= data.thresholds[i-1]) { return data.colorMap[i]; } } diff --git a/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts b/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts index 17b34f6bcef..5e93923e6d3 100644 --- a/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts +++ b/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts @@ -2,12 +2,12 @@ import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; import {getColorForValue} from '../module'; -describe('grafanaSingleStat', function() { +describe.only('grafanaSingleStat', function() { describe('legacy thresholds', () => { describe('positive thresholds', () => { var data: any = { colorMap: ['green', 'yellow', 'red'], - thresholds: [0, 20, 50] + thresholds: [20, 50] }; it('5 should return green', () => { @@ -29,7 +29,7 @@ describe('grafanaSingleStat', function() { describe('negative thresholds', () => { var data: any = { colorMap: ['green', 'yellow', 'red'], - thresholds: [ -20, 0, 20] + thresholds: [ 0, 20] }; it('-30 should return green', () => { @@ -48,7 +48,7 @@ describe('grafanaSingleStat', function() { describe('negative thresholds', () => { var data: any = { colorMap: ['green', 'yellow', 'red'], - thresholds: [ -40, -27, 20] + thresholds: [-27, 20] }; it('-30 should return green', () => { From 72a64388b57f21c3b6aef5aa8f9a0951a3ea264e Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 28 Jan 2016 01:14:12 +0100 Subject: [PATCH 16/18] fix(tests): remove only in spec --- .../app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts b/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts index 5e93923e6d3..0ea34c54721 100644 --- a/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts +++ b/public/app/plugins/panel/singlestat/specs/singlestat_panel_spec.ts @@ -2,7 +2,7 @@ import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; import {getColorForValue} from '../module'; -describe.only('grafanaSingleStat', function() { +describe('grafanaSingleStat', function() { describe('legacy thresholds', () => { describe('positive thresholds', () => { var data: any = { From 8bd07287f8d993d32f3decb849e47782a36ca371 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Wed, 27 Jan 2016 17:41:23 -0800 Subject: [PATCH 17/18] Fixed dashboard_tag query --- pkg/services/sqlstore/stats.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/sqlstore/stats.go b/pkg/services/sqlstore/stats.go index 0465c6999a9..fbd22ac0f5c 100644 --- a/pkg/services/sqlstore/stats.go +++ b/pkg/services/sqlstore/stats.go @@ -71,7 +71,7 @@ func GetAdminStats(query *m.GetAdminStatsQuery) error { FROM ` + dialect.Quote("dashboard_snapshot") + ` ) AS db_snapshot_count, ( - SELECT COUNT(*) + SELECT COUNT( DISTINCT ( ` + dialect.Quote("term") + ` )) FROM ` + dialect.Quote("dashboard_tag") + ` ) AS db_tag_count, ( From 64fa9a6394995bd23da97698e8955c0ef709b755 Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 28 Jan 2016 22:25:25 +0100 Subject: [PATCH 18/18] fix(singlestat): add ngInject for controller fixes #3879 --- public/app/plugins/panel/singlestat/module.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index faf88e691e4..f4e0063a912 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -7,6 +7,7 @@ import {SingleStatCtrl} from './controller'; angular.module('grafana.directives').directive('singleStatPanel', singleStatPanel); +/** @ngInject */ function singleStatPanel($location, linkSrv, $timeout, templateSrv) { 'use strict'; return {