stamparm/maltrail · error
unable to write event log
Error message
unable to write event log ({e}) What it means
The event log write(2) call itself failed, so the event record was not written at all. The sensor counts the failure in log_write_errors and logs the wrapped OS error, but continues running rather than crashing.
Solutions
- Read the wrapped {e} to identify the OS-level cause (ENOSPC → free space, EIO → check dmesg/storage health).
- If a log rotator is in use, configure it to signal/rename safely or use a rotation mechanism compatible with the sensor's open handle.
- Restart the sensor to re-open the event log if the handle has become stale (e.g. after rotation or unmount).
- Monitor log_write_errors in metrics to gauge how many events were lost during the outage.
Defensive patterns
Strategy: try-catch
Try / catch
// the sensor increments log_write_errors and keeps running;
// on the operator side, detect a stale handle and restart
if log_write_errors_rate > threshold {
restart_sensor(); // reopens the event log after rotation/unmount
} Prevention
- Use rotation tooling compatible with open handles (rename-then-recreate, not truncate-in-place under a stale fd)
- Monitor log_write_errors and disk health (smartctl, dmesg)
- Alert on ENOSPC before it occurs via disk usage alerts
- Avoid remounting or unmounting the log filesystem while the sensor runs
When it happens
Trigger: file.write(line.as_bytes()) returns Err(e) during write_event_log — e.g. ENOSPC, EBADF after the handle was closed/rotated underneath the sensor, or EIO on the underlying device.
Common situations: Log rotation tooling moved/deleted the file while the sensor holds a stale handle; disk full; I/O errors on failing storage hardware; filesystem remounted read-only.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- unable to open event log
- short write to the event log
- invalid configuration value for 'LOG_SERVER
- invalid configuration value for 'LOCAL_LOG_FORMAT
- create log dir
AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13).
Data as JSON: /api/errors/d817285efcffa93d.
Report an issue: GitHub.
Appendix: source
Thrown at sensor/src/output.rs:377
// (An earlier comment here justified this with PIPE_BUF. That was wrong: PIPE_BUF
// bounds atomic writes to PIPES, not regular files. The property being relied on is
// O_APPEND's atomic offset-plus-write, which has no such size bound in practice but is
// also not unlimited — hence treating a short write as an error rather than looping.)
match file.write(line.as_bytes()) {
Ok(n) if n == line.len() => {}
Ok(n) => {
self.log_write_errors += 1;
log_error(
&format!(
"short write to the event log ({n} of {} bytes); the record may be truncated",
line.len()
),
true,
)
}
Err(e) => {
self.log_write_errors += 1;
log_error(&format!("unable to write event log ({e})"), true)
}
}
}
}
/// Matched against "<info> <reference>". Whether a verdict was corroborated lives in the
/// reference, and REMOTE_SEVERITY_REGEX has to see it to rank a heuristic guess below a feed
/// hit the way the dashboard does - `core/log.py:severity_of()` does the same.
fn severity_for(&self, info: &str, reference: &str) -> Severity {
let Some(re) = &self.cfg.severity_regex else {
return Severity::Medium;
};
match re.captures(&format!("{info} {reference}")) {
Ok(Some(caps)) => {
for name in ["low", "medium", "high"] {
if caps.name(name).is_some() {
return match name {
"low" => Severity::Low,View on GitHub (pinned to 77cfb06d76)