From a79b1f057fe10bc2693a12348c48ca1070932d2c Mon Sep 17 00:00:00 2001 From: dmabry Date: Fri, 15 May 2026 16:08:12 -0500 Subject: [PATCH] Perf: cache dashboard HTML template at package init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dashboard template was parsed on every HTTP request via template.New().Funcs().Parse() — unnecessary CPU and allocation overhead. Move template parsing to a package-level variable initialized once at startup. DashboardHandler now reuses the pre-parsed template. Also simplified error handling: parse failure logs a warning at init time and returns an empty template (server still starts); execute failures log per-request as before. --- stats/collector.go | 51 +++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/stats/collector.go b/stats/collector.go index 76bed1b..7572481 100644 --- a/stats/collector.go +++ b/stats/collector.go @@ -154,6 +154,35 @@ func (sc *Collector) HistoryHandler(w http.ResponseWriter, r *http.Request) { } } +// dashboardTmpl is the pre-parsed dashboard HTML template with custom +// functions registered. Parsed once at package init and reused for every +// request to avoid repeated template parsing overhead. +var dashboardTmpl = func() *template.Template { + t, err := template.New("dashboard").Funcs(template.FuncMap{ + "formatBytes": func(bytes uint64) string { + if bytes == 0 { + return "0 B" + } + const unit = 1024 + const units = "BKMG" + i := 0 + f := float64(bytes) + for f >= unit && i < len(units)-1 { + f /= unit + i++ + } + return fmt.Sprintf("%.1f %sB", f, string(units[i])) + }, + }).Parse(templates.DashboardTpl) + if err != nil { + log.Printf("[WARN] Failed to parse dashboard template: %v", err) + // Return a no-op template so the server still starts; + // DashboardHandler will log the nil-template error per-request. + return template.New("dashboard") + } + return t +}() + // DashboardHandler renders the dashboard HTML page with current stats. func (sc *Collector) DashboardHandler(w http.ResponseWriter, r *http.Request) { sc.mu.RLock() @@ -190,29 +219,9 @@ func (sc *Collector) DashboardHandler(w http.ResponseWriter, r *http.Request) { Uptime: uptimeStr, } - t, err := template.New("dashboard").Funcs(template.FuncMap{ - "formatBytes": func(bytes uint64) string { - if bytes == 0 { - return "0 B" - } - const unit = 1024 - const units = "BKMG" - i := 0 - f := float64(bytes) - for f >= unit && i < len(units)-1 { - f /= unit - i++ - } - return fmt.Sprintf("%.1f %sB", f, string(units[i])) - }, - }).Parse(templates.DashboardTpl) + err := dashboardTmpl.Execute(w, d) if err != nil { log.Printf("Web server had issue: %v\n", err) - } else { - err = t.Execute(w, d) - if err != nil { - log.Printf("Web server had issue: %v\n", err) - } } }