96 lines
2.1 KiB
Go
96 lines
2.1 KiB
Go
package stats
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"time"
|
|
)
|
|
|
|
type RuntimeStats struct {
|
|
TotalAlloc uint64
|
|
Mallocs uint64
|
|
NumGC uint32
|
|
AllocDelta uint64
|
|
MallocsDelta uint64
|
|
GCDelta uint32
|
|
}
|
|
|
|
type RuntimeCollector struct {
|
|
startStats runtime.MemStats
|
|
memPath string
|
|
}
|
|
|
|
func NewRuntimeCollector(memPath string) *RuntimeCollector {
|
|
var stats runtime.MemStats
|
|
runtime.ReadMemStats(&stats)
|
|
|
|
return &RuntimeCollector{
|
|
startStats: stats,
|
|
memPath: memPath,
|
|
}
|
|
}
|
|
|
|
func (rc *RuntimeCollector) Collect() RuntimeStats {
|
|
var current runtime.MemStats
|
|
runtime.ReadMemStats(¤t)
|
|
|
|
return RuntimeStats{
|
|
TotalAlloc: current.TotalAlloc,
|
|
Mallocs: current.Mallocs,
|
|
NumGC: current.NumGC,
|
|
AllocDelta: current.TotalAlloc - rc.startStats.TotalAlloc,
|
|
MallocsDelta: current.Mallocs - rc.startStats.Mallocs,
|
|
GCDelta: current.NumGC - rc.startStats.NumGC,
|
|
}
|
|
}
|
|
|
|
func (rc *RuntimeCollector) WriteStats() error {
|
|
stats := rc.Collect()
|
|
timestamp := time.Now().Format(time.RFC3339Nano)
|
|
|
|
// Check if file exists
|
|
fileExists := false
|
|
if _, err := os.Stat(rc.memPath); err == nil {
|
|
fileExists = true
|
|
}
|
|
|
|
// Open in append mode
|
|
file, err := os.OpenFile(rc.memPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open mem.csv: %w", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
writer := csv.NewWriter(file)
|
|
|
|
// Write header if new file
|
|
if !fileExists {
|
|
header := []string{
|
|
"timestamp", "total_alloc_bytes", "mallocs", "gc_cycles",
|
|
"alloc_delta", "mallocs_delta", "gc_delta",
|
|
}
|
|
if err := writer.Write(header); err != nil {
|
|
return fmt.Errorf("failed to write mem.csv header: %w", err)
|
|
}
|
|
}
|
|
|
|
// Write data row
|
|
row := []string{
|
|
timestamp,
|
|
fmt.Sprintf("%d", stats.TotalAlloc),
|
|
fmt.Sprintf("%d", stats.Mallocs),
|
|
fmt.Sprintf("%d", stats.NumGC),
|
|
fmt.Sprintf("%d", stats.AllocDelta),
|
|
fmt.Sprintf("%d", stats.MallocsDelta),
|
|
fmt.Sprintf("%d", stats.GCDelta),
|
|
}
|
|
if err := writer.Write(row); err != nil {
|
|
return fmt.Errorf("failed to write mem.csv row: %w", err)
|
|
}
|
|
|
|
writer.Flush()
|
|
return writer.Error()
|
|
}
|