Log to a rotating file in production
You want production logs on disk: one file per day, capped so a single file never grows without bound, and guaranteed to flush the last entries when the container stops. That’s three options on FileLog plus one autoFlushOn.
The setup
Section titled “The setup”import { log, ConsoleLog, FileLog } from "@warlock.js/logger";
const isProduction = process.env.NODE_ENV === "production";
log.configure({ channels: isProduction ? [ new FileLog({ storagePath: process.cwd() + "/storage/logs", chunk: "daily", // one file per calendar day → 2024-03-15.log rotate: true, // roll the file over once it gets too big maxFileSize: 10 * 1024 * 1024, // 10 MB per file before rotation retention: { maxFiles: 30, maxAgeDays: 30 }, // prune old days and archives }), ] : [new ConsoleLog()], // Drain the in-memory buffer before the process exits. autoFlushOn: ["SIGINT", "SIGTERM", "beforeExit"],});Import it once, as early as possible:
import "./logger"; // side-effect: configures the singleton
import { log } from "@warlock.js/logger";
log.info("app", "boot", "Server listening on :3000");What each piece does
Section titled “What each piece does”chunk: "daily"names the file by ISO date, so you get2024-03-15.log,2024-03-16.log, … (sorted by name = sorted by day) instead of one ever-growingapp.log. Use"hourly"for very high volume,"single"(the default) for a single file, orfileName: "app-{YYYY}-{MM}-{DD}"for your own pattern.rotate: true(the default) checks the active file’s size before each write and, once it passesmaxFileSize, renames it aside (2024-03-15-2024-03-15-1710494523000.log) and starts a fresh one.retentionremoves this channel’s old files — on boot and whenever a new file starts — keeping the 30 newest and none older than 30 days. Only files matching the channel’s name pattern are touched; failures go toonChannelError, never to the call site.maxFileSizeis in bytes —10 * 1024 * 1024is 10 MB, which is also the default.autoFlushOnis the important one.FileLogbuffers entries in memory (it flushes at 100 entries or every 5 seconds), so a process that exits without draining loses whatever is still buffered. WiringSIGINT/SIGTERM/beforeExitmakes the logger flush onCtrl+C,docker stop, and natural exit. See Shutdown & flushing.
Keeping errors in their own file
Section titled “Keeping errors in their own file”A common refinement: everything goes to the daily file, and errors and warnings get their own dedicated file so on-call doesn’t have to grep the firehose.
log.setChannels([ new FileLog({ storagePath: "./storage/logs", chunk: "daily" }), new FileLog({ storagePath: "./storage/logs/errors", // ← its own directory levels: ["error", "warn"], // only these reach this file chunk: "daily", }),]);The levels whitelist is per channel — the first file still records everything. See Channels Overview for the filtering model.
See also
Section titled “See also”- File Channel — every
FileLogoption in detail - Shutdown & flushing — why the buffer needs draining and how
autoFlushOndoes it - JSON File Channel — swap
FileLogforJSONFileLogwhen a log aggregator reads the files