Files
skills/docs/api-stack/api/api-audit-file/src/retention/retention.md
2026-05-29 08:20:56 +01:00

2.4 KiB

retention

(no submodules)

Purpose

Enforces the maxFiles retention dimension of the rotation policy by deleting the oldest rotated files until at most maxFiles remain. Retention runs immediately after each rotation succeeds so the disk footprint is bounded across long-running deployments — an audit directory left to grow unchecked is the most common operator pain point with file-based sinks, and this module's existence is exactly the answer to it.

The increment on api.audit.rotation_evicted_total{sink="file"} makes eviction observable. Operators alert on an unexpectedly high rate so a runaway rotation cycle (e.g. clock skew, misconfigured maxAgeMs) is visible before the retention sweep drops historical data.

Features

  • enforceRetention(fs, basePath, maxFiles, instruments) — deletes the oldest rotated files until at most maxFiles remain. Idempotent: re-running with no surplus is a no-op.
  • Counter increment per deletion with the canonical sink="file" attribute set.
  • Surfaces AUDIT_FILE.RETENTION_FAILED on a delete failure with the offending path in context.path and the underlying cause.

Usage: Basic

import { enforceRetention } from "@suaveplan/api-audit-file/retention";

await enforceRetention(fs, "/var/log/audit.log", 30, instruments);

Usage: Advanced

Call from a custom rotation cadence — e.g. an external cron that wants to prune without rotating:

import { enforceRetention } from "@suaveplan/api-audit-file/retention";

// Cron job: every hour, prune to a smaller retention than the sink's
// default to claw back disk during high-traffic windows.
setInterval(async () => {
    await enforceRetention(fs, basePath, 10, instruments);
}, 60 * 60 * 1000);

API Reference

  • enforceRetention(fs: FsAdapter, basePath: string, maxFiles: number, instruments: AuditFileInstruments): Promise<void>

Implementation Notes

listRotatedFiles returns paths sorted oldest-first by the embedded ISO timestamp; we slice off the first (count - maxFiles) entries and unlink them. Sorting is lexicographic on the ISO string, which is also chronological for the YYYY-MM-DDTHH-MM-SS.sssZ shape — no extra parsing required. If unlink fails midway, the previously-evicted deletions are not undone; the throw surfaces the failure and the next rotation re-attempts retention against whatever survived.