@jay-chauhan/logger
v1.0.0
Published
A standalone info/warn/error logger with caller-location banners, .env-driven configuration, and date-based log files.
Maintainers
Readme
@jay-chauhan/logger
A standalone info / warn / error logger with caller-location banners,
.env-driven configuration, and date-based log files. No relation to any
other logging package — a fresh design, not a wrapper or extension.
Install
npm install @jay-chauhan/loggerTo use startAutoCleanup(), also install the optional peer dependency:
npm install node-cronUsage
const Logger = require('@jay-chauhan/logger');
const logger = new Logger(); // reads config from .env + defaults
logger.info('Server started');
logger.warn('Cache miss for key X');
logger.error('Payment failed', err); // accepts a message and/or an Error object
// optional category override — controls the log file path
logger.info('User logged in', 'auth/info');
logger.error('DB connection lost', dbError, 'database/error');
// manual cleanup
logger.cleanupLogs();
// scheduled cleanup (requires node-cron)
logger.startAutoCleanup();
logger.stopAutoCleanup();Each level writes to its own log file per category, under a human-readable dated folder structure:
log/2026/July/29/category/name.log(Year → full month name → zero-padded day → category → file.)
Output format
==================================================
Error: /home/jay/projects/api/src/services/payment.js:42
==================================================
Payment failed for order #4821
TypeError: Cannot read properties of undefined (reading 'id')
at processPayment (/home/jay/projects/api/src/services/payment.js:42:18)
...stack...
==================================================
- The banner label (
Error:/Warning:/Info:) is followed by the absolute file path and line number of the call site — not the logger's own internal code. - If an
Errorobject is passed, its.stackis appended below the message. - A trailing blank line separates entries when tailing the file.
Configuration
Resolved in priority order (highest wins):
- Options object passed to
new Logger({ ... }) .envvariables (loaded once, lazily, viadotenv)- Hardcoded defaults
| Key | Option | Default | Purpose |
|---|---|---|---|
| LOG_DIR | logDir | log | Where logs are written, relative to the project root unless absolute |
| LOG_RETENTION_DAYS | retentionDays | 7 | Cleanup age threshold, in days |
| LOG_LEVEL | level | info | Minimum level written (error < warn < info in verbosity) |
| LOG_TO_CONSOLE | toConsole | true | Mirror entries to stdout/stderr |
| LOG_COLOR | color | true | Colorize console output |
| LOG_AUTO_CLEANUP | autoCleanup | false | Self-schedule cleanup on instantiation |
| LOG_CLEANUP_CRON | cleanupCron | 0 0 * * * | Cron expression if auto-cleanup is on |
| LOG_MAX_FILE_SIZE_MB | maxFileSizeMb | 0 (disabled) | Size-based rotation (not yet implemented) |
new Logger({ projectRoot }) can override project-root discovery, which
otherwise walks up from require.main.filename until it finds a
package.json, falling back to process.cwd().
Level filtering
error (highest severity, always most important)
warn
info (lowest severity)LOG_LEVEL=warn writes error and warn, and skips info. Skipped levels
short-circuit before any stack-trace capture or file I/O.
API
logger.info(message, category?)
Banner label Info:. Writes to log/YYYY/MonthName/DD/{category||'app/info'}.log
and mirrors to console.log if LOG_TO_CONSOLE.
logger.warn(message, category?)
Banner label Warning:. Same mechanics, default category app/warn,
mirrors to console.warn.
logger.error(message, errorOrCategory?, category?)
Banner label Error:. Overloads:
logger.error('msg');
logger.error('msg', err);
logger.error('msg', err, 'category');
logger.error('msg', 'category'); // no Error objectIf an Error instance is present, its .stack is appended under the
message. Default category app/error. Mirrors to console.error.
logger.cleanupLogs()
Recursively deletes files (and resulting empty folders) older than
retentionDays, based on file mtime — this doesn't depend on parsing the
date out of the folder name.
logger.startAutoCleanup() / logger.stopAutoCleanup()
Schedules cleanupLogs() on cleanupCron using node-cron. Throws a clear
error if node-cron isn't installed, since it's an optional peer dependency.
Safety notes
- Category sanitization — the
categoryargument is stripped of..and empty/.segments before being joined into a file path, since it may originate from user-influenced strings. - Write failures don't crash the host app — if a log write fails
(permissions, disk full), the entry is dumped to
console.errorinstead of throwing. - Circular-safe message formatting — object messages that fail
JSON.stringify(circular references) fall back toutil.inspect. - Config validated at construction — an unwritable
LOG_DIRor an invalidLOG_LEVELthrows immediately rather than failing silently later. An invalidLOG_CLEANUP_CRONthrows whenstartAutoCleanup()is called.
Testing
npm testRuns unit tests for formatter/caller/cleanup as pure functions, plus an
integration test that runs a Logger against a temp directory and asserts
on actual file contents.
