|
| 1 | +# Log File Index (.index) Implementation |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This implementation adds robust persistence for the `LogFileIndex` variable using a separate `.index` file that survives configuration file resets and provides self-healing capabilities. |
| 6 | + |
| 7 | +## Problem Solved |
| 8 | + |
| 9 | +Previously, `LogFileIndex` was only stored in the configuration file. This caused issues when: |
| 10 | +- Config file was reset to defaults (LogFileIndex lost) |
| 11 | +- Config file was corrupted or deleted |
| 12 | +- Log file existed but config had LogFileIndex = 0 |
| 13 | +- Result: Log data was overwritten or file size tracking was lost |
| 14 | + |
| 15 | +## Solution: Single Source of Truth with .index File |
| 16 | + |
| 17 | +### Architecture |
| 18 | + |
| 19 | +``` |
| 20 | +┌─────────────────┐ |
| 21 | +│ config.json │ ← Configuration only (NO LogFileIndex) |
| 22 | +│ LogFile path │ |
| 23 | +└─────────────────┘ |
| 24 | + ↓ |
| 25 | + (references) |
| 26 | + ↓ |
| 27 | +┌─────────────────┐ |
| 28 | +│ agent.log.index │ ← Single source of truth for write position |
| 29 | +│ 500000 │ |
| 30 | +└─────────────────┘ |
| 31 | + ↓ |
| 32 | + (validates) |
| 33 | + ↓ |
| 34 | +┌─────────────────┐ |
| 35 | +│ agent.log │ ← Actual log file |
| 36 | +│ (500KB data) │ |
| 37 | +└─────────────────┘ |
| 38 | +``` |
| 39 | + |
| 40 | +### Design Principle |
| 41 | + |
| 42 | +**Single Source of Truth**: The `.index` file is the ONLY place where `LogFileIndex` is persisted. |
| 43 | + |
| 44 | +1. **Load**: Read from `.index` file on startup (defaults to 0 if missing) |
| 45 | +2. **Validate**: Compare against actual log file size |
| 46 | +3. **Auto-Correct**: Fix mismatches when safe to do so |
| 47 | +4. **Save**: Write to `.index` file after every log write |
| 48 | + |
| 49 | +## Implementation Details |
| 50 | + |
| 51 | +### New Functions in logging.c |
| 52 | + |
| 53 | +#### `load_log_index()` |
| 54 | +- Reads `LogFileIndex` from `<LogFile>.index` |
| 55 | +- Returns 0 if file doesn't exist |
| 56 | +- Called during log file validation |
| 57 | + |
| 58 | +#### `save_log_index()` |
| 59 | +- Writes current `LogFileIndex` to `<LogFile>.index` |
| 60 | +- Called after every log write operation |
| 61 | +- Simple text file format: single number |
| 62 | + |
| 63 | +#### `validate_and_correct_log_index()` |
| 64 | +- Comprehensive validation logic |
| 65 | +- Handles multiple scenarios (see below) |
| 66 | +- Auto-corrects when safe |
| 67 | +- Warns user when manual intervention needed |
| 68 | + |
| 69 | +#### `log_file_index` (static variable) |
| 70 | +- Local static variable in `logging.c` |
| 71 | +- Replaces `ConfigData->LogFileIndex` |
| 72 | +- Only persisted in `.index` file |
| 73 | + |
| 74 | +### Changes to config.h |
| 75 | + |
| 76 | +- **Removed** `LogFileIndex` field from `ConfigData_t` structure |
| 77 | +- LogFileIndex is no longer part of configuration |
| 78 | + |
| 79 | +### Changes to config.c |
| 80 | + |
| 81 | +- **Removed** reading `LogFileIndex` from JSON |
| 82 | +- **Removed** writing `LogFileIndex` to JSON |
| 83 | +- Added comments noting that LogFileIndex is managed by `logging.c` |
| 84 | +- Config file is now purely configuration, not runtime state |
| 85 | + |
| 86 | +### Validation Logic |
| 87 | + |
| 88 | +#### Case 1: File Hasn't Wrapped (size < MAX_FILE_SIZE) |
| 89 | +``` |
| 90 | +Scenario: actualLogSize = 2MB, log_file_index = 0 (.index missing) |
| 91 | +Action: Auto-correct to 2MB (.index file was deleted) |
| 92 | +Result: ✅ Resumes at end of file, no data loss |
| 93 | +``` |
| 94 | + |
| 95 | +#### Case 2: File Truncated |
| 96 | +``` |
| 97 | +Scenario: actualLogSize = 1MB, LogFileIndex = 3MB |
| 98 | +Action: Auto-correct to 1MB (file was truncated) |
| 99 | +Result: ✅ Resumes at end of file |
| 100 | +``` |
| 101 | + |
| 102 | +#### Case 3: Circular Buffer Active (size >= MAX_FILE_SIZE) |
| 103 | +``` |
| 104 | +Scenario: actualLogSize = 5MB, LogFileIndex = 2MB |
| 105 | +Action: Trust the index (circular buffer position) |
| 106 | +Result: ✅ Continues circular writes correctly |
| 107 | +``` |
| 108 | + |
| 109 | +#### Case 4: Circular Buffer + Missing .index |
| 110 | +``` |
| 111 | +Scenario: actualLogSize = 5MB, log_file_index = 0 (.index missing) |
| 112 | +Action: Warn user, start at 0 (cannot auto-correct) |
| 113 | +Result: ⚠️ May overwrite old logs, but warns user |
| 114 | +``` |
| 115 | + |
| 116 | +#### Case 5: Invalid Index |
| 117 | +``` |
| 118 | +Scenario: log_file_index = 6MB (exceeds MAX_FILE_SIZE) |
| 119 | +Action: Reset to 0 |
| 120 | +Result: Prevents corruption |
| 121 | +``` |
| 122 | + |
| 123 | +## File Format |
| 124 | + |
| 125 | +### .index File Format |
| 126 | +``` |
| 127 | +500000 |
| 128 | +``` |
| 129 | +- Single line containing the LogFileIndex value |
| 130 | +- Plain text, human-readable |
| 131 | +- Can be manually edited if needed |
| 132 | +- Located at: `<LogFile>.index` |
| 133 | + |
| 134 | +Example: |
| 135 | +- Log file: `/var/log/keyfactor-agent.log` |
| 136 | +- Index file: `/var/log/keyfactor-agent.log.index` |
| 137 | + |
| 138 | +## Benefits |
| 139 | + |
| 140 | +### ✅ Clean Separation of Concerns |
| 141 | +- Config file = configuration settings only |
| 142 | +- .index file = runtime state only |
| 143 | +- No confusion about source of truth |
| 144 | + |
| 145 | +### ✅ Survives Config Reset |
| 146 | +- `.index` file persists independently of config |
| 147 | +- Auto-recovers LogFileIndex value |
| 148 | +- No manual intervention needed (in most cases) |
| 149 | + |
| 150 | +### ✅ Self-Healing |
| 151 | +- Detects mismatches between .index and actual file |
| 152 | +- Auto-corrects when safe to do so |
| 153 | +- Comprehensive validation on every write |
| 154 | + |
| 155 | +### ✅ Simpler Implementation |
| 156 | +- Single source of truth (no sync needed) |
| 157 | +- No redundant storage |
| 158 | +- Clearer code logic |
| 159 | + |
| 160 | +### ✅ Circular Buffer Support |
| 161 | +- Correctly handles wrap-around scenarios |
| 162 | +- Validates index doesn't exceed MAX_FILE_SIZE |
| 163 | +- Warns when circular buffer + reset detected |
| 164 | + |
| 165 | +### ✅ Transparent Operation |
| 166 | +- Detailed logging of validation process |
| 167 | +- Clear warnings when issues detected |
| 168 | +- No user action required in normal cases |
| 169 | + |
| 170 | +## Usage |
| 171 | + |
| 172 | +### Normal Operation |
| 173 | +No changes required. The system automatically: |
| 174 | +1. Loads index from `.index` file (or config if missing) |
| 175 | +2. Validates against actual file size |
| 176 | +3. Writes logs |
| 177 | +4. Saves index to both config and `.index` file |
| 178 | + |
| 179 | +### Manual Recovery |
| 180 | +If needed, you can manually edit the `.index` file: |
| 181 | +```bash |
| 182 | +echo "0" > /var/log/keyfactor-agent.log.index |
| 183 | +``` |
| 184 | + |
| 185 | +### Deleting Log File |
| 186 | +If you delete the log file, you should also delete the `.index` file: |
| 187 | +```bash |
| 188 | +rm /var/log/keyfactor-agent.log |
| 189 | +rm /var/log/keyfactor-agent.log.index |
| 190 | +``` |
| 191 | +Or the system will auto-correct on next run. |
| 192 | + |
| 193 | +## Testing Scenarios |
| 194 | + |
| 195 | +### Test 1: .index File Deleted with Existing Log |
| 196 | +``` |
| 197 | +1. Run agent, create 500KB of logs |
| 198 | +2. Delete .index file |
| 199 | +3. Run agent again |
| 200 | +Expected: Auto-corrects to 500KB, resumes at end |
| 201 | +``` |
| 202 | + |
| 203 | +### Test 2: Log File Deleted |
| 204 | +``` |
| 205 | +1. Run agent, create logs |
| 206 | +2. Delete log file (keep config) |
| 207 | +3. Run agent again |
| 208 | +Expected: Creates new log file, starts at 0 |
| 209 | +``` |
| 210 | + |
| 211 | +### Test 3: Circular Buffer Wrap |
| 212 | +``` |
| 213 | +1. Run agent until log reaches 5MB |
| 214 | +2. Continue writing (wraps to beginning) |
| 215 | +3. Restart agent |
| 216 | +Expected: Continues at correct circular position |
| 217 | +``` |
| 218 | + |
| 219 | +### Test 4: .index File Deleted with Wrapped Log |
| 220 | +``` |
| 221 | +1. Run agent until log reaches 5MB |
| 222 | +2. Delete .index file |
| 223 | +3. Run agent |
| 224 | +Expected: Warns user, starts at 0 (may overwrite) |
| 225 | +``` |
| 226 | + |
| 227 | +## Diagnostic Output |
| 228 | + |
| 229 | +The validation process produces detailed output: |
| 230 | +``` |
| 231 | +logging.c::validate_and_correct_log_index(156) : Validating LogFileIndex... |
| 232 | +logging.c::validate_and_correct_log_index(157) : Actual file size: 500000 |
| 233 | +logging.c::validate_and_correct_log_index(158) : Index from .index file: 0 |
| 234 | +logging.c::validate_and_correct_log_index(159) : Index from config: 0 |
| 235 | +logging.c::validate_and_correct_log_index(193) : WARNING: LogFileIndex is 0 but file has 500000 bytes |
| 236 | +logging.c::validate_and_correct_log_index(195) : Config may have been reset. Resuming at end of file |
| 237 | +logging.c::validate_and_correct_log_index(226) : LogFileIndex corrected to 500000 |
| 238 | +``` |
| 239 | + |
| 240 | +## Migration from Old Version |
| 241 | + |
| 242 | +**Breaking Change**: Old config files with `LogFileIndex` field will ignore that value. |
| 243 | + |
| 244 | +Migration steps: |
| 245 | +1. On first run, `.index` file will be created (starting at 0) |
| 246 | +2. If log file exists, validation will auto-correct to end of file |
| 247 | +3. Old `LogFileIndex` in config.json can be safely removed (it's ignored) |
| 248 | +4. Future config saves will not include `LogFileIndex` |
| 249 | + |
| 250 | +**Note**: If you have a running system with accurate `LogFileIndex` in config: |
| 251 | +1. Manually create `.index` file with that value before upgrading |
| 252 | +2. Or accept that logs will resume at end of file (safe for non-wrapped logs) |
| 253 | + |
| 254 | +## Maintenance |
| 255 | + |
| 256 | +### .index File Location |
| 257 | +- Same directory as log file |
| 258 | +- Same name as log file + `.index` extension |
| 259 | +- Can be safely deleted (will be recreated) |
| 260 | + |
| 261 | +### Cleanup |
| 262 | +If you want to start fresh: |
| 263 | +```bash |
| 264 | +rm /var/log/keyfactor-agent.log |
| 265 | +rm /var/log/keyfactor-agent.log.index |
| 266 | +# Edit config.json and set LogFileIndex to 0 |
| 267 | +``` |
| 268 | + |
| 269 | +## Technical Notes |
| 270 | + |
| 271 | +### Thread Safety |
| 272 | +- Not currently thread-safe (single-threaded agent) |
| 273 | +- If multi-threading added, need file locking |
| 274 | + |
| 275 | +### Performance Impact |
| 276 | +- Minimal: one extra file read on startup |
| 277 | +- One extra file write per log flush (already writing config) |
| 278 | +- File I/O is buffered |
| 279 | + |
| 280 | +### Disk Space |
| 281 | +- `.index` file is tiny (< 20 bytes) |
| 282 | +- Negligible impact |
| 283 | + |
| 284 | +## Future Enhancements |
| 285 | + |
| 286 | +Potential improvements: |
| 287 | +1. Add timestamp to .index file for staleness detection |
| 288 | +2. Add checksum for corruption detection |
| 289 | + |
| 290 | +## Summary |
| 291 | + |
| 292 | +The `.index` file approach provides robust, self-healing log file management that survives configuration resets while maintaining full backwards compatibility. It handles edge cases gracefully and provides clear diagnostic output for troubleshooting. |
0 commit comments