package httpapp import ( "encoding/json" "log" "net/http" "time" ) func (a *App) handleDashboard(w http.ResponseWriter, r *http.Request) { data := map[string]any{ "Title": "Dashboard", "Build": map[string]string{ "version": "v0.1.0-dev", }, } a.render(w, "dashboard.html", data) } func (a *App) handleHealthz(w http.ResponseWriter, r *http.Request) { id, _ := r.Context().Value(requestIDKey).(string) resp := map[string]any{ "status": "ok", "ts": id, // request ID for correlation } writeJSON(w, http.StatusOK, resp) } func (a *App) handleMetrics(w http.ResponseWriter, r *http.Request) { // Collect real-time metrics // ZFS metrics pools, _ := a.zfs.ListPools() datasets, _ := a.zfs.ListDatasets("") zvols, _ := a.zfs.ListZVOLs("") snapshots, _ := a.zfs.ListSnapshots("") a.metricsCollector.UpdateZFSMetrics(pools, datasets, zvols, snapshots) // Service metrics smbShares := a.smbStore.List() nfsExports := a.nfsStore.List() iscsiTargets := a.iscsiStore.List() smbStatus, _ := a.smbService.GetStatus() nfsStatus, _ := a.nfsService.GetStatus() iscsiStatus, _ := a.iscsiService.GetStatus() a.metricsCollector.UpdateServiceMetrics( len(smbShares), len(nfsExports), len(iscsiTargets), smbStatus, nfsStatus, iscsiStatus, ) // Job metrics allJobs := a.jobManager.List("") running := 0 completed := 0 failed := 0 for _, job := range allJobs { switch job.Status { case "running": running++ case "completed": completed++ case "failed": failed++ } } a.metricsCollector.UpdateJobMetrics(len(allJobs), running, completed, failed) // Update uptime a.metricsCollector.SetUptime(int64(time.Since(a.startTime).Seconds())) // Output Prometheus format w.Header().Set("Content-Type", "text/plain; version=0.0.4") w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte(a.metricsCollector.Collect())) } func (a *App) render(w http.ResponseWriter, name string, data any) { w.Header().Set("Content-Type", "text/html; charset=utf-8") // base.html defines layout; dashboard.html will invoke it via template inheritance style. if err := a.tmpl.ExecuteTemplate(w, name, data); err != nil { log.Printf("template render error: %v", err) http.Error(w, "template render error", http.StatusInternalServerError) return } } func writeJSON(w http.ResponseWriter, code int, v any) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(code) if err := json.NewEncoder(w).Encode(v); err != nil { log.Printf("json encode error: %v", err) } }