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()
}