report.go - Katyusha's blog
mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
report.go
Go Source File · 81 lines
report.go
// Package report 将多场景的诊断结果汇总为一份结构化 Markdown 报告
//(赛题鼓励项:自动生成诊断报告 / 多维关联)。
package report
import (
"fmt"
"io"
"os"
"time"
"github.com/os2026/ebpf-rca/internal/output"
"github.com/os2026/ebpf-rca/internal/schema"
)
// Aggregator 收集去重后的诊断结果。
type Aggregator struct {
reports []schema.AnomalyReport
seen map[string]bool
}
// New 构造聚合器。
func New() *Aggregator {
return &Aggregator{seen: make(map[string]bool)}
}
// Add 添加一条结果(按异常类型+关联对象去重)。
func (a *Aggregator) Add(r schema.AnomalyReport) {
k := fmt.Sprintf("%s|%d|%s|%s|%v",
r.AnomalyType, r.RelatedObject.Pid, r.RelatedObject.Comm,
r.RelatedObject.Device, r.KeyMetrics["syscall"])
if a.seen[k] {
return
}
a.seen[k] = true
a.reports = append(a.reports, r)
}
// Count 返回已收集的结果数。
func (a *Aggregator) Count() int { return len(a.reports) }
// Render 输出一份汇总 Markdown 报告:概要表 + 各项详细诊断。
func (a *Aggregator) Render(w io.Writer, dur time.Duration) error {
host, _ := os.Hostname()
fmt.Fprintf(w, "# 系统异常诊断报告\n\n")
fmt.Fprintf(w, "- 主机:%s\n", host)
fmt.Fprintf(w, "- 采集时长:%s\n", dur.Round(time.Second))
fmt.Fprintf(w, "- 生成时间:%s\n", time.Now().Format(time.RFC3339))
fmt.Fprintf(w, "- 发现异常:%d\n\n", len(a.reports))
if len(a.reports) == 0 {
fmt.Fprintf(w, "未发现异常。系统在采集窗口内各项指标均低于告警阈值。\n")
return nil
}
fmt.Fprintf(w, "## 概要\n\n")
fmt.Fprintf(w, "| # | 异常类型 | 关联对象 | 疑似根因 | 置信度 |\n")
fmt.Fprintf(w, "|---|----------|----------|----------|--------|\n")
for i, r := range a.reports {
fmt.Fprintf(w, "| %d | %s | %s | %s | %.2f |\n",
i+1, r.AnomalyType, objStr(r.RelatedObject), r.SuspectedRootCause, r.Confidence)
}
fmt.Fprintf(w, "\n## 详细诊断\n\n")
for i, r := range a.reports {
fmt.Fprintf(w, "### %d. %s\n\n", i+1, r.AnomalyType)
if err := output.Write(w, r, "md"); err != nil {
return err
}
}
return nil
}
func objStr(o schema.RelatedObject) string {
if o.Device != "" {
return "设备 " + o.Device
}
if o.Comm != "" {
return fmt.Sprintf("%s(pid=%d)", o.Comm, o.Pid)
}
return fmt.Sprintf("pid=%d", o.Pid)
}

目录