this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: live stats

+67 -3
+6 -3
web/server.go
··· 84 84 } 85 85 render(w, "repos", struct { 86 86 Active string 87 + Stats Stats 87 88 Query query 88 89 Repos []store.Repo 89 90 Languages []string 90 - }{"repos", q, repos, langs}) 91 + }{"repos", collectStats(), q, repos, langs}) 91 92 } 92 93 } 93 94 ··· 100 101 } 101 102 render(w, "knots", struct { 102 103 Active string 104 + Stats Stats 103 105 Knots []store.KnotEntry 104 - }{"knots", knots}) 106 + }{"knots", collectStats(), knots}) 105 107 } 106 108 } 107 109 ··· 130 132 } 131 133 render(w, "handles", struct { 132 134 Active string 135 + Stats Stats 133 136 Handles []store.HandleEntry 134 - }{"handles", handles}) 137 + }{"handles", collectStats(), handles}) 135 138 } 136 139 } 137 140
+49
web/stats.go
··· 1 + package web 2 + 3 + import ( 4 + "runtime" 5 + "syscall" 6 + "time" 7 + ) 8 + 9 + // Stats is a small snapshot of process-level resource usage rendered into 10 + // every page footer. Pure stdlib — runtime for Go heap, getrusage for OS-level 11 + // RSS and CPU time. 12 + type Stats struct { 13 + Goroutines int 14 + HeapAllocMB float64 // Go heap currently in use 15 + SysMB float64 // total bytes obtained from the OS by the runtime 16 + GCRuns uint32 17 + RSSMB float64 // resident set size (peak since start) 18 + CPUSec float64 // user + system CPU seconds since start 19 + Uptime time.Duration // process uptime, rounded to seconds 20 + } 21 + 22 + var startTime = time.Now() 23 + 24 + func collectStats() Stats { 25 + var ms runtime.MemStats 26 + runtime.ReadMemStats(&ms) 27 + 28 + var ru syscall.Rusage 29 + _ = syscall.Getrusage(syscall.RUSAGE_SELF, &ru) 30 + 31 + // ru.Maxrss is bytes on Darwin/BSD, kilobytes on Linux. 32 + rssBytes := int64(ru.Maxrss) 33 + if runtime.GOOS == "linux" { 34 + rssBytes *= 1024 35 + } 36 + 37 + cpuSec := float64(ru.Utime.Sec) + float64(ru.Utime.Usec)/1e6 + 38 + float64(ru.Stime.Sec) + float64(ru.Stime.Usec)/1e6 39 + 40 + return Stats{ 41 + Goroutines: runtime.NumGoroutine(), 42 + HeapAllocMB: float64(ms.HeapAlloc) / 1024 / 1024, 43 + SysMB: float64(ms.Sys) / 1024 / 1024, 44 + GCRuns: ms.NumGC, 45 + RSSMB: float64(rssBytes) / 1024 / 1024, 46 + CPUSec: cpuSec, 47 + Uptime: time.Since(startTime).Round(time.Second), 48 + } 49 + }
+12
web/templates/layout.html
··· 29 29 td.num.has { color: inherit; } 30 30 td.desc { color: #aaa; max-width: 480px; word-break: break-word; } 31 31 .empty { padding: 3em; text-align: center; color: #888; border: 1px dashed currentColor; opacity: .4; } 32 + footer.stats { margin-top: 2em; padding-top: .5em; border-top: 1px solid color-mix(in srgb, currentColor 15%, transparent); color: #888; font-size: 12px; display: flex; gap: 1em; flex-wrap: wrap; } 33 + footer.stats span { white-space: nowrap; } 32 34 </style> 33 35 </head> 34 36 <body> ··· 41 43 {{end}} 42 44 43 45 {{define "foot"}} 46 + {{with .Stats}} 47 + <footer class="stats"> 48 + <span>uptime {{.Uptime}}</span> 49 + <span>goroutines {{.Goroutines}}</span> 50 + <span>heap {{printf "%.1f" .HeapAllocMB}} MB</span> 51 + <span>rss {{printf "%.1f" .RSSMB}} MB</span> 52 + <span>cpu {{printf "%.1f" .CPUSec}}s</span> 53 + <span>gc {{.GCRuns}}</span> 54 + </footer> 55 + {{end}} 44 56 </body> 45 57 </html> 46 58 {{end}}