Silence noisy logs per environment
Three different “too much noise” problems, three different tools:
| Problem | Reach for |
|---|---|
”Drop everything below info in prod” | logger-wide minLevel |
| ”This one file should only collect errors” | per-channel levels |
| ”Mute health-check / third-party chatter” | per-channel filter |
They stack — minLevel runs first (before any channel), then each channel applies its own levels and filter.
Drop low-severity noise everywhere — minLevel
Section titled “Drop low-severity noise everywhere — minLevel”The cheapest control. Entries below the floor are dropped before fan-out, so no channel sees them and nothing is allocated:
import { log } from "@warlock.js/logger";
log.configure({ // debug + everything below `info` is dropped globally minLevel: process.env.NODE_ENV === "production" ? "info" : "debug",});
// or flip it at runtimelog.setMinLevel("warn");log.setMinLevel(undefined); // clear — accept all levels againSeverity order is debug < info ≈ success < warn < error. minLevel: "warn" drops debug, info, and success (success shares info’s rank). This is the right tool for “production should be quieter than dev.”
Restrict a single channel — levels
Section titled “Restrict a single channel — levels”When the channel should only ever handle certain levels — e.g. a file that’s just an error log — use its levels whitelist. Other channels are unaffected:
import { log, ConsoleLog, FileLog } from "@warlock.js/logger";
log.setChannels([ new ConsoleLog(), // sees every level new FileLog({ name: "errors", // → errors.log (name applies because chunk is "single") levels: ["error", "warn"], // this file only grows with errors + warnings }),]);Omitting levels (or passing []) means “allow all five.” (With chunk: "daily" the file is named by date, not by name — see the rotating-file recipe for the gotcha.)
Mute a chatty module — filter
Section titled “Mute a chatty module — filter”For suppression that levels can’t express — a specific module, a message pattern, a health-check route — pass a filter predicate. It receives the full LoggingData and returns true to keep the entry, false to drop it. It runs after the levels check:
import { ConsoleLog, type LoggingData } from "@warlock.js/logger";
// Drop GET /health spam from the dev terminalnew ConsoleLog({ filter: (data: LoggingData) => !(data.type === "info" && typeof data.message === "string" && data.message.includes("GET /health")),});
// Silence all debug output from a noisy third-party modulenew ConsoleLog({ filter: (data) => !(data.type === "debug" && data.module === "socket.io"),});The predicate is synchronous — it runs on every entry that passes the level check, so keep it cheap and don’t await inside it.
Keep the dev terminal focused on what you’re working on
Section titled “Keep the dev terminal focused on what you’re working on”A handy inverse — surface only the subsystem you’re actively debugging:
new ConsoleLog({ filter: (data) => data.module === "auth" || data.type === "error",});// You see auth logs + every error, nothing else.Putting it together per environment
Section titled “Putting it together per environment”import { log, ConsoleLog, FileLog } from "@warlock.js/logger";
const isProduction = process.env.NODE_ENV === "production";
log.configure({ channels: isProduction ? [ new FileLog({ storagePath: "./storage/logs", chunk: "daily" }), // Own directory — two daily files in one directory would collide // (daily chunking names the file by date, ignoring `name`). new FileLog({ storagePath: "./storage/logs/errors", levels: ["error", "warn"], chunk: "daily" }), ] : [new ConsoleLog({ showContext: true })], minLevel: isProduction ? "info" : "debug",});Dev sees everything (with context expanded); prod drops debug/below globally and keeps a separate error file.
See also
Section titled “See also”- Configuration —
minLeveland the environment-branch pattern - Channels Overview — the
levelswhitelist andfilterpredicate in depth