createRotatingLog().write does stat, rotate and append as separate awaits with nothing serialising them. Events that arrive together all stat the same old size, none rotates, and they all append, so the file grows past maxBytes. Startup, provider, Discord and tray events are logged independently, so overlap is possible.
Repro (repo root, real createRotatingLog):
import { createRotatingLog } from './src/app-log.js'
const log = createRotatingLog({ file: '/tmp/n.log', maxBytes: 1024, retain: 3 })
await Promise.all(Array.from({ length: 40 }, (_, i) =>
log.write({ time: new Date(i * 1000), level: 'info', component: 'tray', status: 'ok', code: 'C' + i })))
// stat('/tmp/n.log').size -> 3870 with maxBytes 1024, no n.log.1 created
Expected: file stays at or under 1024 bytes, older lines rotate into n.log.1.
Fix: chain writes on one promise queue so check, rotate and append run one at a time, and keep a failed write from blocking the next. A test with the same 40 concurrent writes is in the same file as the existing rotation tests.
Priority: Low.
createRotatingLog().writedoes stat, rotate and append as separate awaits with nothing serialising them. Events that arrive together all stat the same old size, none rotates, and they all append, so the file grows pastmaxBytes. Startup, provider, Discord and tray events are logged independently, so overlap is possible.Repro (repo root, real
createRotatingLog):Expected: file stays at or under 1024 bytes, older lines rotate into
n.log.1.Fix: chain writes on one promise queue so check, rotate and append run one at a time, and keep a failed write from blocking the next. A test with the same 40 concurrent writes is in the same file as the existing rotation tests.
Priority: Low.