2014-03-20 15:50:26 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2019-06-26 19:12:38 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2014-03-20 15:50:26 +04:00
package admin
import (
2014-03-22 15:42:24 +04:00
"fmt"
2021-04-05 18:30:52 +03:00
"net/http"
2024-02-23 00:25:19 +03:00
"reflect"
2014-03-22 15:42:24 +04:00
"runtime"
"time"
2014-03-21 11:27:59 +04:00
2022-08-25 05:31:57 +03:00
activities_model "code.gitea.io/gitea/models/activities"
2024-01-10 14:03:23 +03:00
"code.gitea.io/gitea/models/db"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/base"
2023-06-29 13:03:20 +03:00
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/setting"
2021-10-21 19:10:49 +03:00
"code.gitea.io/gitea/modules/updatechecker"
2021-01-26 18:36:53 +03:00
"code.gitea.io/gitea/modules/web"
2024-02-27 10:12:22 +03:00
"code.gitea.io/gitea/services/context"
2021-11-16 16:30:11 +03:00
"code.gitea.io/gitea/services/cron"
2021-04-06 22:44:05 +03:00
"code.gitea.io/gitea/services/forms"
2024-01-24 06:02:04 +03:00
release_service "code.gitea.io/gitea/services/release"
2023-06-29 13:03:20 +03:00
repo_service "code.gitea.io/gitea/services/repository"
2014-03-20 15:50:26 +04:00
)
2014-06-22 21:14:03 +04:00
const (
2024-02-16 05:52:25 +03:00
tplDashboard base . TplName = "admin/dashboard"
tplSystemStatus base . TplName = "admin/system_status"
tplSelfCheck base . TplName = "admin/self_check"
tplCron base . TplName = "admin/cron"
tplQueue base . TplName = "admin/queue"
tplStacktrace base . TplName = "admin/stacktrace"
tplQueueManage base . TplName = "admin/queue_manage"
tplStats base . TplName = "admin/stats"
2014-06-22 21:14:03 +04:00
)
2014-03-22 15:42:24 +04:00
var sysStatus struct {
2023-04-11 02:01:20 +03:00
StartTime string
2014-03-22 15:42:24 +04:00
NumGoroutine int
// General statistics.
MemAllocated string // bytes allocated and still in use
MemTotal string // bytes allocated (even if freed)
MemSys string // bytes obtained from system (sum of XxxSys below)
Lookups uint64 // number of pointer lookups
MemMallocs uint64 // number of mallocs
MemFrees uint64 // number of frees
// Main allocation heap statistics.
HeapAlloc string // bytes allocated and still in use
HeapSys string // bytes obtained from system
HeapIdle string // bytes in idle spans
HeapInuse string // bytes in non-idle span
HeapReleased string // bytes released to the OS
HeapObjects uint64 // total number of allocated objects
// Low-level fixed-size structure allocator statistics.
// Inuse is bytes used now.
// Sys is bytes obtained from system.
StackInuse string // bootstrap stacks
StackSys string
MSpanInuse string // mspan structures
MSpanSys string
MCacheInuse string // mcache structures
MCacheSys string
BuckHashSys string // profiling bucket hash table
GCSys string // GC metadata
OtherSys string // other system allocations
// Garbage collector statistics.
NextGC string // next run in HeapAlloc time (bytes)
2024-02-16 05:52:25 +03:00
LastGCTime string // last run time
2014-03-22 15:42:24 +04:00
PauseTotalNs string
PauseNs string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
NumGC uint32
}
func updateSystemStatus ( ) {
2023-04-11 02:01:20 +03:00
sysStatus . StartTime = setting . AppStartTime . Format ( time . RFC3339 )
2014-03-22 17:21:57 +04:00
2014-03-22 15:42:24 +04:00
m := new ( runtime . MemStats )
runtime . ReadMemStats ( m )
sysStatus . NumGoroutine = runtime . NumGoroutine ( )
sysStatus . MemAllocated = base . FileSize ( int64 ( m . Alloc ) )
sysStatus . MemTotal = base . FileSize ( int64 ( m . TotalAlloc ) )
sysStatus . MemSys = base . FileSize ( int64 ( m . Sys ) )
sysStatus . Lookups = m . Lookups
sysStatus . MemMallocs = m . Mallocs
sysStatus . MemFrees = m . Frees
sysStatus . HeapAlloc = base . FileSize ( int64 ( m . HeapAlloc ) )
sysStatus . HeapSys = base . FileSize ( int64 ( m . HeapSys ) )
sysStatus . HeapIdle = base . FileSize ( int64 ( m . HeapIdle ) )
sysStatus . HeapInuse = base . FileSize ( int64 ( m . HeapInuse ) )
sysStatus . HeapReleased = base . FileSize ( int64 ( m . HeapReleased ) )
sysStatus . HeapObjects = m . HeapObjects
sysStatus . StackInuse = base . FileSize ( int64 ( m . StackInuse ) )
sysStatus . StackSys = base . FileSize ( int64 ( m . StackSys ) )
sysStatus . MSpanInuse = base . FileSize ( int64 ( m . MSpanInuse ) )
sysStatus . MSpanSys = base . FileSize ( int64 ( m . MSpanSys ) )
sysStatus . MCacheInuse = base . FileSize ( int64 ( m . MCacheInuse ) )
sysStatus . MCacheSys = base . FileSize ( int64 ( m . MCacheSys ) )
sysStatus . BuckHashSys = base . FileSize ( int64 ( m . BuckHashSys ) )
sysStatus . GCSys = base . FileSize ( int64 ( m . GCSys ) )
sysStatus . OtherSys = base . FileSize ( int64 ( m . OtherSys ) )
sysStatus . NextGC = base . FileSize ( int64 ( m . NextGC ) )
2024-02-16 05:52:25 +03:00
sysStatus . LastGCTime = time . Unix ( 0 , int64 ( m . LastGC ) ) . Format ( time . RFC3339 )
2014-03-22 17:21:57 +04:00
sysStatus . PauseTotalNs = fmt . Sprintf ( "%.1fs" , float64 ( m . PauseTotalNs ) / 1000 / 1000 / 1000 )
sysStatus . PauseNs = fmt . Sprintf ( "%.3fs" , float64 ( m . PauseNs [ ( m . NumGC + 255 ) % 256 ] ) / 1000 / 1000 / 1000 )
2014-03-22 15:42:24 +04:00
sysStatus . NumGC = m . NumGC
}
2023-07-26 06:53:37 +03:00
func prepareDeprecatedWarningsAlert ( ctx * context . Context ) {
if len ( setting . DeprecatedWarnings ) > 0 {
content := setting . DeprecatedWarnings [ 0 ]
if len ( setting . DeprecatedWarnings ) > 1 {
content += fmt . Sprintf ( " (and %d more)" , len ( setting . DeprecatedWarnings ) - 1 )
}
ctx . Flash . Error ( content , true )
}
}
2016-11-21 06:21:24 +03:00
// Dashboard show admin panel dashboard
2016-03-11 19:56:52 +03:00
func Dashboard ( ctx * context . Context ) {
2014-08-28 18:29:00 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "admin.dashboard" )
ctx . Data [ "PageIsAdminDashboard" ] = true
2023-10-15 18:46:06 +03:00
ctx . Data [ "NeedUpdate" ] = updatechecker . GetNeedUpdate ( ctx )
ctx . Data [ "RemoteVersion" ] = updatechecker . GetRemoteVersion ( ctx )
2020-02-26 01:54:13 +03:00
updateSystemStatus ( )
ctx . Data [ "SysStatus" ] = sysStatus
2020-10-08 19:43:15 +03:00
ctx . Data [ "SSH" ] = setting . SSH
2023-07-26 06:53:37 +03:00
prepareDeprecatedWarningsAlert ( ctx )
2021-04-05 18:30:52 +03:00
ctx . HTML ( http . StatusOK , tplDashboard )
2020-02-26 01:54:13 +03:00
}
2024-02-16 05:52:25 +03:00
func SystemStatus ( ctx * context . Context ) {
updateSystemStatus ( )
ctx . Data [ "SysStatus" ] = sysStatus
ctx . HTML ( http . StatusOK , tplSystemStatus )
}
2020-02-26 01:54:13 +03:00
// DashboardPost run an admin operation
2021-01-26 18:36:53 +03:00
func DashboardPost ( ctx * context . Context ) {
2021-04-06 22:44:05 +03:00
form := web . GetForm ( ctx ) . ( * forms . AdminDashboardForm )
2020-02-26 01:54:13 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "admin.dashboard" )
ctx . Data [ "PageIsAdminDashboard" ] = true
updateSystemStatus ( )
ctx . Data [ "SysStatus" ] = sysStatus
2014-05-06 21:47:47 +04:00
// Run operation.
2020-05-17 02:31:38 +03:00
if form . Op != "" {
2023-06-29 13:03:20 +03:00
switch form . Op {
case "sync_repo_branches" :
go func ( ) {
if err := repo_service . AddAllRepoBranchesToSyncQueue ( graceful . GetManager ( ) . ShutdownContext ( ) , ctx . Doer . ID ) ; err != nil {
log . Error ( "AddAllRepoBranchesToSyncQueue: %v: %v" , ctx . Doer . ID , err )
}
} ( )
ctx . Flash . Success ( ctx . Tr ( "admin.dashboard.sync_branch.started" ) )
2024-01-24 06:02:04 +03:00
case "sync_repo_tags" :
go func ( ) {
if err := release_service . AddAllRepoTagsToSyncQueue ( graceful . GetManager ( ) . ShutdownContext ( ) ) ; err != nil {
log . Error ( "AddAllRepoTagsToSyncQueue: %v: %v" , ctx . Doer . ID , err )
}
} ( )
ctx . Flash . Success ( ctx . Tr ( "admin.dashboard.sync_tag.started" ) )
2023-06-29 13:03:20 +03:00
default :
task := cron . GetTask ( form . Op )
if task != nil {
go task . RunWithUser ( ctx . Doer , nil )
ctx . Flash . Success ( ctx . Tr ( "admin.dashboard.task.started" , ctx . Tr ( "admin.dashboard." + form . Op ) ) )
} else {
ctx . Flash . Error ( ctx . Tr ( "admin.dashboard.task.unknown" , form . Op ) )
}
2014-05-06 21:47:47 +04:00
}
}
2020-07-05 22:38:03 +03:00
if form . From == "monitor" {
Improve queue & process & stacktrace (#24636)
Although some features are mixed together in this PR, this PR is not
that large, and these features are all related.
Actually there are more than 70 lines are for a toy "test queue", so
this PR is quite simple.
Major features:
1. Allow site admin to clear a queue (remove all items in a queue)
* Because there is no transaction, the "unique queue" could be corrupted
in rare cases, that's unfixable.
* eg: the item is in the "set" but not in the "list", so the item would
never be able to be pushed into the queue.
* Now site admin could simply clear the queue, then everything becomes
correct, the lost items could be re-pushed into queue by future
operations.
3. Split the "admin/monitor" to separate pages
4. Allow to download diagnosis report
* In history, there were many users reporting that Gitea queue gets
stuck, or Gitea's CPU is 100%
* With diagnosis report, maintainers could know what happens clearly
The diagnosis report sample:
[gitea-diagnosis-20230510-192913.zip](https://github.com/go-gitea/gitea/files/11441346/gitea-diagnosis-20230510-192913.zip)
, use "go tool pprof profile.dat" to view the report.
Screenshots:
![image](https://github.com/go-gitea/gitea/assets/2114189/320659b4-2eda-4def-8dc0-5ea08d578063)
![image](https://github.com/go-gitea/gitea/assets/2114189/c5c46fae-9dc0-44ca-8cd3-57beedc5035e)
![image](https://github.com/go-gitea/gitea/assets/2114189/6168a811-42a1-4e64-a263-0617a6c8c4fe)
---------
Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2023-05-11 10:45:47 +03:00
ctx . Redirect ( setting . AppSubURL + "/admin/monitor/cron" )
2020-07-05 22:38:03 +03:00
} else {
ctx . Redirect ( setting . AppSubURL + "/admin" )
}
2014-03-20 15:50:26 +04:00
}
2024-01-10 14:03:23 +03:00
func SelfCheck ( ctx * context . Context ) {
ctx . Data [ "PageIsAdminSelfCheck" ] = true
r , err := db . CheckCollationsDefaultEngine ( )
if err != nil {
ctx . Flash . Error ( fmt . Sprintf ( "CheckCollationsDefaultEngine: %v" , err ) , true )
}
if r != nil {
ctx . Data [ "DatabaseType" ] = setting . Database . Type
ctx . Data [ "DatabaseCheckResult" ] = r
hasProblem := false
if ! r . CollationEquals ( r . DatabaseCollation , r . ExpectedCollation ) {
ctx . Data [ "DatabaseCheckCollationMismatch" ] = true
hasProblem = true
}
if ! r . IsCollationCaseSensitive ( r . DatabaseCollation ) {
ctx . Data [ "DatabaseCheckCollationCaseInsensitive" ] = true
hasProblem = true
}
ctx . Data [ "DatabaseCheckInconsistentCollationColumns" ] = r . InconsistentCollationColumns
hasProblem = hasProblem || len ( r . InconsistentCollationColumns ) > 0
ctx . Data [ "DatabaseCheckHasProblems" ] = hasProblem
}
ctx . HTML ( http . StatusOK , tplSelfCheck )
}
Improve queue & process & stacktrace (#24636)
Although some features are mixed together in this PR, this PR is not
that large, and these features are all related.
Actually there are more than 70 lines are for a toy "test queue", so
this PR is quite simple.
Major features:
1. Allow site admin to clear a queue (remove all items in a queue)
* Because there is no transaction, the "unique queue" could be corrupted
in rare cases, that's unfixable.
* eg: the item is in the "set" but not in the "list", so the item would
never be able to be pushed into the queue.
* Now site admin could simply clear the queue, then everything becomes
correct, the lost items could be re-pushed into queue by future
operations.
3. Split the "admin/monitor" to separate pages
4. Allow to download diagnosis report
* In history, there were many users reporting that Gitea queue gets
stuck, or Gitea's CPU is 100%
* With diagnosis report, maintainers could know what happens clearly
The diagnosis report sample:
[gitea-diagnosis-20230510-192913.zip](https://github.com/go-gitea/gitea/files/11441346/gitea-diagnosis-20230510-192913.zip)
, use "go tool pprof profile.dat" to view the report.
Screenshots:
![image](https://github.com/go-gitea/gitea/assets/2114189/320659b4-2eda-4def-8dc0-5ea08d578063)
![image](https://github.com/go-gitea/gitea/assets/2114189/c5c46fae-9dc0-44ca-8cd3-57beedc5035e)
![image](https://github.com/go-gitea/gitea/assets/2114189/6168a811-42a1-4e64-a263-0617a6c8c4fe)
---------
Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2023-05-11 10:45:47 +03:00
func CronTasks ( ctx * context . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "admin.monitor.cron" )
ctx . Data [ "PageIsAdminMonitorCron" ] = true
2015-08-17 21:19:29 +03:00
ctx . Data [ "Entries" ] = cron . ListTasks ( )
Improve queue & process & stacktrace (#24636)
Although some features are mixed together in this PR, this PR is not
that large, and these features are all related.
Actually there are more than 70 lines are for a toy "test queue", so
this PR is quite simple.
Major features:
1. Allow site admin to clear a queue (remove all items in a queue)
* Because there is no transaction, the "unique queue" could be corrupted
in rare cases, that's unfixable.
* eg: the item is in the "set" but not in the "list", so the item would
never be able to be pushed into the queue.
* Now site admin could simply clear the queue, then everything becomes
correct, the lost items could be re-pushed into queue by future
operations.
3. Split the "admin/monitor" to separate pages
4. Allow to download diagnosis report
* In history, there were many users reporting that Gitea queue gets
stuck, or Gitea's CPU is 100%
* With diagnosis report, maintainers could know what happens clearly
The diagnosis report sample:
[gitea-diagnosis-20230510-192913.zip](https://github.com/go-gitea/gitea/files/11441346/gitea-diagnosis-20230510-192913.zip)
, use "go tool pprof profile.dat" to view the report.
Screenshots:
![image](https://github.com/go-gitea/gitea/assets/2114189/320659b4-2eda-4def-8dc0-5ea08d578063)
![image](https://github.com/go-gitea/gitea/assets/2114189/c5c46fae-9dc0-44ca-8cd3-57beedc5035e)
![image](https://github.com/go-gitea/gitea/assets/2114189/6168a811-42a1-4e64-a263-0617a6c8c4fe)
---------
Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2023-05-11 10:45:47 +03:00
ctx . HTML ( http . StatusOK , tplCron )
2019-11-30 17:40:22 +03:00
}
2023-06-03 17:03:41 +03:00
func MonitorStats ( ctx * context . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "admin.monitor.stats" )
ctx . Data [ "PageIsAdminMonitorStats" ] = true
2024-02-23 00:25:19 +03:00
modelStats := activities_model . GetStatistic ( ctx ) . Counter
stats := map [ string ] any { }
// To avoid manually converting the values of the stats struct to an map,
// and to avoid using JSON to do this for us (JSON encoder converts numbers to
// scientific notation). Use reflect to convert the struct to an map.
rv := reflect . ValueOf ( modelStats )
for i := 0 ; i < rv . NumField ( ) ; i ++ {
field := rv . Field ( i )
// Preserve old behavior, do not show arrays that are empty.
if field . Kind ( ) == reflect . Slice && field . Len ( ) == 0 {
2023-06-03 17:03:41 +03:00
continue
}
2024-02-23 00:25:19 +03:00
stats [ rv . Type ( ) . Field ( i ) . Name ] = field . Interface ( )
2023-06-03 17:03:41 +03:00
}
2024-02-23 00:25:19 +03:00
ctx . Data [ "Stats" ] = stats
2023-06-03 17:03:41 +03:00
ctx . HTML ( http . StatusOK , tplStats )
}