---
module: agent.srv-monitor
title: Server Monitor — CPU/memory/disk/service health watcher for SRV devices
tab: Claude
order: 40
audience: dev
---

> **Internal · agent reference.** Terse, act-without-guessing. Confirmed against `hiveops-module-srv-monitor` source 2026-07-01.

## Identity
- Module name (`AgentModule.getName()`): **`srv-monitor`**
- Maven artifact / drop-in jar: **`hiveops-module-srv-monitor.jar`** (own version `1.0.0`; parent `hiveops-agent-parent` currently `4.4.3`)
- Entry class: `com.hiveops.srvmonitor.ServerMonitorModule` (SPI file: `META-INF/services/com.hiveops.core.module.AgentModule`)
- Other classes: `ServerMonitorCollector` (iface), `LinuxServerMonitorCollector`, `WindowsServerMonitorCollector`, `ServerMetrics`
- Log package (`getLogPackage()`): `com.hiveops.srvmonitor` → `logs/modules/srv-monitor.log`
- Dependencies (`getDependencies()`): **none** (empty list)
- Constants: `deviceType = "SRV"`, `eventSource = "HIVEOPS_AGENT"`

## Config properties (exact keys, from `hiveops.properties`)
| Key | Default | Notes |
|---|---|---|
| `srv.monitor.enabled` | `false` | master gate; module inactive unless `true` |
| `srv.monitor.interval.seconds` | `60` | fixed-rate poll; initial delay 0 |
| `srv.monitor.cpu.threshold` | `85` | CPU busy % |
| `srv.monitor.cpu.sustained.samples` | `3` | consecutive breaching polls before CPU_HIGH |
| `srv.monitor.memory.threshold` | `90` | mem used % |
| `srv.monitor.disk.threshold` | `90` | per-filesystem used % |
| `srv.monitor.services` | *(empty)* | comma list of service/unit names; empty = no service checks |
- Shared (not srv-monitor-specific), required for events: `agent.endpoint` (preferred) **or** `incident.endpoint` (fallback). Neither set → module stays inactive even if enabled. HTTP client settings loaded with prefix `agent` or `incident` to match.
- Config is read **once in `initialize()`** → change needs an agent restart to apply.
- Disable via `srv.monitor.enabled=false` **or** add `srv-monitor` to `modules.disabled`.

## Event-type strings emitted (exact)
- CPU: **`SERVER_CPU_HIGH`**, **`SERVER_CPU_NORMAL`**
- Memory: **`SERVER_MEMORY_HIGH`**, **`SERVER_MEMORY_NORMAL`**
- Disk: **`SERVER_DISK_LOW`**, **`SERVER_DISK_NORMAL`**
- Service: **`SERVICE_DOWN`**, **`SERVICE_UP`**
- Edge-triggered: fired on state **transition** only, not per poll. CPU is debounced by `sustained.samples`; memory/disk/service transition immediately.
- Sent as `CreateJournalEventRequest` (`agentAtmId`, `deviceType=SRV`, `eventType`, `eventDetails`, `eventSource=HIVEOPS_AGENT`).

## Transport
- `IncidentEventClient.sendEvents(...)` → **`POST {endpoint}/api/journal-events`**, **one POST per event** (not batched — loops `sendEvent`).
- Same client/endpoint as the `journal-events` module; only `deviceType=SRV` differs. Routed via agent-proxy → incident ingest.

## Deployment (fleet)
- Deliver jar via **`INSTALL_MODULE`** fleet task (`ProcessInstallModule`): artifact chunked-download **or** `configPatch.url` + `filename` (filename must end `.jar`). Drops into `modules/`, then restarts agent.
- Then enable via `CONFIG_UPDATE` setting `srv.monitor.enabled=true`.

## Collectors
- Linux: `/proc/stat` (CPU, 1 s sample), `/proc/meminfo` (MemTotal/MemAvailable), `File.listRoots()` (disk), `systemctl is-active <svc>` (up iff `active`).
- Windows: PowerShell (`-NoProfile -NonInteractive -ExecutionPolicy Bypass`) — `Get-Counter`, `Win32_OperatingSystem`, `Win32_LogicalDisk`, `Get-Service` (up iff `Running`).
- Chosen at init by `context.getPlatformService().isWindows()`.

## Gotchas
- **Linux disk = roots only.** `File.listRoots()` is typically just `/`; separate mounts (e.g. `/var`) are not monitored per-partition. Windows lists each drive letter.
- **CPU spike shorter than `sustained.samples` polls never fires** (default 3 × 60 s ≈ 3 min sustained).
- **Transition state is in-memory only** — agent restart re-emits HIGH on next breaching poll if condition persists.
- **Flapping at the threshold** — memory/disk/service have no debounce; a value hovering at the threshold alternates HIGH/NORMAL each poll.
- **Windows collector returns 0.0/empty** if PowerShell is unavailable/locked down; non-zero exit + stderr logged.
- **Service name mismatch → false `SERVICE_DOWN`** (needs exact systemd unit / Windows service name).
- **Log-line cosmetic bug:** several info logs use `{:.1f}` placeholders (SLF4J-C style), which log4j2 does not format — the value is dropped in the log text. The `eventDetails` sent to the platform use `String.format("%.1f", …)` and are correct; only the local log strings are affected.

## Do NOT
- Do **not** expect batched event POSTs — it's one HTTP request per event.
- Do **not** assume enabling `srv.monitor.enabled` alone works — the jar must also be present in `modules/` and an endpoint configured.
- Do **not** expect config changes to apply without an agent restart.
- Do **not** point this at ATM incidents expecting ATM device type — it always emits `deviceType=SRV`.
- Do **not** invent `srv-monitor.*` (dot-dash) keys — the real prefix is `srv.monitor.*` (all dots).
- Do **not** rely on Linux per-mount disk alerts for non-root filesystems.
