You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

admin.go 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package admin
  5. import (
  6. "fmt"
  7. "net/http"
  8. "runtime"
  9. "sort"
  10. "time"
  11. activities_model "code.gitea.io/gitea/models/activities"
  12. "code.gitea.io/gitea/modules/base"
  13. "code.gitea.io/gitea/modules/context"
  14. "code.gitea.io/gitea/modules/json"
  15. "code.gitea.io/gitea/modules/setting"
  16. "code.gitea.io/gitea/modules/updatechecker"
  17. "code.gitea.io/gitea/modules/web"
  18. "code.gitea.io/gitea/services/cron"
  19. "code.gitea.io/gitea/services/forms"
  20. )
  21. const (
  22. tplDashboard base.TplName = "admin/dashboard"
  23. tplCron base.TplName = "admin/cron"
  24. tplQueue base.TplName = "admin/queue"
  25. tplStacktrace base.TplName = "admin/stacktrace"
  26. tplQueueManage base.TplName = "admin/queue_manage"
  27. tplStats base.TplName = "admin/stats"
  28. )
  29. var sysStatus struct {
  30. StartTime string
  31. NumGoroutine int
  32. // General statistics.
  33. MemAllocated string // bytes allocated and still in use
  34. MemTotal string // bytes allocated (even if freed)
  35. MemSys string // bytes obtained from system (sum of XxxSys below)
  36. Lookups uint64 // number of pointer lookups
  37. MemMallocs uint64 // number of mallocs
  38. MemFrees uint64 // number of frees
  39. // Main allocation heap statistics.
  40. HeapAlloc string // bytes allocated and still in use
  41. HeapSys string // bytes obtained from system
  42. HeapIdle string // bytes in idle spans
  43. HeapInuse string // bytes in non-idle span
  44. HeapReleased string // bytes released to the OS
  45. HeapObjects uint64 // total number of allocated objects
  46. // Low-level fixed-size structure allocator statistics.
  47. // Inuse is bytes used now.
  48. // Sys is bytes obtained from system.
  49. StackInuse string // bootstrap stacks
  50. StackSys string
  51. MSpanInuse string // mspan structures
  52. MSpanSys string
  53. MCacheInuse string // mcache structures
  54. MCacheSys string
  55. BuckHashSys string // profiling bucket hash table
  56. GCSys string // GC metadata
  57. OtherSys string // other system allocations
  58. // Garbage collector statistics.
  59. NextGC string // next run in HeapAlloc time (bytes)
  60. LastGC string // last run in absolute time (ns)
  61. PauseTotalNs string
  62. PauseNs string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
  63. NumGC uint32
  64. }
  65. func updateSystemStatus() {
  66. sysStatus.StartTime = setting.AppStartTime.Format(time.RFC3339)
  67. m := new(runtime.MemStats)
  68. runtime.ReadMemStats(m)
  69. sysStatus.NumGoroutine = runtime.NumGoroutine()
  70. sysStatus.MemAllocated = base.FileSize(int64(m.Alloc))
  71. sysStatus.MemTotal = base.FileSize(int64(m.TotalAlloc))
  72. sysStatus.MemSys = base.FileSize(int64(m.Sys))
  73. sysStatus.Lookups = m.Lookups
  74. sysStatus.MemMallocs = m.Mallocs
  75. sysStatus.MemFrees = m.Frees
  76. sysStatus.HeapAlloc = base.FileSize(int64(m.HeapAlloc))
  77. sysStatus.HeapSys = base.FileSize(int64(m.HeapSys))
  78. sysStatus.HeapIdle = base.FileSize(int64(m.HeapIdle))
  79. sysStatus.HeapInuse = base.FileSize(int64(m.HeapInuse))
  80. sysStatus.HeapReleased = base.FileSize(int64(m.HeapReleased))
  81. sysStatus.HeapObjects = m.HeapObjects
  82. sysStatus.StackInuse = base.FileSize(int64(m.StackInuse))
  83. sysStatus.StackSys = base.FileSize(int64(m.StackSys))
  84. sysStatus.MSpanInuse = base.FileSize(int64(m.MSpanInuse))
  85. sysStatus.MSpanSys = base.FileSize(int64(m.MSpanSys))
  86. sysStatus.MCacheInuse = base.FileSize(int64(m.MCacheInuse))
  87. sysStatus.MCacheSys = base.FileSize(int64(m.MCacheSys))
  88. sysStatus.BuckHashSys = base.FileSize(int64(m.BuckHashSys))
  89. sysStatus.GCSys = base.FileSize(int64(m.GCSys))
  90. sysStatus.OtherSys = base.FileSize(int64(m.OtherSys))
  91. sysStatus.NextGC = base.FileSize(int64(m.NextGC))
  92. sysStatus.LastGC = fmt.Sprintf("%.1fs", float64(time.Now().UnixNano()-int64(m.LastGC))/1000/1000/1000)
  93. sysStatus.PauseTotalNs = fmt.Sprintf("%.1fs", float64(m.PauseTotalNs)/1000/1000/1000)
  94. sysStatus.PauseNs = fmt.Sprintf("%.3fs", float64(m.PauseNs[(m.NumGC+255)%256])/1000/1000/1000)
  95. sysStatus.NumGC = m.NumGC
  96. }
  97. func prepareDeprecatedWarningsAlert(ctx *context.Context) {
  98. if len(setting.DeprecatedWarnings) > 0 {
  99. content := setting.DeprecatedWarnings[0]
  100. if len(setting.DeprecatedWarnings) > 1 {
  101. content += fmt.Sprintf(" (and %d more)", len(setting.DeprecatedWarnings)-1)
  102. }
  103. ctx.Flash.Error(content, true)
  104. }
  105. }
  106. // Dashboard show admin panel dashboard
  107. func Dashboard(ctx *context.Context) {
  108. ctx.Data["Title"] = ctx.Tr("admin.dashboard")
  109. ctx.Data["PageIsAdminDashboard"] = true
  110. ctx.Data["NeedUpdate"] = updatechecker.GetNeedUpdate()
  111. ctx.Data["RemoteVersion"] = updatechecker.GetRemoteVersion()
  112. // FIXME: update periodically
  113. updateSystemStatus()
  114. ctx.Data["SysStatus"] = sysStatus
  115. ctx.Data["SSH"] = setting.SSH
  116. prepareDeprecatedWarningsAlert(ctx)
  117. ctx.HTML(http.StatusOK, tplDashboard)
  118. }
  119. // DashboardPost run an admin operation
  120. func DashboardPost(ctx *context.Context) {
  121. form := web.GetForm(ctx).(*forms.AdminDashboardForm)
  122. ctx.Data["Title"] = ctx.Tr("admin.dashboard")
  123. ctx.Data["PageIsAdminDashboard"] = true
  124. updateSystemStatus()
  125. ctx.Data["SysStatus"] = sysStatus
  126. // Run operation.
  127. if form.Op != "" {
  128. task := cron.GetTask(form.Op)
  129. if task != nil {
  130. go task.RunWithUser(ctx.Doer, nil)
  131. ctx.Flash.Success(ctx.Tr("admin.dashboard.task.started", ctx.Tr("admin.dashboard."+form.Op)))
  132. } else {
  133. ctx.Flash.Error(ctx.Tr("admin.dashboard.task.unknown", form.Op))
  134. }
  135. }
  136. if form.From == "monitor" {
  137. ctx.Redirect(setting.AppSubURL + "/admin/monitor/cron")
  138. } else {
  139. ctx.Redirect(setting.AppSubURL + "/admin")
  140. }
  141. }
  142. func CronTasks(ctx *context.Context) {
  143. ctx.Data["Title"] = ctx.Tr("admin.monitor.cron")
  144. ctx.Data["PageIsAdminMonitorCron"] = true
  145. ctx.Data["Entries"] = cron.ListTasks()
  146. ctx.HTML(http.StatusOK, tplCron)
  147. }
  148. func MonitorStats(ctx *context.Context) {
  149. ctx.Data["Title"] = ctx.Tr("admin.monitor.stats")
  150. ctx.Data["PageIsAdminMonitorStats"] = true
  151. bs, err := json.Marshal(activities_model.GetStatistic().Counter)
  152. if err != nil {
  153. ctx.ServerError("MonitorStats", err)
  154. return
  155. }
  156. statsCounter := map[string]any{}
  157. err = json.Unmarshal(bs, &statsCounter)
  158. if err != nil {
  159. ctx.ServerError("MonitorStats", err)
  160. return
  161. }
  162. statsKeys := make([]string, 0, len(statsCounter))
  163. for k := range statsCounter {
  164. if statsCounter[k] == nil {
  165. continue
  166. }
  167. statsKeys = append(statsKeys, k)
  168. }
  169. sort.Strings(statsKeys)
  170. ctx.Data["StatsKeys"] = statsKeys
  171. ctx.Data["StatsCounter"] = statsCounter
  172. ctx.HTML(http.StatusOK, tplStats)
  173. }