mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-11 14:00:29 +00:00
e6c0c4d385
Performance reports were structurally disconnected from the v6 ID space: the UI (and any API caller working from /api/state) addresses resources by canonical unified ID, while the metrics store is keyed by each platform's native source ID (the resource's metricsTarget). The engine queried the store with the unified ID verbatim, so every report rendered 'Data Points: 0' regardless of how much history existed, and covers showed raw hash IDs a report reader cannot map to a machine. - MetricReportRequest gains MetricsResourceID: handlers resolve the unified ID through the tenant monitor's resource store (new Monitor.MetricsTargetForResource accessor; the registry computes targets on demand, they are not persisted on snapshot structs) and the engine uses it for store queries only. Recovery points and Patrol findings stay keyed by the unified ID. - Legacy snapshot models and their alerts are keyed by the metrics target ID, so enrichment now matches either ID space and resource names/status resolve again on covers, headers, and fleet rows. - Fleet summaries mirror the single-report guard: zero data points across the fleet renders a muted NO DATA card instead of a green HEALTHY 'All systems operating normally' - false reassurance is the worst failure mode for a client-facing stability report. - Em dashes in PDF-bound literals become hyphens; fpdf core fonts are cp1252 and rendered them as mojibake.
191 lines
6.0 KiB
Go
191 lines
6.0 KiB
Go
package reporting
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
// ReportFormat represents the output format of a report
|
|
type ReportFormat string
|
|
|
|
const (
|
|
FormatCSV ReportFormat = "csv"
|
|
FormatPDF ReportFormat = "pdf"
|
|
)
|
|
|
|
// MetricReportRequest defines the parameters for generating a report
|
|
type MetricReportRequest struct {
|
|
ResourceType string
|
|
ResourceID string
|
|
MetricType string // Optional, if empty all metrics for the resource are included
|
|
Start time.Time
|
|
End time.Time
|
|
Format ReportFormat
|
|
Title string
|
|
Branding ReportBranding
|
|
|
|
// MetricsResourceID overrides ResourceID for metrics-store queries.
|
|
// The v6 API addresses resources by canonical unified ID while the
|
|
// metrics store is keyed by each platform's native source ID (the
|
|
// resource's metricsTarget); recovery points and Patrol findings stay
|
|
// keyed by the unified ID. Handlers set this from the resource's
|
|
// metricsTarget so the store query can match without changing the
|
|
// identity the rest of the report pipeline sees.
|
|
MetricsResourceID string
|
|
|
|
// Optional enrichment data (populated by handler from monitor state)
|
|
Resource *ResourceInfo // Details about the resource being reported on
|
|
Alerts []AlertInfo // Active and recently resolved alerts for this resource
|
|
Backups []BackupInfo // Backup information for VMs/containers
|
|
Storage []StorageInfo // Storage pools (for nodes)
|
|
Disks []DiskInfo // Physical disk health (for nodes)
|
|
|
|
// Optional narrative interpretation. When Narrator is non-nil the
|
|
// engine builds a NarrativeInput from the queried report data and asks
|
|
// it to produce the executive summary; on error or nil it falls back to
|
|
// the heuristic narrator. Findings are passed through to NarrativeInput
|
|
// so a narrator can reference Patrol activity in the period.
|
|
Narrator Narrator
|
|
FindingsProvider FindingsProvider
|
|
}
|
|
|
|
// ResourceInfo contains details about the resource being reported on
|
|
type ResourceInfo struct {
|
|
Name string
|
|
DisplayName string
|
|
Status string
|
|
Host string // URL for nodes
|
|
Node string // Parent node for VMs/containers
|
|
Instance string // Proxmox instance name
|
|
Uptime int64
|
|
KernelVersion string
|
|
PVEVersion string
|
|
OSName string
|
|
OSVersion string
|
|
IPAddresses []string
|
|
CPUModel string
|
|
CPUCores int
|
|
CPUSockets int
|
|
MemoryTotal int64
|
|
DiskTotal int64
|
|
LoadAverage []float64
|
|
Temperature *float64 // CPU temp if available
|
|
Tags []string
|
|
ClusterName string
|
|
IsCluster bool
|
|
}
|
|
|
|
// AlertInfo contains alert information for the report
|
|
type AlertInfo struct {
|
|
Type string
|
|
Level string // warning, critical
|
|
Message string
|
|
Value float64
|
|
Threshold float64
|
|
StartTime time.Time
|
|
ResolvedTime *time.Time // nil if still active
|
|
Acknowledged bool
|
|
}
|
|
|
|
// BackupInfo contains backup information for VMs/containers
|
|
type BackupInfo struct {
|
|
Type string // vzdump, pbs
|
|
Storage string
|
|
Timestamp time.Time
|
|
Size int64
|
|
Verified bool
|
|
Protected bool
|
|
VolID string
|
|
NextBackup *time.Time
|
|
}
|
|
|
|
// StorageInfo contains storage pool information
|
|
type StorageInfo struct {
|
|
Name string
|
|
Type string // lvm, zfs, dir, nfs, etc.
|
|
Status string
|
|
Total int64
|
|
Used int64
|
|
Available int64
|
|
UsagePerc float64
|
|
Content string // images, rootdir, backup, etc.
|
|
ZFSHealth string // For ZFS pools
|
|
ZFSErrors int // Checksum/read/write errors
|
|
}
|
|
|
|
// DiskInfo contains physical disk health information
|
|
type DiskInfo struct {
|
|
Device string
|
|
Model string
|
|
Serial string
|
|
Type string // nvme, ssd, hdd
|
|
Size int64
|
|
Health string // PASSED, FAILED, UNKNOWN
|
|
Temperature int // Celsius
|
|
WearLevel int // 0-100, percentage of life REMAINING (100 = healthy, 0 = end of life, -1 = unknown)
|
|
}
|
|
|
|
// MultiReportRequest defines the parameters for generating a multi-resource report.
|
|
type MultiReportRequest struct {
|
|
Resources []MetricReportRequest // One per resource, each with enrichment
|
|
Format ReportFormat
|
|
Start time.Time
|
|
End time.Time
|
|
Title string
|
|
MetricType string
|
|
Branding ReportBranding
|
|
|
|
// Optional fleet-level narrative interpretation. When FleetNarrator is
|
|
// non-nil the engine builds a FleetNarrativeInput from the queried
|
|
// per-resource report data and asks it to produce the cross-resource
|
|
// summary; on error or nil it falls back to the heuristic fleet
|
|
// narrator. FindingsProvider, when set, is consulted per-resource so
|
|
// patrol findings can flow into per-resource narratives.
|
|
FleetNarrator FleetNarrator
|
|
Narrator Narrator
|
|
FindingsProvider FindingsProvider
|
|
}
|
|
|
|
// MultiReportData holds the data for multi-resource report generation.
|
|
type MultiReportData struct {
|
|
Title string
|
|
Start time.Time
|
|
End time.Time
|
|
GeneratedAt time.Time
|
|
Resources []*ReportData // Reuse existing ReportData per resource
|
|
TotalPoints int
|
|
Brand *ReportBrand
|
|
|
|
// Fleet-level narrative interpretation, populated by the engine when
|
|
// the request supplies a FleetNarrator (or always populated with the
|
|
// heuristic fallback). The renderer prefers this over recomputing
|
|
// observations inline.
|
|
FleetNarrative *FleetNarrative
|
|
}
|
|
|
|
// Engine defines the interface for report generation.
|
|
// This allows the enterprise version to provide PDF/CSV generation.
|
|
//
|
|
// NarrativeFor and FleetNarrativeFor return the structured narrative
|
|
// without rendering, for callers that want the synthesis layer in a
|
|
// non-PDF form (Pulse Assistant tool calls, programmatic consumers).
|
|
type Engine interface {
|
|
Generate(req MetricReportRequest) (data []byte, contentType string, err error)
|
|
GenerateMulti(req MultiReportRequest) (data []byte, contentType string, err error)
|
|
NarrativeFor(req MetricReportRequest) (*Narrative, error)
|
|
FleetNarrativeFor(req MultiReportRequest) (*FleetNarrative, error)
|
|
}
|
|
|
|
var (
|
|
globalEngine Engine
|
|
)
|
|
|
|
// SetEngine sets the global report engine.
|
|
func SetEngine(e Engine) {
|
|
globalEngine = e
|
|
}
|
|
|
|
// GetEngine returns the current global report engine.
|
|
func GetEngine() Engine {
|
|
return globalEngine
|
|
}
|