Fetches SMART data from Scrutiny's InfluxDB and calculates failure probabilities using the exact BackBlaze tables from SnapRAID source. Key features: - Calculates both v12 (with attr 193) and v13 (without attr 193) algorithms - v12 matches SnapRAID pre-v13.0 (includes Load Cycle Count) - v13 matches modern SnapRAID v13.0+ (excludes Load Cycle Count) - Stores both values for trending and comparison - Correctly applies bit masks (16-bit for 187/188, 32-bit for others) - Annualizes monthly rates and applies Poisson distribution - Logs to PostgreSQL with device metadata Solved the mystery: SnapRAID v12 uses attribute 193 which was removed in v13.0. Load cycle count has massive impact on failure predictions for some drives (80% vs 4% difference). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
9.2 KiB
SnapRAID SMART Logger - Investigation Notes
Project Goal
Create a Python utility that:
- Fetches SMART data from Scrutiny's InfluxDB
- Calculates failure probability exactly like SnapRAID does (using BackBlaze algorithm)
- Logs enhanced data to PostgreSQL
- Eventually add alerts and automation
Current Status: BLOCKED - Algorithm Mismatch
We successfully built the infrastructure but cannot match SnapRAID's failure probability calculations.
The Mystery: 81% vs 4.63%
What SnapRAID Reports for /dev/sdc (ZLW0A3QJ)
Temp Power Error FP Size
C OnDays Count TB Serial Device Disk
-----------------------------------------------------------------------
24 1968 0 81% 12.0 ZLW0A3QJ /dev/sdc d1
Failure Probability: 81%
What smartctl -A Shows
ID# ATTRIBUTE_NAME VALUE WORST THRESH RAW_VALUE
5 Reallocated_Sector_Ct 100 100 010 0
187 Reported_Uncorrect 100 100 000 0
188 Command_Timeout 100 100 000 0
197 Current_Pending_Sector 100 100 000 0
198 Offline_Uncorrectable 100 100 000 0
All critical attributes are PERFECT (VALUE=100, RAW_VALUE=0)
What Our BackBlaze Calculation Gives
Using the exact same BackBlaze tables extracted from SnapRAID source:
- With RAW_VALUE = 0: Probability = 4.63%
- With VALUE = 100: Probability = 100% (saturated, wrong)
Neither matches SnapRAID's 81%!
What We Know About SnapRAID's Algorithm
Source Code Analysis
From cmdline/device.c:
static double smart_afr(uint64_t* smart, const char* model)
{
double afr = 0;
uint64_t mask32 = 0xffffffffU;
uint64_t mask16 = 0xffffU;
// Attribute 5: Reallocated Sectors (32-bit mask)
if (smart[5] != SMART_UNASSIGNED) {
double r = smart_afr_value(SMART_5_R, SMART_5_STEP, smart[5] & mask32);
if (afr < r) afr = r;
}
// Attribute 187: Reported Uncorrectable (16-bit mask)
if (smart[187] != SMART_UNASSIGNED) {
double r = smart_afr_value(SMART_187_R, SMART_187_STEP, smart[187] & mask16);
if (afr < r) afr = r;
}
// Attribute 188: Command Timeout (16-bit, skipped for Seagate)
if (strncmp(model, "ST", 2) != 0 && smart[188] != SMART_UNASSIGNED) {
double r = smart_afr_value(SMART_188_R, SMART_188_STEP, smart[188] & mask16);
if (afr < r) afr = r;
}
// Attribute 197: Current Pending Sectors (32-bit)
if (smart[197] != SMART_UNASSIGNED) {
double r = smart_afr_value(SMART_197_R, SMART_197_STEP, smart[197] & mask32);
if (afr < r) afr = r;
}
// Attribute 198: Offline Uncorrectable (32-bit)
if (smart[198] != SMART_UNASSIGNED) {
double r = smart_afr_value(SMART_198_R, SMART_198_STEP, smart[198] & mask32);
if (afr < r) afr = r;
}
return afr;
}
Table Lookup Function
static double smart_afr_value(double* tab, unsigned step, uint64_t value)
{
value /= step;
if (value >= SMART_MEASURES) value = SMART_MEASURES - 1;
return 365.0 / 30.0 * tab[value]; // Annualize monthly rate
}
Final Probability Calculation
// Poisson distribution: P(at least 1 failure) = 1 - e^(-AFR)
poisson_prob_n_or_more_failures(afr, 1) * 100
Formula: P = (1 - e^(-AFR)) × 100
Key Findings
1. BackBlaze Tables Are Correct
We extracted all 5 tables (256 values each) from SnapRAID source:
SMART_5_R(Reallocated Sectors)SMART_187_R(Reported Uncorrectable)SMART_188_R(Command Timeout)SMART_197_R(Current Pending Sectors)SMART_198_R(Offline Uncorrectable)
Tables match exactly - verified byte-for-byte.
2. Algorithm Is Correct
Our implementation:
- ✅ Uses correct bit masks (16-bit for 187/188, 32-bit for 5/197/198)
- ✅ Applies correct step size (all = 1)
- ✅ Takes maximum AFR across attributes
- ✅ Scales monthly to annual (365/30)
- ✅ Applies Poisson:
1 - e^(-AFR)
3. The Math Works Backwards
If SnapRAID reports 81%, then:
0.81 = 1 - e^(-AFR)
e^(-AFR) = 0.19
AFR = -ln(0.19) = 1.66
Monthly rate = 1.66 × (30/365) = 0.136
Looking at SMART_187_R table:
table[1] = 0.1287→ AFR = 1.565 → P = 79% ✓table[2] = 0.1579→ AFR = 1.920 → P = 85% ✓
Conclusion: SnapRAID is using an attribute value of 1 or 2 for one of the attributes!
4. But We Can't Find That Value!
From both smartctl AND InfluxDB:
- RAW_VALUE = 0 for all 5 attributes
- VALUE (normalized) = 100 for all 5 attributes
- WORST = 100 for all 5 attributes
- No errors, no degradation visible
Current Hypothesis
SnapRAID must be:
- Extracting a specific byte from RAW_VALUE that contains 1-2?
- Using a different field we haven't checked (FLAGS? WHEN_FAILED?)?
- Calculating a derived value from multiple fields?
- Using a different version of the algorithm than GitHub master?
What We Need
Immediate Next Step
Check if RAW_VALUE has byte-level data we're missing:
smartctl -A /dev/sdc | grep -E "^( 5|187|188|197|198)"
Need to see if there are parenthetical byte breakdowns like:
194 Temperature_Celsius 24 (0 15 0 0 0)
^^^^^^^^^^^^^ Individual bytes
Alternative Approaches
- Run SnapRAID with debug/verbose mode to see what values it reads
- Find the smartctl parsing code in SnapRAID source
- Check SnapRAID version - might be using different algorithm
- Contact SnapRAID author if needed
Project Files
Core Implementation
smart_logger_v3.py- Main logger (currently uses Scrutiny's failure rates)backblaze_tables.py- BackBlaze failure rate tables (256 values × 5 attributes)schema_v2.sql- PostgreSQL schema with devices + smart_metrics tablespopulate_devices_final.sql- Your 9 drives' metadata
Debug Scripts
debug_smart_values.py- Check InfluxDB raw SMART valuesdebug_scrutiny_failure_rate.py- Check Scrutiny's calculated ratesdebug_value_field.py- Compare VALUE vs RAW_VALUE fieldstest_backblaze_calc.py- Test BackBlaze calculation with different inputs
Setup
setup_database.sh- PostgreSQL database creationget_device_info.py- Extract device WWNs from InfluxDBrequirements.txt- Python dependencies
Database Schema
devices (manually populated)
device_wwn, device_path, serial_number, model, manufacturer,
capacity_bytes, size_tb, disk_role, notes
smart_metrics (auto-populated by logger)
device_wwn, timestamp, temperature_celsius, power_on_days,
error_count, failure_probability_pct, smart_attributes (JSONB)
Views
smart_latest- Latest metrics per device with metadatasmart_high_risk- Devices >50% failure probabilitysmart_summary- SnapRAID-style summary table
Database Connection Info
-
InfluxDB: cyrion.c0smere.net:8086
- Org: scrutiny
- Bucket: metrics
- Token: (in .env)
-
PostgreSQL: phlegethon.c0smere.net:5432
- Database: smart_monitoring
- User: smart_logger
- Password: saddog095
Next Steps (After Solving Algorithm)
Option 2 Features (After Option 1 Works)
-
Alerts
- Email/webhook when failure probability crosses thresholds
- Trend detection (rapidly increasing failure rate)
- Integration with monitoring systems
-
SnapRAID Integration
- Trigger scrub when high-risk drives detected
- Pre-scrub notifications
- Post-scrub verification
-
Historical Analysis
- Failure probability trends over time
- Predict when drives will cross risk thresholds
- Identify patterns across drive models/manufacturers
-
Custom Queries
- Drive health reports
- Lifetime statistics
- Comparison across drive families
Comparison: SnapRAID vs Scrutiny vs Our Calculator
| Drive | SnapRAID | Scrutiny | Our Calc (raw=0) | Our Calc (val=100) |
|---|---|---|---|---|
| /dev/sdc (d1) | 81% | 11% | 4.63% | 100% |
| /dev/sdb (d2) | 22% | 19% | 4.63% | 100% |
| /dev/sdd (d5) | 51% | 11% | 4.63% | 100% |
| /dev/sda (parity) | 49% | 16% | 4.63% | 100% |
| /dev/sdg (2-parity) | 30% | 12% | 4.63% | 100% |
| /dev/sdh (2-parity) | 4% | 5% | 4.63% | 100% |
| /dev/sde | 4% | 5% | 4.63% | 100% |
| /dev/sdf | 84% | 11% | 4.63% | 100% |
| /dev/sdi | 84% | 11% | 4.63% | 100% |
Pattern: SnapRAID shows high variance (4-84%), we show either 4.63% or 100%.
Questions to Answer
- What exact value does SnapRAID read for attribute 5/187/188/197/198?
- Is SnapRAID using RAW_VALUE, VALUE, WORST, or something else?
- Could there be byte-level parsing we're missing?
- What version of SnapRAID is running, and does it match GitHub master?
- Is there a verbose mode to see what SnapRAID actually reads?
References
Last Updated: 2025-12-05 Status: 🔴 BLOCKED - Cannot match SnapRAID algorithm Blocker: Unknown how SnapRAID calculates 81% with all attributes = 0/100