# Storage Saturation Report for Nagios XI **Product:** Storage Saturation Report **Vendor:** Everwatch.Global **Document:** Technical documentation for implementation, calculations, and perfdata parsing. For compliance and audit traceability. **Component version:** 1.0.2 (see CHANGELOG.txt) This component displays a report-style view of storage volumes that are close to capacity. Only services with the `trackvolume` custom variable enabled are included. --- ## Configuration ### Custom Variables To enable volume tracking for a service, add a custom variable named **`trackvolume`** with value **`1`** or **`true`** (case-insensitive) to the service configuration. - **`trackvolume`**: Set to `1` or `true` to include the service in the report. The service must provide performance data (perfdata) that includes disk usage. The component parses this data to obtain used space, total space, and derived percentage and available space. ### Template Support Custom variables can be set in templates and inherit to all services using that template. ### Navigation Path in CCM 1. Navigate to **Core Configuration Manager** → **Hosts/Services** 2. Select the config and the service that monitors disk usage 3. Open **Custom Variables** 4. Add `trackvolume` with value `1` or `true` --- ## Technical Operation The following flow is implemented in `saturationreport.api.php` and is deterministic for audit traceability. 1. **Service inclusion** Only services with custom variable **`trackvolume`** equal to **`1`** or **`true`** (case-insensitive) are included. Implemented via `get_xml_custom_service_variable_status()` and `has_trackvolume_enabled()`. 2. **Data source** - Service list: `get_data_service_status()` - Perfdata: from each service’s `perfdata` field when present; if empty, from `get_xml_service_status()` (backend `getservicestatus`). 3. **Parsing** Each service’s single perfdata string is passed to `parse_disk_perfdata()`. Parsing tries **four formats in fixed order** (see Performance Data Parsing). The first successful parse is used. Output includes: `used`, `total`, `available`, `percent`, `used_bytes`, `total_bytes`, `available_bytes`, `used_unit`, `total_unit`, and when applicable `label`. 4. **Multi-metric behavior** For the single-metric format (Format 3), the perfdata string may contain multiple metrics (e.g. multiple drives). All matches are evaluated; the metric with the **highest percent used** is selected for that service. If that metric has a quoted label, it is used as the CAPTION. 5. **Sorting** Rows are sorted by **`disk_available_bytes` ascending** (least available first / most critical first). 6. **Display** CAPTION uses the perfdata **label** when present (e.g. `C:\_Label:__Serial_Number_2c3f47f4`); otherwise the service name/description. All displayed sizes and percentages are derived from the parsed values and the formulas below. --- ## Calculations All formulas below are implemented in `saturationreport.api.php` (`parse_disk_perfdata`, `convert_to_bytes`, `format_bytes`). They are deterministic for a given perfdata string and unit handling. ### Percent used - **Formula:** `percent_used = (used_bytes / total_bytes) * 100` - **Storage/display:** Rounded to **2 decimal places** (e.g. `round($percent, 2)`). ### Available space - **Formula:** `available_bytes = total_bytes - used_bytes` - In display units: `available = total - used` (same unit as used/total). ### Byte conversion (input → bytes) All capacity math uses **base 1024** for both binary and decimal-style units in this component: | Unit | Formula | |------|--------| | TiB, T | `value × 1024⁴` | | GiB, G | `value × 1024³` | | MiB, M | `value × 1024²` | | KiB, K | `value × 1024` | | B, (none), % | `value` (no scaling) | - Implemented in: `convert_to_bytes($value, $unit)`. ### Human-readable display (bytes → display) - **Function:** `format_bytes($bytes, $unit)` - Divides bytes by 1024^n and rounds to **1 decimal place**. - Unit selection: TB if bytes ≥ 1024⁴, else GB if ≥ 1024³, else MB if ≥ 1024², else KB if ≥ 1024, else B. ### Unit inference - If **total** (or max) has no unit but **used** has a unit, total is interpreted in the **same unit as used** (e.g. both MB). --- ## Performance Data (Perfdata) Parsing Parsing is attempted in the following order. The **first** successful format wins. All patterns are PCRE and case-insensitive unless noted. ### Format 1 – NCPA-style quoted `used` / `total` - Two metrics: `'used'=value[unit];` and `'total'=value[unit];` - **Patterns:** - Used: `/'used'\s*=\s*([0-9.]+)([KMGT]?(?:IB|B)?);/i` - Total: `/'total'\s*=\s*([0-9.]+)([KMGT]?(?:IB|B)?);/i` - **Capture groups:** (1) numeric value, (2) unit (e.g. MB, MiB) - **Example:** `'used'=0.69GiB;;; 'total'=5.82GiB;;;` ### Format 2 – NCPA-style unquoted `used` / `total` - Same as Format 1 with unquoted labels. - **Patterns:** - Used: `/\bused\s*=\s*([0-9.]+)([KMGT]?(?:IB|B)?);/i` - Total: `/\btotal\s*=\s*([0-9.]+)([KMGT]?(?:IB|B)?);/i` - **Example:** `used=0.69GiB;;; total=5.82GiB;;;` ### Format 3 – Single-metric with optional quoted label (multi-metric) - Standard Nagios: **label**`=`**value**`[unit]`**;**warn**;**crit**;**min**;**max**`[unit]`. Value is “used”; 5th field is “max” (total). If max has no unit, the value’s unit is used. - **Label:** Quoted `'...'` (any characters except single quote) or unquoted (non-whitespace, non-`=`). - **Full pattern:** `(?:'([^']*)'|[^=\s]+)=([0-9.]+)([KMGT]?(?:IB|B)?);[^;]*;[^;]*;[^;]*;([0-9.]+)([KMGT]?(?:IB|B)?)?` - **Capture groups:** (1) label if quoted, (2) value, (3) value unit, (4) max/total, (5) max unit if present. - **Example:** `'C:\_Label:__Serial_Number_2c3f47f4'=91445.6016MB;111560;132477;0;139450` - When **multiple** such metrics appear in one perfdata string, the metric with the **largest percent used** is chosen; its label (if any) is used for CAPTION. ### Format 4 – Fallback single-metric (no label capture) - Same structure as Format 3; label is not captured. - **Pattern:** `/[^=]*=([0-9.]+)([KMGT]?(?:IB|B)?);[^;]*;[^;]*;[^;]*;([0-9.]+)([KMGT]?(?:IB|B)?)?/i` - **Capture groups:** (1) value, (2) value unit, (3) max, (4) max unit. - **Example:** `/=4985MiB;9592;10791;0;11991` ### Unit token - **Pattern:** `[KMGT]?(?:IB|B)?` — optional K/M/G/T followed by optional `iB` or `B` (e.g. M, MB, MiB). --- ## Display The report is a table, ordered by available disk space (ascending). Each row shows: - **DISPLAY NAME:** Host name - **CAPTION:** Perfdata volume label when present (e.g. `C:\_Label:__Serial_Number_2c3f47f4`), otherwise service description/name - **DISK SPACE USED:** Used space (e.g. "117 GB") - **DISK SPACE AVAILABLE:** Available space (e.g. "2.7 GB") with color coding - **PERCENT USED:** Percentage with progress bar (e.g. "97%") --- ## Export and Print Export uses **client-side** PDF and image generation (jsPDF + html2canvas). No dependency on Nagios XI Chromium or the report command pipeline. - **PDF:** Client-side export: html2canvas captures `#saturationreport-container`, jsPDF creates a one-page PDF and triggers download. Libraries loaded from `scripts/vendor/` when present (html2canvas.min.js, jspdf.umd.min.js), else CDN. Fallback to browser Print (e.g. Print to PDF) if jsPDF or html2canvas unavailable. - **Image (PNG):** Client-side: html2canvas captures `#saturationreport-container` (2× scale). Same vendor/CDN loading as PDF. - **Progress bar:** The "percent used" bar uses color classes (green/amber/red) in both the main stylesheet and the minimal export document so the bar is styled correctly in the report and in exported PDF/image. Add to My Reports / Schedule / Email use `get_add_myreport_html()` with the full report URL. All report actions (settings, star, Schedule, Email, Export PDF, Export Image) are in the report options well in a single row. ### Mode routing (index.php) - **default:** Full page with form, reportexportlinks, and `#report` container. Report body is loaded via AJAX from `?mode=getreport`. - **mode=getreport:** Returns only the report HTML (table and optional header). Used by (1) AJAX to fill `#report`, (2) client-side capture for PDF/image. - **mode=submitpdf** / **mode=submitjpg:** Still available for XI installs that use the Chromium pipeline; the Export PDF button uses client-side jsPDF + html2canvas by default. --- ## Compliance and Audit - **Implementation reference:** Parsing and calculations are in `saturationreport.api.php`: `parse_disk_perfdata()`, `convert_to_bytes()`, `format_bytes()`, `get_saturationreport_services_data()`, `has_trackvolume_enabled()`. - **Parsing order:** Formats 1 → 2 → 3 → 4; first successful parse is used. - **Determinism:** For a given perfdata string and unit rules, percent used and available space are uniquely determined by the formulas and pattern order above. - **Version:** This document and the formulas/patterns apply to component version 1.0.3 (see CHANGELOG.txt). --- ## Author / Vendor **Everwatch.Global** https://everwatch.global Component development: snapier Technical documentation: Component version 1.0.3, January 2026