Files
kandev/apps/backend/internal/debug/export.go
T
2026-05-16 20:07:57 +01:00

76 lines
2.0 KiB
Go

package debug
import (
"net/http"
"runtime"
"time"
"github.com/gin-gonic/gin"
"github.com/kandev/kandev/internal/common/logger"
"github.com/kandev/kandev/internal/common/logger/buffer"
)
var startTime = time.Now()
// ExportMetadata contains system runtime information for debugging.
type ExportMetadata struct {
UptimeSeconds float64 `json:"uptime_seconds"`
Version string `json:"version"`
Commit string `json:"commit"`
GoVersion string `json:"go_version"`
OS string `json:"os"`
Arch string `json:"arch"`
Goroutines int `json:"goroutines"`
HeapAllocMB float64 `json:"heap_alloc_mb"`
CapturedAt string `json:"captured_at"`
}
// ExportResponse is the JSON response for the debug export endpoint.
type ExportResponse struct {
Metadata ExportMetadata `json:"metadata"`
Logs []buffer.Entry `json:"logs"`
}
// RegisterExportRoute registers GET /api/v1/system/debug/export.
func RegisterExportRoute(router *gin.Engine, version, commit string, _ *logger.Logger) {
api := router.Group("/api/v1/system/debug")
api.GET("/export", handleExport(version, commit))
}
func handleExport(version, commit string) gin.HandlerFunc {
return func(c *gin.Context) {
logs := buffer.Default().Snapshot()
// Optional level filter.
if level := c.Query("level"); level != "" {
filtered := make([]buffer.Entry, 0, len(logs))
for _, e := range logs {
if e.Level == level {
filtered = append(filtered, e)
}
}
logs = filtered
}
var mem runtime.MemStats
runtime.ReadMemStats(&mem)
resp := ExportResponse{
Metadata: ExportMetadata{
UptimeSeconds: time.Since(startTime).Seconds(),
Version: version,
Commit: commit,
GoVersion: runtime.Version(),
OS: runtime.GOOS,
Arch: runtime.GOARCH,
Goroutines: runtime.NumGoroutine(),
HeapAllocMB: float64(mem.HeapAlloc) / (1024 * 1024),
CapturedAt: time.Now().UTC().Format(time.RFC3339),
},
Logs: logs,
}
c.JSON(http.StatusOK, resp)
}
}