forgejo-runner-optimiser/internal/summary/writer.go
Manuel Ganter c5c872a373
All checks were successful
ci / build (push) Successful in 1m56s
fix(output): correct JSON serialization of top process metrics
slog.Any() does not properly serialize slices of slog.Group() attributes,
resulting in broken output like {"Key":"","Value":{}}. Fixed by passing
structs with JSON tags directly to slog.Any() instead.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 11:00:34 +01:00

61 lines
1.7 KiB
Go

// ABOUTME: Emits a RunSummary as a structured log entry via slog.
// ABOUTME: Follows the same slog pattern as internal/output/logger.go for consistency.
package summary
import (
"io"
"log/slog"
)
// SummaryWriter outputs a RunSummary using structured logging
type SummaryWriter struct {
logger *slog.Logger
}
// NewSummaryWriter creates a writer that emits summaries to the given output in the given format
func NewSummaryWriter(output io.Writer, format string) *SummaryWriter {
opts := &slog.HandlerOptions{Level: slog.LevelInfo}
var handler slog.Handler
switch format {
case "text":
handler = slog.NewTextHandler(output, opts)
default:
handler = slog.NewJSONHandler(output, opts)
}
return &SummaryWriter{
logger: slog.New(handler),
}
}
// Write emits the run summary as a single structured log entry
func (w *SummaryWriter) Write(s *RunSummary) {
if s == nil {
return
}
w.logger.Info("run_summary",
slog.Time("start_time", s.StartTime),
slog.Time("end_time", s.EndTime),
slog.Float64("duration_seconds", s.DurationSeconds),
slog.Int("sample_count", s.SampleCount),
slog.Group("cpu_total_percent",
slog.Float64("peak", s.CPUTotal.Peak),
slog.Float64("avg", s.CPUTotal.Avg),
slog.Float64("p95", s.CPUTotal.P95),
),
slog.Group("mem_used_bytes",
slog.Float64("peak", s.MemUsedBytes.Peak),
slog.Float64("avg", s.MemUsedBytes.Avg),
slog.Float64("p95", s.MemUsedBytes.P95),
),
slog.Group("mem_used_percent",
slog.Float64("peak", s.MemUsedPercent.Peak),
slog.Float64("avg", s.MemUsedPercent.Avg),
slog.Float64("p95", s.MemUsedPercent.P95),
),
slog.Any("top_cpu_processes", s.TopCPUProcesses),
slog.Any("top_mem_processes", s.TopMemProcesses),
)
}