Skip to content

fix: OCP/SMART metric correctness, endurance from percent_used, GUID info metric - #16

Merged
dobbi84 merged 6 commits into
mainfrom
fix/ocp-metric-correctness
Jun 4, 2026
Merged

fix: OCP/SMART metric correctness, endurance from percent_used, GUID info metric#16
dobbi84 merged 6 commits into
mainfrom
fix/ocp-metric-correctness

Conversation

@dobbi84

@dobbi84 dobbi84 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Correctness improvements to the OCP/SMART metrics and the recording rules that derive endurance values. Unit semantics verified against the NVMe Base Spec and OCP Datacenter NVMe SSD Spec.

Exporter (cmd/collector.go, pkg/provider.go)

  • nvme_data_units_read/written help: now states values are in thousands of 512-byte units (bytes = value × 512000).
  • nvme_physical_media_units_* help: corrected from "1000h sector size" to bytes (128-bit counter split lo/hi), per OCP spec.
  • Type fix: nvme_bad_user/system_nand_blocks_normalized changed counter → gauge (normalized 0-100 values decrease; counters would misread that as resets).
  • nvme_log_page_guidnvme_log_page_guid_info: the GUID is a 128-bit identifier; read as a float it was always 0/garbage. Now emitted as a constant-1 info metric nvme_log_page_guid_info{guid="..."} via a new label-metric provider — the standard Prometheus pattern for string identifiers.

Recording rules (resources/prom/nvme_ocp.yml)

  • Removed the hard-coded 3000 P/E-cycle guess. Endurance now derives from the device's own nvme_percent_used (vendor wear estimate, which already accounts for real endurance and write amplification):
    • device:DRL_calculated = clamp_min(100 - nvme_percent_used, 0)
    • device:TBW_calculated derived from percent_used, guarded to > 0
    • dropped device:TBW_numerator
  • Kept 365*5 (warranty window — contractual, not telemetry) and the spec unit constants (512000, 1e12, 273.15), all documented.
  • Added device:DWPD_lifetime — total host writes ÷ capacity ÷ powered-on days; constant-free and single-scrape. Plus device:DWPD_observed (windowed rate) from the earlier commit.
  • Annotated every constant/unit and flagged which rules are stateful (rate, predict_linear) and must stay in Prometheus.

Behavioral notes

  • nvme_log_page_guid is renamed to nvme_log_page_guid_info (the old metric was always 0, so no real consumer).
  • device:DRL_calculated / device:TBW_calculated keep their names but change basis (3000-model → vendor percent_used); dashboards keep working, values become more accurate.
  • device:projected_DRL_4h now uses a [6h] lookback because percent_used is coarse.

Still not done (breaking — needs a decision)

  • Counter metrics lack the Prometheus _total suffix; fixing is breaking (renames metrics referenced by these rules + dashboards).

Testing

  • go build ./... ✅ · go vet ./... ✅ · nvme_ocp.yml parses as valid YAML (promtool unavailable locally).

dobbi84 added 2 commits June 4, 2026 11:29
- data_units_read/written help now states the values are in thousands of
  512-byte units (bytes = value * 512000), per the NVMe spec.
- physical_media_units_* help corrected from "1000h sector size" to bytes
  (128-bit byte counter split lo/hi), per the OCP spec.
- bad_user/system_nand_blocks_normalized changed from counter to gauge:
  normalized 0-100 values decrease over time, so rate()/increase() on a
  counter would misread them as resets.
Document every magic constant and unit assumption (512000 = 1000*512
data-unit-to-byte factor, 1e12 decimal TB, 3000 P/E cycles, 365*5
warranty window, 273.15 Kelvin offset) and note which rules are stateful
(rate/predict_linear) and must stay in Prometheus.

Add device:DWPD_observed, the actual drive-writes-per-day computed from
the host write rate, complementing the existing rated DWPD_calculated.
@dobbi84
dobbi84 requested a review from LemonySnippet as a code owner June 4, 2026 09:30
dobbi84 added 2 commits June 4, 2026 11:51
The GUID is a 128-bit identifier; read via gjson .Float() it was always
0/garbage. Add a label-metric provider that emits a constant-1 gauge
nvme_log_page_guid_info{guid="..."} carrying the GUID as a label, the
standard Prometheus pattern for string identifiers.
Replace the hard-coded 3000 P/E-cycle guess with the device's own
nvme_percent_used (the vendor wear estimate, which already accounts for
real endurance and write amplification):
- DRL_calculated is now clamp_min(100 - nvme_percent_used, 0)
- TBW_calculated is derived from percent_used (guarded to >0)
- removed TBW_numerator (the *3000 rule)

Keep 365*5 (warranty window) as it is contractual, not telemetry; keep
the spec unit constants (512000, 1e12, 273.15). Add device:DWPD_lifetime
(total host writes / capacity / powered-on days), a constant-free,
single-scrape DWPD.
@dobbi84 dobbi84 changed the title fix: OCP/SMART raw-metric correctness + annotated recording rules fix: OCP/SMART metric correctness, endurance from percent_used, GUID info metric Jun 4, 2026
dobbi84 added 2 commits June 4, 2026 11:57
… projection

Two distinct rules for two distinct questions:
- device:DRL_calculated: accurate remaining-life % from the vendor's own
  percent_used (how much life is left now).
- device:DRL_days_remaining: estimated days to end-of-life at the current
  write rate. The wear rate comes from the continuous data-units counter
  (smooth), the endurance size from percent_used.

Replaces device:projected_DRL_4h, whose predict_linear over the coarse
integer percent_used produced a flat/jumpy slope regardless of window.
- Add the missing root '{' — the JSON was invalid and could not be
  imported into Grafana at all.
- Fix broken metric references:
  - device:projected_DRL_8h (rule never existed) -> device:DRL_days_remaining,
    retitled to estimated days-to-EOL with day units and proper thresholds.
  - node_nvme_info (not exported) -> nvme_physical_size, with the Disk Info
    table regrouped on the real info labels (model_number, serial_number,
    firmware, generic_path) plus capacity.
  - Remove a stray 'nvme_num' target.
- Add panels for the new recording rules: device:DWPD_observed and
  device:DWPD_lifetime.
- Correct stale/copy-paste descriptions and titles (DRL gauge now reflects
  percent_used basis, DWPD reflects telemetry-derived TBW, unsafe-shutdowns
  description, truncated 'Host Read/Write Commands' titles, data-units-written
  node scoping).
- Drop the hard-coded node IP from the OCP row title and the baked-in node
  selection; clean dashboard title and null the id for clean import.
@dobbi84 dobbi84 added bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request go Pull requests that update go code labels Jun 4, 2026
@dobbi84 dobbi84 self-assigned this Jun 4, 2026
@dobbi84
dobbi84 merged commit f8834ba into main Jun 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant