usage_stats.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package usagestats
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "net/http"
  7. "runtime"
  8. "strings"
  9. "time"
  10. "github.com/grafana/grafana/pkg/infra/metrics"
  11. "github.com/grafana/grafana/pkg/models"
  12. "github.com/grafana/grafana/pkg/plugins"
  13. "github.com/grafana/grafana/pkg/setting"
  14. )
  15. var usageStatsURL = "https://stats.grafana.org/grafana-usage-report"
  16. func (uss *UsageStatsService) sendUsageStats(oauthProviders map[string]bool) {
  17. if !setting.ReportingEnabled {
  18. return
  19. }
  20. metricsLogger.Debug(fmt.Sprintf("Sending anonymous usage stats to %s", usageStatsURL))
  21. version := strings.Replace(setting.BuildVersion, ".", "_", -1)
  22. metrics := map[string]interface{}{}
  23. report := map[string]interface{}{
  24. "version": version,
  25. "metrics": metrics,
  26. "os": runtime.GOOS,
  27. "arch": runtime.GOARCH,
  28. "edition": getEdition(),
  29. "packaging": setting.Packaging,
  30. }
  31. statsQuery := models.GetSystemStatsQuery{}
  32. if err := uss.Bus.Dispatch(&statsQuery); err != nil {
  33. metricsLogger.Error("Failed to get system stats", "error", err)
  34. return
  35. }
  36. metrics["stats.dashboards.count"] = statsQuery.Result.Dashboards
  37. metrics["stats.users.count"] = statsQuery.Result.Users
  38. metrics["stats.orgs.count"] = statsQuery.Result.Orgs
  39. metrics["stats.playlist.count"] = statsQuery.Result.Playlists
  40. metrics["stats.plugins.apps.count"] = len(plugins.Apps)
  41. metrics["stats.plugins.panels.count"] = len(plugins.Panels)
  42. metrics["stats.plugins.datasources.count"] = len(plugins.DataSources)
  43. metrics["stats.alerts.count"] = statsQuery.Result.Alerts
  44. metrics["stats.active_users.count"] = statsQuery.Result.ActiveUsers
  45. metrics["stats.datasources.count"] = statsQuery.Result.Datasources
  46. metrics["stats.stars.count"] = statsQuery.Result.Stars
  47. metrics["stats.folders.count"] = statsQuery.Result.Folders
  48. metrics["stats.dashboard_permissions.count"] = statsQuery.Result.DashboardPermissions
  49. metrics["stats.folder_permissions.count"] = statsQuery.Result.FolderPermissions
  50. metrics["stats.provisioned_dashboards.count"] = statsQuery.Result.ProvisionedDashboards
  51. metrics["stats.snapshots.count"] = statsQuery.Result.Snapshots
  52. metrics["stats.teams.count"] = statsQuery.Result.Teams
  53. metrics["stats.total_auth_token.count"] = statsQuery.Result.AuthTokens
  54. userCount := statsQuery.Result.Users
  55. avgAuthTokensPerUser := statsQuery.Result.AuthTokens
  56. if userCount != 0 {
  57. avgAuthTokensPerUser = avgAuthTokensPerUser / userCount
  58. }
  59. metrics["stats.avg_auth_token_per_user.count"] = avgAuthTokensPerUser
  60. dsStats := models.GetDataSourceStatsQuery{}
  61. if err := uss.Bus.Dispatch(&dsStats); err != nil {
  62. metricsLogger.Error("Failed to get datasource stats", "error", err)
  63. return
  64. }
  65. // send counters for each data source
  66. // but ignore any custom data sources
  67. // as sending that name could be sensitive information
  68. dsOtherCount := 0
  69. for _, dsStat := range dsStats.Result {
  70. if models.IsKnownDataSourcePlugin(dsStat.Type) {
  71. metrics["stats.ds."+dsStat.Type+".count"] = dsStat.Count
  72. } else {
  73. dsOtherCount += dsStat.Count
  74. }
  75. }
  76. metrics["stats.ds.other.count"] = dsOtherCount
  77. metrics["stats.packaging."+setting.Packaging+".count"] = 1
  78. dsAccessStats := models.GetDataSourceAccessStatsQuery{}
  79. if err := uss.Bus.Dispatch(&dsAccessStats); err != nil {
  80. metricsLogger.Error("Failed to get datasource access stats", "error", err)
  81. return
  82. }
  83. // send access counters for each data source
  84. // but ignore any custom data sources
  85. // as sending that name could be sensitive information
  86. dsAccessOtherCount := make(map[string]int64)
  87. for _, dsAccessStat := range dsAccessStats.Result {
  88. if dsAccessStat.Access == "" {
  89. continue
  90. }
  91. access := strings.ToLower(dsAccessStat.Access)
  92. if models.IsKnownDataSourcePlugin(dsAccessStat.Type) {
  93. metrics["stats.ds_access."+dsAccessStat.Type+"."+access+".count"] = dsAccessStat.Count
  94. } else {
  95. old := dsAccessOtherCount[access]
  96. dsAccessOtherCount[access] = old + dsAccessStat.Count
  97. }
  98. }
  99. for access, count := range dsAccessOtherCount {
  100. metrics["stats.ds_access.other."+access+".count"] = count
  101. }
  102. anStats := models.GetAlertNotifierUsageStatsQuery{}
  103. if err := uss.Bus.Dispatch(&anStats); err != nil {
  104. metricsLogger.Error("Failed to get alert notification stats", "error", err)
  105. return
  106. }
  107. for _, stats := range anStats.Result {
  108. metrics["stats.alert_notifiers."+stats.Type+".count"] = stats.Count
  109. }
  110. authTypes := map[string]bool{}
  111. authTypes["anonymous"] = setting.AnonymousEnabled
  112. authTypes["basic_auth"] = setting.BasicAuthEnabled
  113. authTypes["ldap"] = setting.LdapEnabled
  114. authTypes["auth_proxy"] = setting.AuthProxyEnabled
  115. for provider, enabled := range oauthProviders {
  116. authTypes["oauth_"+provider] = enabled
  117. }
  118. for authType, enabled := range authTypes {
  119. enabledValue := 0
  120. if enabled {
  121. enabledValue = 1
  122. }
  123. metrics["stats.auth_enabled."+authType+".count"] = enabledValue
  124. }
  125. out, _ := json.MarshalIndent(report, "", " ")
  126. data := bytes.NewBuffer(out)
  127. client := http.Client{Timeout: 5 * time.Second}
  128. go client.Post(usageStatsURL, "application/json", data)
  129. }
  130. func (uss *UsageStatsService) updateTotalStats() {
  131. statsQuery := models.GetSystemStatsQuery{}
  132. if err := uss.Bus.Dispatch(&statsQuery); err != nil {
  133. metricsLogger.Error("Failed to get system stats", "error", err)
  134. return
  135. }
  136. metrics.M_StatTotal_Dashboards.Set(float64(statsQuery.Result.Dashboards))
  137. metrics.M_StatTotal_Users.Set(float64(statsQuery.Result.Users))
  138. metrics.M_StatActive_Users.Set(float64(statsQuery.Result.ActiveUsers))
  139. metrics.M_StatTotal_Playlists.Set(float64(statsQuery.Result.Playlists))
  140. metrics.M_StatTotal_Orgs.Set(float64(statsQuery.Result.Orgs))
  141. }
  142. func getEdition() string {
  143. if setting.IsEnterprise {
  144. return "enterprise"
  145. }
  146. return "oss"
  147. }