This commit is contained in:
ponzischeme89
2026-08-19 14:25:44 +12:00
parent 2b43b9ef12
commit 590e069366
83 changed files with 8948 additions and 1266 deletions
+123 -3
View File
@@ -116,9 +116,9 @@ func adminPreviewData() map[string]any {
}
return map[string]any{
"/admin/api/status": status,
"/admin/api/runtime": map[string]any{"goroutines": 84, "heapInuse": 41943040,
"sys": 92274688, "numGc": 311, "nextGc": 62914560, "gomaxprocs": 4},
"/admin/api/status": status,
"/admin/api/runtime": adminPreviewRuntime(now),
"/admin/api/runtime/goroutines": adminPreviewGoroutines(now),
"/admin/api/accounts": map[string]any{
"accounts": []any{
map[string]any{"userId": "u-1", "username": "matt", "onboardingCompleted": true,
@@ -191,3 +191,123 @@ func adminPreviewData() map[string]any {
},
}
}
// A gateway with a mild, deliberate upward drift in both goroutines and heap, so the
// preview shows what a trend that has earned a "watch" actually looks like — the flat case
// is the one that draws itself.
func adminPreviewRuntime(now time.Time) map[string]any {
const points = 90
samples := make([]any, 0, points)
for index := 0; index < points; index++ {
at := now.Add(-time.Duration(points-1-index) * time.Minute)
samples = append(samples, map[string]any{
"at": at.Format(time.RFC3339),
"goroutines": 62 + index/4 + index%3,
"heapInuse": 33_000_000 + index*90_000,
"sys": 92_274_688,
"numGc": 220 + index,
})
}
trend := func(direction string, perHour, first, latest, low, high float64) map[string]any {
return map[string]any{
"direction": direction, "perHour": perHour, "first": first, "latest": latest,
"min": low, "max": high, "spanSeconds": float64((points - 1) * 60), "points": points,
}
}
return map[string]any{
"at": now.Format(time.RFC3339), "uptimeSeconds": 61_240.0,
"goroutines": 84, "gomaxprocs": 4, "threads": 17, "goVersion": "go1.26",
"memory": map[string]any{
"heapAlloc": 39_000_000, "heapInuse": 41_943_040, "heapIdle": 24_000_000,
"heapReleased": 8_000_000, "stackInuse": 1_800_000, "sys": 223_100_000,
"nextGc": 62_914_560, "numGc": 311, "pauseTotalMs": 812.4, "pauseRecentMs": 1.9,
"memoryLimit": 402_653_184, "configuredLimit": "384MiB",
"heapShare": 0.104, "gcPerHour": 60.0,
},
"workers": []any{
map[string]any{"name": "HTTP listener", "component": "HTTP server",
"state": "running", "started": now.Add(-17 * time.Hour).Format(time.RFC3339), "starts": 1},
map[string]any{"name": "Emby health probe", "component": "Emby",
"state": "running", "started": now.Add(-17 * time.Hour).Format(time.RFC3339), "starts": 1},
map[string]any{"name": "Library ingest", "component": "Library sync",
"state": "running", "started": now.Add(-17 * time.Hour).Format(time.RFC3339), "starts": 1},
map[string]any{"name": "Task scheduler", "component": "Scheduled jobs",
"state": "running", "started": now.Add(-17 * time.Hour).Format(time.RFC3339), "starts": 1},
map[string]any{"name": "Startup library sync", "component": "Library sync",
"state": "finished", "started": now.Add(-17 * time.Hour).Format(time.RFC3339),
"stopped": now.Add(-17 * time.Hour).Add(4 * time.Minute).Format(time.RFC3339), "starts": 1},
},
"process": map[string]any{"pid": 1, "cpuSeconds": 431.8, "cpuPercent": 3.4,
"cpuKnown": true, "openFiles": 41, "openSockets": 22, "fileLimit": 1048576,
"filesKnown": true},
"samples": samples,
"goroutineTrend": trend("rising", 14, 62, 84, 62, 86),
"heapTrend": trend("rising", 5_400_000, 33_000_000, 41_943_040, 33_000_000, 41_943_040),
"reservedTrend": trend("steady", 0, 92_274_688, 92_274_688, 92_274_688, 92_274_688),
"sampleEverySeconds": 60.0,
"health": map[string]any{
"level": "watch",
"summary": "2 things to look at, in Goroutines and Memory.",
"areas": []any{"Goroutines", "Memory"},
"notes": []any{
map[string]any{"level": "watch", "area": "Memory",
"message": "Heap in use has risen by about 5.1 MB an hour over the last 1.5 hours. If it does not fall after a collection, something is holding on to it."},
map[string]any{"level": "watch", "area": "Goroutines",
"message": "Goroutines have risen by about 14 an hour over the last 1.5 hours, from 62 to 84. Open the breakdown to see which component they belong to."},
},
},
}
}
func adminPreviewGoroutines(now time.Time) map[string]any {
category := func(key, label, description string, count int, states []any) map[string]any {
return map[string]any{"category": key, "label": label, "description": description,
"count": count, "states": states}
}
state := func(name string, count int) any {
return map[string]any{"state": name, "count": count}
}
return map[string]any{
"at": now.Format(time.RFC3339), "total": 84, "collectedInMs": 6.2, "dumpBytes": 98_304,
"categories": []any{
category("running", "Running", "On a processor now, or queued for one.", 3,
[]any{state("running", 2), state("runnable", 1)}),
category("io", "Network / I/O",
"Waiting on a network read or write — Emby, Postgres, Redis, or a television.", 26,
[]any{state("IO wait", 26)}),
category("waiting", "Waiting / idle",
"Parked waiting for work or for a lock. Idle, and costing almost nothing.", 41,
[]any{state("select", 29), state("chan receive", 9), state("semacquire", 3)}),
category("timers", "Timers / scheduled work", "Asleep until a scheduled time.", 8,
[]any{state("sleep", 8)}),
category("runtime", "Go runtime / collection",
"The Go runtime's own housekeeping. This handful is always present.", 6,
[]any{state("GC worker (idle)", 4), state("finalizer wait", 1), state("force gc (idle)", 1)}),
},
"components": []any{
map[string]any{"component": "HTTP server", "count": 24, "longestWaitMinutes": 3},
map[string]any{"component": "Database pool", "count": 18, "longestWaitMinutes": 940},
map[string]any{"component": "Emby", "count": 11, "longestWaitMinutes": 2},
map[string]any{"component": "Gateway API", "count": 9, "longestWaitMinutes": 0},
map[string]any{"component": "Redis", "count": 8, "longestWaitMinutes": 940},
map[string]any{"component": "Library sync", "count": 6, "longestWaitMinutes": 940},
map[string]any{"component": "Go runtime", "count": 6, "longestWaitMinutes": 0},
map[string]any{"component": "Scheduled jobs", "count": 2, "longestWaitMinutes": 940},
},
"groups": []any{
map[string]any{"count": 24, "component": "HTTP server", "category": "io",
"state": "IO wait", "function": "net/http.(*conn).serve",
"file": "/usr/local/go/src/net/http/server.go:2092",
"createdBy": "net/http.(*Server).Serve", "longestWaitMinutes": 3},
map[string]any{"count": 18, "component": "Database pool", "category": "waiting",
"state": "select", "function": "github.com/jackc/puddle/v2.(*Pool).acquire",
"file": "/root/go/pkg/mod/github.com/jackc/puddle/v2/pool.go:481",
"createdBy": "github.com/jackc/pgx/v5/pgxpool.NewWithConfig", "longestWaitMinutes": 940},
map[string]any{"count": 6, "component": "Library sync", "category": "waiting",
"state": "chan receive", "function": "memby/server/internal/library.(*Ingester).Run",
"file": "/app/internal/library/ingest.go:118",
"createdBy": "main.run", "longestWaitMinutes": 940},
},
"groupsTotal": 21,
}
}