Some checks failed
ci / goreleaser (push) Failing after 1s
Rename module from edp.buildth.ing/DevFW/forgejo-runner-resource-collector to edp.buildth.ing/DevFW-CICD/forgejo-runner-resource-collector
131 lines
3.1 KiB
Go
131 lines
3.1 KiB
Go
package output
|
|
|
|
import (
|
|
"io"
|
|
"log/slog"
|
|
"os"
|
|
|
|
"edp.buildth.ing/DevFW-CICD/forgejo-runner-resource-collector/internal/metrics"
|
|
)
|
|
|
|
// LogFormat specifies the log output format
|
|
type LogFormat string
|
|
|
|
const (
|
|
LogFormatJSON LogFormat = "json"
|
|
LogFormatText LogFormat = "text"
|
|
)
|
|
|
|
// LoggerWriter outputs metrics using structured logging
|
|
type LoggerWriter struct {
|
|
logger *slog.Logger
|
|
level slog.Level
|
|
}
|
|
|
|
// LoggerConfig holds configuration for the logger
|
|
type LoggerConfig struct {
|
|
Output io.Writer
|
|
Format LogFormat
|
|
Level slog.Level
|
|
}
|
|
|
|
// NewLoggerWriter creates a new logger-based writer
|
|
func NewLoggerWriter(cfg LoggerConfig) *LoggerWriter {
|
|
if cfg.Output == nil {
|
|
cfg.Output = os.Stdout
|
|
}
|
|
|
|
var handler slog.Handler
|
|
opts := &slog.HandlerOptions{
|
|
Level: cfg.Level,
|
|
}
|
|
|
|
switch cfg.Format {
|
|
case LogFormatText:
|
|
handler = slog.NewTextHandler(cfg.Output, opts)
|
|
default:
|
|
handler = slog.NewJSONHandler(cfg.Output, opts)
|
|
}
|
|
|
|
return &LoggerWriter{
|
|
logger: slog.New(handler),
|
|
level: cfg.Level,
|
|
}
|
|
}
|
|
|
|
// Write outputs the metrics using structured logging
|
|
func (w *LoggerWriter) Write(m *metrics.SystemMetrics) error {
|
|
// Build top CPU process attrs
|
|
topCPUAttrs := make([]any, 0, len(m.TopCPU))
|
|
for _, p := range m.TopCPU {
|
|
topCPUAttrs = append(topCPUAttrs, slog.Group("",
|
|
slog.Int("pid", p.PID),
|
|
slog.String("name", p.Name),
|
|
slog.Float64("cpu_percent", p.CPUPercent),
|
|
))
|
|
}
|
|
|
|
// Build top memory process attrs
|
|
topMemAttrs := make([]any, 0, len(m.TopMemory))
|
|
for _, p := range m.TopMemory {
|
|
topMemAttrs = append(topMemAttrs, slog.Group("",
|
|
slog.Int("pid", p.PID),
|
|
slog.String("name", p.Name),
|
|
slog.Uint64("rss_bytes", p.MemRSS),
|
|
))
|
|
}
|
|
|
|
w.logger.Info("metrics_collected",
|
|
slog.Time("collection_time", m.Timestamp),
|
|
slog.Int("total_processes", m.TotalProcesses),
|
|
slog.Group("cpu",
|
|
slog.Float64("total_percent", m.CPU.TotalPercent),
|
|
slog.Float64("user_percent", m.CPU.UserPercent),
|
|
slog.Float64("system_percent", m.CPU.SystemPercent),
|
|
slog.Float64("idle_percent", m.CPU.IdlePercent),
|
|
slog.Float64("iowait_percent", m.CPU.IOWaitPercent),
|
|
),
|
|
slog.Group("memory",
|
|
slog.Uint64("total_bytes", m.Memory.TotalBytes),
|
|
slog.Uint64("used_bytes", m.Memory.UsedBytes),
|
|
slog.Uint64("free_bytes", m.Memory.FreeBytes),
|
|
slog.Uint64("available_bytes", m.Memory.AvailableBytes),
|
|
slog.Float64("used_percent", m.Memory.UsedPercent),
|
|
slog.Uint64("total_rss_bytes", m.Memory.TotalRSSBytes),
|
|
slog.Float64("rss_percent", m.Memory.RSSPercent),
|
|
),
|
|
slog.Any("top_cpu", topCPUAttrs),
|
|
slog.Any("top_memory", topMemAttrs),
|
|
)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Close is a no-op for the logger writer
|
|
func (w *LoggerWriter) Close() error {
|
|
return nil
|
|
}
|
|
|
|
// ParseLogLevel parses a log level string
|
|
func ParseLogLevel(level string) slog.Level {
|
|
switch level {
|
|
case "debug":
|
|
return slog.LevelDebug
|
|
case "warn", "warning":
|
|
return slog.LevelWarn
|
|
case "error":
|
|
return slog.LevelError
|
|
default:
|
|
return slog.LevelInfo
|
|
}
|
|
}
|
|
|
|
// ParseLogFormat parses a log format string
|
|
func ParseLogFormat(format string) LogFormat {
|
|
switch format {
|
|
case "text":
|
|
return LogFormatText
|
|
default:
|
|
return LogFormatJSON
|
|
}
|
|
}
|