mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-05-12 22:10:25 +00:00
feat(i18n): translate system status data units in runtime (#10358)
Followup to https://codeberg.org/forgejo/forgejo/pulls/2528 Instead of storing translated strings in memory, store raw numbers and translate at template rendering time. Our implementation of `TrSize` is not very efficient and is more expensive than just the underlying `humanize.IBytes`, but for me on localhost both ways render response to HTMLX's request to `/admin/system_status` in 0-1 ms. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10358 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Co-authored-by: 0ko <0ko@noreply.codeberg.org> Co-committed-by: 0ko <0ko@noreply.codeberg.org>
This commit is contained in:
parent
7cfa6ef670
commit
2bde157a0d
3 changed files with 79 additions and 58 deletions
|
|
@ -43,36 +43,36 @@ var sysStatus struct {
|
|||
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)
|
||||
MemAllocated int64 // bytes allocated and still in use
|
||||
MemTotal int64 // bytes allocated (even if freed)
|
||||
MemSys int64 // 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
|
||||
HeapAlloc int64 // bytes allocated and still in use
|
||||
HeapSys int64 // bytes obtained from system
|
||||
HeapIdle int64 // bytes in idle spans
|
||||
HeapInuse int64 // bytes in non-idle span
|
||||
HeapReleased int64 // 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
|
||||
StackInuse int64 // bootstrap stacks
|
||||
StackSys int64
|
||||
MSpanInuse int64 // mspan structures
|
||||
MSpanSys int64
|
||||
MCacheInuse int64 // mcache structures
|
||||
MCacheSys int64
|
||||
BuckHashSys int64 // profiling bucket hash table
|
||||
GCSys int64 // GC metadata
|
||||
OtherSys int64 // other system allocations
|
||||
|
||||
// Garbage collector statistics.
|
||||
NextGC string // next run in HeapAlloc time (bytes)
|
||||
NextGC int64 // next run in HeapAlloc time (bytes)
|
||||
LastGCTime string // last run time
|
||||
PauseTotalNs string
|
||||
PauseNs string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
|
||||
|
|
@ -86,31 +86,31 @@ func updateSystemStatus() {
|
|||
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.MemAllocated = int64(m.Alloc)
|
||||
sysStatus.MemTotal = int64(m.TotalAlloc)
|
||||
sysStatus.MemSys = 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.HeapAlloc = int64(m.HeapAlloc)
|
||||
sysStatus.HeapSys = int64(m.HeapSys)
|
||||
sysStatus.HeapIdle = int64(m.HeapIdle)
|
||||
sysStatus.HeapInuse = int64(m.HeapInuse)
|
||||
sysStatus.HeapReleased = 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.StackInuse = int64(m.StackInuse)
|
||||
sysStatus.StackSys = int64(m.StackSys)
|
||||
sysStatus.MSpanInuse = int64(m.MSpanInuse)
|
||||
sysStatus.MSpanSys = int64(m.MSpanSys)
|
||||
sysStatus.MCacheInuse = int64(m.MCacheInuse)
|
||||
sysStatus.MCacheSys = int64(m.MCacheSys)
|
||||
sysStatus.BuckHashSys = int64(m.BuckHashSys)
|
||||
sysStatus.GCSys = int64(m.GCSys)
|
||||
sysStatus.OtherSys = int64(m.OtherSys)
|
||||
|
||||
sysStatus.NextGC = base.FileSize(int64(m.NextGC))
|
||||
sysStatus.NextGC = int64(m.NextGC)
|
||||
sysStatus.LastGCTime = time.Unix(0, int64(m.LastGC)).Format(time.RFC3339)
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
<dd>{{.SysStatus.NumGoroutine}}</dd>
|
||||
<div class="divider"></div>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.current_memory_usage"}}</dt>
|
||||
<dd>{{.SysStatus.MemAllocated}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.MemAllocated}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.total_memory_allocated"}}</dt>
|
||||
<dd>{{.SysStatus.MemTotal}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.MemTotal}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.memory_obtained"}}</dt>
|
||||
<dd>{{.SysStatus.MemSys}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.MemSys}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.pointer_lookup_times"}}</dt>
|
||||
<dd>{{.SysStatus.Lookups}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.memory_allocate_times"}}</dt>
|
||||
|
|
@ -18,39 +18,39 @@
|
|||
<dd>{{.SysStatus.MemFrees}}</dd>
|
||||
<div class="divider"></div>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.current_heap_usage"}}</dt>
|
||||
<dd>{{.SysStatus.HeapAlloc}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.HeapAlloc}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.heap_memory_obtained"}}</dt>
|
||||
<dd>{{.SysStatus.HeapSys}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.HeapSys}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.heap_memory_idle"}}</dt>
|
||||
<dd>{{.SysStatus.HeapIdle}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.HeapIdle}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.heap_memory_in_use"}}</dt>
|
||||
<dd>{{.SysStatus.HeapInuse}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.HeapInuse}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.heap_memory_released"}}</dt>
|
||||
<dd>{{.SysStatus.HeapReleased}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.HeapReleased}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.heap_objects"}}</dt>
|
||||
<dd>{{.SysStatus.HeapObjects}}</dd>
|
||||
<div class="divider"></div>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.bootstrap_stack_usage"}}</dt>
|
||||
<dd>{{.SysStatus.StackInuse}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.StackInuse}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.stack_memory_obtained"}}</dt>
|
||||
<dd>{{.SysStatus.StackSys}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.StackSys}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.mspan_structures_usage"}}</dt>
|
||||
<dd>{{.SysStatus.MSpanInuse}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.MSpanInuse}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.mspan_structures_obtained"}}</dt>
|
||||
<dd>{{.SysStatus.MSpanSys}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.MSpanSys}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.mcache_structures_usage"}}</dt>
|
||||
<dd>{{.SysStatus.MCacheInuse}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.MCacheInuse}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.mcache_structures_obtained"}}</dt>
|
||||
<dd>{{.SysStatus.MCacheSys}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.MCacheSys}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.profiling_bucket_hash_table_obtained"}}</dt>
|
||||
<dd>{{.SysStatus.BuckHashSys}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.BuckHashSys}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.gc_metadata_obtained"}}</dt>
|
||||
<dd>{{.SysStatus.GCSys}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.GCSys}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.other_system_allocation_obtained"}}</dt>
|
||||
<dd>{{.SysStatus.OtherSys}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.OtherSys}}</dd>
|
||||
<div class="divider"></div>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.next_gc_recycle"}}</dt>
|
||||
<dd>{{.SysStatus.NextGC}}</dd>
|
||||
<dd>{{ctx.Locale.TrSize .SysStatus.NextGC}}</dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.last_gc_time"}}</dt>
|
||||
<dd><relative-time format="duration" datetime="{{.SysStatus.LastGCTime}}">{{.SysStatus.LastGCTime}}</relative-time></dd>
|
||||
<dt>{{ctx.Locale.Tr "admin.dashboard.total_gc_pause"}}</dt>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import (
|
|||
"forgejo.org/modules/test"
|
||||
"forgejo.org/modules/translation"
|
||||
"forgejo.org/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var commonEntries = []string{
|
||||
|
|
@ -33,7 +35,8 @@ var sshEntries = []string{
|
|||
"resync_all_sshprincipals",
|
||||
}
|
||||
|
||||
func testAssertAdminDashboardEntries(t *testing.T, page *HTMLDoc, locale translation.Locale, expectSSH bool) {
|
||||
// Check cron options on /admin, including those that are available conditionally
|
||||
func testAssertAdminDashboardOptions(t *testing.T, page *HTMLDoc, locale translation.Locale, expectSSH bool) {
|
||||
for _, entry := range commonEntries {
|
||||
page.AssertSelection(t, page.FindByText("table tr td", locale.TrString(fmt.Sprintf("admin.dashboard.%s", entry))), true)
|
||||
page.AssertSelection(t, page.Find(fmt.Sprintf("table tr td button[value='%s']", entry)), true)
|
||||
|
|
@ -56,7 +59,7 @@ func TestAdminDashboard(t *testing.T) {
|
|||
defer test.MockVariableValue(&setting.SSH.Disabled, true)()
|
||||
|
||||
page := NewHTMLParser(t, session.MakeRequest(t, NewRequest(t, "GET", url), http.StatusOK).Body)
|
||||
testAssertAdminDashboardEntries(t, page, locale, false)
|
||||
testAssertAdminDashboardOptions(t, page, locale, false)
|
||||
})
|
||||
|
||||
t.Run("SSH enabled, but built-in", func(t *testing.T) {
|
||||
|
|
@ -65,7 +68,7 @@ func TestAdminDashboard(t *testing.T) {
|
|||
defer test.MockVariableValue(&setting.SSH.StartBuiltinServer, true)()
|
||||
|
||||
page := NewHTMLParser(t, session.MakeRequest(t, NewRequest(t, "GET", url), http.StatusOK).Body)
|
||||
testAssertAdminDashboardEntries(t, page, locale, false)
|
||||
testAssertAdminDashboardOptions(t, page, locale, false)
|
||||
})
|
||||
|
||||
t.Run("SSH enabled and external", func(t *testing.T) {
|
||||
|
|
@ -74,6 +77,24 @@ func TestAdminDashboard(t *testing.T) {
|
|||
defer test.MockVariableValue(&setting.SSH.StartBuiltinServer, false)()
|
||||
|
||||
page := NewHTMLParser(t, session.MakeRequest(t, NewRequest(t, "GET", url), http.StatusOK).Body)
|
||||
testAssertAdminDashboardEntries(t, page, locale, true)
|
||||
testAssertAdminDashboardOptions(t, page, locale, true)
|
||||
})
|
||||
|
||||
t.Run("System status", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// Check data units translations in the System status table
|
||||
selector := ".table[hx-get='/admin/system_status'] > dl > dd"
|
||||
// ...in English
|
||||
page := NewHTMLParser(t, session.MakeRequest(t, NewRequest(t, "GET", url), http.StatusOK).Body)
|
||||
assert.Contains(t, page.Find(selector).Text(), "MiB")
|
||||
|
||||
// ...in another language
|
||||
lang := session.GetCookie("lang")
|
||||
lang.Value = "ru-RU"
|
||||
session.SetCookie(lang)
|
||||
|
||||
page = NewHTMLParser(t, session.MakeRequest(t, NewRequest(t, "GET", url), http.StatusOK).Body)
|
||||
assert.Contains(t, page.Find(selector).Text(), "МиБ")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue