package utils
import (
"fmt"
"html/template"
"runtime"
"strings"
"time"
"git.sharkk.net/Sky/Moonshark/core/config"
"git.sharkk.net/Sky/Moonshark/core/metadata"
)
// ComponentStats holds stats from various system components
type ComponentStats struct {
RouteCount int // Number of routes
BytecodeBytes int64 // Total size of bytecode in bytes
ModuleCount int // Number of loaded modules
}
// SystemStats represents system statistics for debugging
type SystemStats struct {
Timestamp time.Time
GoVersion string
GoRoutines int
Memory runtime.MemStats
Components ComponentStats
Version string
Config *config.Config // Configuration information
}
// CollectSystemStats gathers basic system statistics
func CollectSystemStats(cfg *config.Config) SystemStats {
var stats SystemStats
var mem runtime.MemStats
// Collect basic system info
stats.Timestamp = time.Now()
stats.GoVersion = runtime.Version()
stats.GoRoutines = runtime.NumGoroutine()
stats.Version = metadata.Version
stats.Config = cfg
// Collect memory stats
runtime.ReadMemStats(&mem)
stats.Memory = mem
return stats
}
// DebugStatsPage generates an HTML debug stats page
func DebugStatsPage(stats SystemStats) string {
const debugTemplate = `
Moonshark
Moonshark
Generated at: {{.Timestamp.Format "2006-01-02 15:04:05"}}
System
Go Version | {{.GoVersion}} |
Goroutines | {{.GoRoutines}} |
Memory
Allocated | {{ByteCount .Memory.Alloc}} |
Total Allocated | {{ByteCount .Memory.TotalAlloc}} |
System Memory | {{ByteCount .Memory.Sys}} |
GC Cycles | {{.Memory.NumGC}} |
LuaRunner
Interpreter | LuaJIT 2.1 (Lua 5.1) |
Active Routes | {{.Components.RouteCount}} |
Bytecode Size | {{ByteCount .Components.BytecodeBytes}} |
Loaded Modules | {{.Components.ModuleCount}} |
Config
Port | {{.Config.Port}} |
Debug Mode | {{.Config.Debug}} |
Log Level | {{.Config.LogLevel}} |
Routes Directory | {{.Config.RoutesDir}} |
Static Directory | {{.Config.StaticDir}} |
Override Directory | {{.Config.OverrideDir}} |
Buffer Size | {{.Config.BufferSize}} |
HTTP Logging | {{.Config.HTTPLoggingEnabled}} |
Lib Directories | {{range .Config.LibDirs}}{{.}} {{end}} |
Watch Routes | {{index .Config.Watchers "routes"}} |
Watch Static | {{index .Config.Watchers "static"}} |
Watch Modules | {{index .Config.Watchers "modules"}} |
`
// Create a template function map
funcMap := template.FuncMap{
"ByteCount": func(b interface{}) string {
var bytes uint64
// Convert the value to uint64
switch v := b.(type) {
case uint64:
bytes = v
case int64:
bytes = uint64(v)
case int:
bytes = uint64(v)
default:
return "Unknown"
}
const unit = 1024
if bytes < unit {
return fmt.Sprintf("%d B", bytes)
}
div, exp := uint64(unit), 0
for n := bytes / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
},
}
// Parse the template
tmpl, err := template.New("debug").Funcs(funcMap).Parse(debugTemplate)
if err != nil {
return fmt.Sprintf("Error parsing template: %v", err)
}
// Execute the template
var output strings.Builder
if err := tmpl.Execute(&output, stats); err != nil {
return fmt.Sprintf("Error executing template: %v", err)
}
return output.String()
}