mirror of
https://github.com/tw93/Mole.git
synced 2026-03-22 17:55:08 +00:00
feat(status): alert on persistent high-cpu processes (#602)
* feat(status): alert on persistent high-cpu processes * refactor(status): keep high-cpu alerts read-only * fix(status): address lint and sudo test regressions --------- Co-authored-by: Tw93 <hitw93@gmail.com>
This commit is contained in:
@@ -21,7 +21,10 @@ var (
|
||||
BuildTime = ""
|
||||
|
||||
// Command-line flags
|
||||
jsonOutput = flag.Bool("json", false, "output metrics as JSON instead of TUI")
|
||||
jsonOutput = flag.Bool("json", false, "output metrics as JSON instead of TUI")
|
||||
procCPUThreshold = flag.Float64("proc-cpu-threshold", 100, "alert when a process stays above this CPU percent")
|
||||
procCPUWindow = flag.Duration("proc-cpu-window", 5*time.Minute, "continuous duration a process must exceed the CPU threshold")
|
||||
procCPUAlerts = flag.Bool("proc-cpu-alerts", true, "enable persistent high-CPU process alerts")
|
||||
)
|
||||
|
||||
func shouldUseJSONOutput(forceJSON bool, stdout *os.File) bool {
|
||||
@@ -116,11 +119,29 @@ func saveCatHidden(hidden bool) {
|
||||
|
||||
func newModel() model {
|
||||
return model{
|
||||
collector: NewCollector(),
|
||||
collector: NewCollector(processWatchOptionsFromFlags()),
|
||||
catHidden: loadCatHidden(),
|
||||
}
|
||||
}
|
||||
|
||||
func processWatchOptionsFromFlags() ProcessWatchOptions {
|
||||
return ProcessWatchOptions{
|
||||
Enabled: *procCPUAlerts,
|
||||
CPUThreshold: *procCPUThreshold,
|
||||
Window: *procCPUWindow,
|
||||
}
|
||||
}
|
||||
|
||||
func validateFlags() error {
|
||||
if *procCPUThreshold < 0 {
|
||||
return fmt.Errorf("--proc-cpu-threshold must be >= 0")
|
||||
}
|
||||
if *procCPUWindow <= 0 {
|
||||
return fmt.Errorf("--proc-cpu-window must be > 0")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
return tea.Batch(tickAfter(0), animTick())
|
||||
}
|
||||
@@ -179,6 +200,7 @@ func (m model) View() string {
|
||||
}
|
||||
|
||||
header, mole := renderHeader(m.metrics, m.errMessage, m.animFrame, termWidth, m.catHidden)
|
||||
alertBar := renderProcessAlertBar(m.metrics.ProcessAlerts, termWidth)
|
||||
|
||||
var cardContent string
|
||||
if termWidth <= 80 {
|
||||
@@ -204,6 +226,9 @@ func (m model) View() string {
|
||||
|
||||
// Combine header, mole, and cards with consistent spacing
|
||||
parts := []string{header}
|
||||
if alertBar != "" {
|
||||
parts = append(parts, alertBar)
|
||||
}
|
||||
if mole != "" {
|
||||
parts = append(parts, mole)
|
||||
}
|
||||
@@ -235,7 +260,7 @@ func animTickWithSpeed(cpuUsage float64) tea.Cmd {
|
||||
|
||||
// runJSONMode collects metrics once and outputs as JSON.
|
||||
func runJSONMode() {
|
||||
collector := NewCollector()
|
||||
collector := NewCollector(processWatchOptionsFromFlags())
|
||||
|
||||
// First collection initializes network state (returns nil for network)
|
||||
_, _ = collector.Collect()
|
||||
@@ -269,6 +294,10 @@ func runTUIMode() {
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if err := validateFlags(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
if shouldUseJSONOutput(*jsonOutput, os.Stdout) {
|
||||
runJSONMode()
|
||||
@@ -276,3 +305,13 @@ func main() {
|
||||
runTUIMode()
|
||||
}
|
||||
}
|
||||
|
||||
func activeAlerts(alerts []ProcessAlert) []ProcessAlert {
|
||||
var active []ProcessAlert
|
||||
for _, alert := range alerts {
|
||||
if alert.Status == "active" {
|
||||
active = append(active, alert)
|
||||
}
|
||||
}
|
||||
return active
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user