All checks were successful
ci / build (push) Successful in 1m56s
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>
61 lines
1.7 KiB
Go
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),
|
|
)
|
|
}
|