@warlock.js/logger 5.3.2 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/llms-full.txt +88 -88
- package/llms.txt +1 -1
- package/package.json +2 -2
- package/skills/logger-basics/SKILL.md +88 -88
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to `@warlock.js/logger` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
6
|
|
|
7
|
+
## 5.5.0 - 2026-09-07
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Documentation shipped in this package's `skills/` told users to run `pnpm`-specific commands. `pnpm <binary>` has no npm equivalent, so those instructions failed outright for anyone not using pnpm. Commands are now package-manager neutral.
|
|
12
|
+
|
|
7
13
|
## 5.2.3 - 2026-09-02
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/llms-full.txt
CHANGED
|
@@ -475,94 +475,94 @@ captureAnyUnhandledRejection();
|
|
|
475
475
|
|
|
476
476
|
## logger-basics `@warlock.js/logger/logger-basics/SKILL.md`
|
|
477
477
|
|
|
478
|
-
---
|
|
479
|
-
name: logger-basics
|
|
480
|
-
description: 'Start with @warlock.js/logger — the log singleton, six levels (debug / info / warn / error / success / fatal), channel fan-out, foundations. Triggers: `log`, `Logger`, `log.info`, `log.error`, `log.fatal`, `log.debug`, `log.warn`, `log.success`, `ConsoleLog`, `FileLog`, `JSONFileLog`; "how do I log in node", "warlock logger basics", "which logger skill do I need"; typical import `import { log, ConsoleLog, FileLog } from "@warlock.js/logger"`. Skip: channel picks — `@warlock.js/logger/pick-log-channel/SKILL.md`; setup — `@warlock.js/logger/configure-logger/SKILL.md`; competing libs `winston`, `pino`, `bunyan`, `log4js`, `signale`; native `console.log`.'
|
|
481
|
-
---
|
|
482
|
-
|
|
483
|
-
# Log with channels
|
|
484
|
-
|
|
485
|
-
Multi-channel structured logger for Node.js. Four built-in channels (`ConsoleLog`, `FileLog`, `JSONFileLog`, `SentryLog`), an abstract `LogChannel` base for custom sinks, six severity levels, and a safe shutdown path via `Logger.enableAutoFlush(events)` plus async `log.flush()` for network channels.
|
|
486
|
-
|
|
487
|
-
> This skill is the logger **map** — read it first, then load the specific skill for the task.
|
|
488
|
-
|
|
489
|
-
## Install
|
|
490
|
-
|
|
491
|
-
```bash
|
|
492
|
-
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
## Foundations
|
|
496
|
-
|
|
497
|
-
The 11 things that are true in every logger use:
|
|
498
|
-
|
|
499
|
-
1. **Public API is the `log` singleton** (`import { log } from "@warlock.js/logger"`). It's a `Logger` instance — call `log.info(...)`, `log.configure(...)`, etc. No callable `log(data)` form.
|
|
500
|
-
2. **The singleton starts with zero channels.** Nothing is written until at least one channel is registered via `addChannel`, `setChannels`, or `configure`.
|
|
501
|
-
3. **Custom instances:** `new Logger()` gives an isolated logger with the identical API. Almost always you want the singleton — reach for the class only when you need an isolated channel set (libraries, test sandboxes).
|
|
502
|
-
4. **Six levels, closed union:** `"debug" | "info" | "warn" | "error" | "success" | "fatal"`. `fatal` ranks strictly above `error` — use it for unrecoverable failures where the app is going down (failed bootstrap, `uncaughtException`). There are no custom levels.
|
|
503
|
-
5. **Channels can be filtered two ways:** a `levels` array (whitelist) and a `filter` predicate (custom logic). Both run on every entry. See [`@warlock.js/logger/filter-log-entries/SKILL.md`](@warlock.js/logger/filter-log-entries/SKILL.md).
|
|
504
|
-
6. **Logger-wide minimum severity** is available via `log.setMinLevel("info")` (or `configure({ minLevel })`). Entries below the rank are dropped before fan-out — cheaper than per-channel filters.
|
|
505
|
-
7. **Redaction** is two-layer additive: `configure({ redact })` sets the logger floor; `new XxxChannel({ redact: { paths: [...] } })` adds more paths on top. Channels can never remove paths from the logger floor. See [`@warlock.js/logger/redact-sensitive-log-fields/SKILL.md`](@warlock.js/logger/redact-sensitive-log-fields/SKILL.md).
|
|
506
|
-
8. **`FileLog` and `JSONFileLog` buffer in memory.** They flush when `maxMessagesToWrite` (default `100`) is hit, when 5 seconds have elapsed since the last write, or when `flushSync()` is called. See [`@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md).
|
|
507
|
-
9. **Non-terminal channels receive ANSI-stripped messages.** `Logger.log` shallow-clones the entry per non-terminal channel before stripping, so later terminal channels still get the colored original.
|
|
508
|
-
10. **`JSONFileLog.extension` is always `"json"`.** The option is ignored for this channel.
|
|
509
|
-
11. **`captureAnyUnhandledRejection()` registers process listeners.** Call it once at startup, after channels are registered. Calling it twice installs duplicate listeners. See [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md).
|
|
510
|
-
|
|
511
|
-
## Minimal startup example
|
|
512
|
-
|
|
513
|
-
```ts
|
|
514
|
-
import { log, ConsoleLog, FileLog } from "@warlock.js/logger";
|
|
515
|
-
|
|
516
|
-
log.configure({
|
|
517
|
-
channels: [
|
|
518
|
-
new ConsoleLog(),
|
|
519
|
-
new FileLog({ chunk: "daily", storagePath: "./storage/logs" }),
|
|
520
|
-
],
|
|
521
|
-
autoFlushOn: ["SIGINT", "SIGTERM", "beforeExit"],
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
await log.info("users", "register", "New user created");
|
|
525
|
-
await log.error("payments", "charge", new Error("Card declined"));
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
## The six levels
|
|
529
|
-
|
|
530
|
-
```ts
|
|
531
|
-
log.debug("module", "action", "verbose detail"); // dev-only diagnostics
|
|
532
|
-
log.info("module", "action", "neutral event"); // user-visible event
|
|
533
|
-
log.warn("module", "action", "something off"); // recoverable concern
|
|
534
|
-
log.error("module", "action", error); // handled failure, app continues
|
|
535
|
-
log.success("module", "action", "operation done"); // explicit success
|
|
536
|
-
log.fatal("module", "action", error); // unrecoverable, app is going down
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
`fatal` is purely informational — it does NOT auto-flush or exit. The caller decides whether to `await log.flush()` and `process.exit(...)`. See [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md) for the `uncaughtException` → `fatal` routing.
|
|
540
|
-
|
|
541
|
-
Every call signature is the same — `module`, `action`, `message`, optional `context`. `message` can be a string, object, or `Error` instance (file channels capture the stack).
|
|
542
|
-
|
|
543
|
-
## Pick a skill
|
|
544
|
-
|
|
545
|
-
| If the task is about… | Load |
|
|
546
|
-
| --- | --- |
|
|
547
|
-
| Picking a channel — what each built-in does, when to use which | [`@warlock.js/logger/pick-log-channel/SKILL.md`](@warlock.js/logger/pick-log-channel/SKILL.md) |
|
|
548
|
-
| Startup — registering channels, environment-based setup, the `configure` method | [`@warlock.js/logger/configure-logger/SKILL.md`](@warlock.js/logger/configure-logger/SKILL.md) |
|
|
549
|
-
| Filtering log output (`levels`, `filter`, per-channel routing, `minLevel`) | [`@warlock.js/logger/filter-log-entries/SKILL.md`](@warlock.js/logger/filter-log-entries/SKILL.md) |
|
|
550
|
-
| Graceful shutdown — `flushSync`, `autoFlushOn`, signal behavior | [`@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md) |
|
|
551
|
-
| Extending `LogChannel` to build a custom sink (Slack, database, HTTP) | [`@warlock.js/logger/write-custom-log-channel/SKILL.md`](@warlock.js/logger/write-custom-log-channel/SKILL.md) |
|
|
552
|
-
| Routing Node's `unhandledRejection` / `uncaughtException` through the logger | [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md) |
|
|
553
|
-
| `log.assert(...)` and `log.timer(...)` shorthand helpers | [`@warlock.js/logger/use-log-helpers/SKILL.md`](@warlock.js/logger/use-log-helpers/SKILL.md) |
|
|
554
|
-
| Redacting secrets — logger floor + additive channel paths | [`@warlock.js/logger/redact-sensitive-log-fields/SKILL.md`](@warlock.js/logger/redact-sensitive-log-fields/SKILL.md) |
|
|
555
|
-
| Tests that assert on log output, or code under test that logs | [`@warlock.js/logger/test-logging-code/SKILL.md`](@warlock.js/logger/test-logging-code/SKILL.md) |
|
|
556
|
-
|
|
557
|
-
## Things NOT to do
|
|
558
|
-
|
|
559
|
-
- Don't try `log(module, action, message)` or `log({...})` directly — `log` is a `Logger` instance, not a function. Use `log.info(...)`, `log.error(...)`, etc., or the explicit `log.log({ type, module, action, message })` for the data-object form.
|
|
560
|
-
- Don't set `extension` on `JSONFileLog` — it's hardcoded to `"json"` and your value is silently ignored.
|
|
561
|
-
- Don't register multiple `FileLog` instances with the same `name` in the same `storagePath` — the lookup via `log.channel("file")` returns only one, and they'll fight over the same file.
|
|
562
|
-
- Don't mix `autoFlushOn: ["SIGINT"]` with your own `process.on("SIGINT", ...)` handler — both fire, and ours re-raises mid-way through your async work.
|
|
563
|
-
- Don't `await log.info(...)` expecting the write to be on disk — `FileLog` buffers. Call `log.flushSync()` (or rely on `autoFlushOn`) before the process exits.
|
|
564
|
-
- Don't call `captureAnyUnhandledRejection()` more than once — it re-registers listeners every call and your rejections get logged N times.
|
|
565
|
-
- Don't shadow the import in local code: `for (const log of logEntries) { ... }` will hide the singleton inside that block. Rename loop variables (`entry`, `record`) when working with logger imports.
|
|
478
|
+
---
|
|
479
|
+
name: logger-basics
|
|
480
|
+
description: 'Start with @warlock.js/logger — the log singleton, six levels (debug / info / warn / error / success / fatal), channel fan-out, foundations. Triggers: `log`, `Logger`, `log.info`, `log.error`, `log.fatal`, `log.debug`, `log.warn`, `log.success`, `ConsoleLog`, `FileLog`, `JSONFileLog`; "how do I log in node", "warlock logger basics", "which logger skill do I need"; typical import `import { log, ConsoleLog, FileLog } from "@warlock.js/logger"`. Skip: channel picks — `@warlock.js/logger/pick-log-channel/SKILL.md`; setup — `@warlock.js/logger/configure-logger/SKILL.md`; competing libs `winston`, `pino`, `bunyan`, `log4js`, `signale`; native `console.log`.'
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
# Log with channels
|
|
484
|
+
|
|
485
|
+
Multi-channel structured logger for Node.js. Four built-in channels (`ConsoleLog`, `FileLog`, `JSONFileLog`, `SentryLog`), an abstract `LogChannel` base for custom sinks, six severity levels, and a safe shutdown path via `Logger.enableAutoFlush(events)` plus async `log.flush()` for network channels.
|
|
486
|
+
|
|
487
|
+
> This skill is the logger **map** — read it first, then load the specific skill for the task.
|
|
488
|
+
|
|
489
|
+
## Install
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
npm install @warlock.js/logger
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
## Foundations
|
|
496
|
+
|
|
497
|
+
The 11 things that are true in every logger use:
|
|
498
|
+
|
|
499
|
+
1. **Public API is the `log` singleton** (`import { log } from "@warlock.js/logger"`). It's a `Logger` instance — call `log.info(...)`, `log.configure(...)`, etc. No callable `log(data)` form.
|
|
500
|
+
2. **The singleton starts with zero channels.** Nothing is written until at least one channel is registered via `addChannel`, `setChannels`, or `configure`.
|
|
501
|
+
3. **Custom instances:** `new Logger()` gives an isolated logger with the identical API. Almost always you want the singleton — reach for the class only when you need an isolated channel set (libraries, test sandboxes).
|
|
502
|
+
4. **Six levels, closed union:** `"debug" | "info" | "warn" | "error" | "success" | "fatal"`. `fatal` ranks strictly above `error` — use it for unrecoverable failures where the app is going down (failed bootstrap, `uncaughtException`). There are no custom levels.
|
|
503
|
+
5. **Channels can be filtered two ways:** a `levels` array (whitelist) and a `filter` predicate (custom logic). Both run on every entry. See [`@warlock.js/logger/filter-log-entries/SKILL.md`](@warlock.js/logger/filter-log-entries/SKILL.md).
|
|
504
|
+
6. **Logger-wide minimum severity** is available via `log.setMinLevel("info")` (or `configure({ minLevel })`). Entries below the rank are dropped before fan-out — cheaper than per-channel filters.
|
|
505
|
+
7. **Redaction** is two-layer additive: `configure({ redact })` sets the logger floor; `new XxxChannel({ redact: { paths: [...] } })` adds more paths on top. Channels can never remove paths from the logger floor. See [`@warlock.js/logger/redact-sensitive-log-fields/SKILL.md`](@warlock.js/logger/redact-sensitive-log-fields/SKILL.md).
|
|
506
|
+
8. **`FileLog` and `JSONFileLog` buffer in memory.** They flush when `maxMessagesToWrite` (default `100`) is hit, when 5 seconds have elapsed since the last write, or when `flushSync()` is called. See [`@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md).
|
|
507
|
+
9. **Non-terminal channels receive ANSI-stripped messages.** `Logger.log` shallow-clones the entry per non-terminal channel before stripping, so later terminal channels still get the colored original.
|
|
508
|
+
10. **`JSONFileLog.extension` is always `"json"`.** The option is ignored for this channel.
|
|
509
|
+
11. **`captureAnyUnhandledRejection()` registers process listeners.** Call it once at startup, after channels are registered. Calling it twice installs duplicate listeners. See [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md).
|
|
510
|
+
|
|
511
|
+
## Minimal startup example
|
|
512
|
+
|
|
513
|
+
```ts
|
|
514
|
+
import { log, ConsoleLog, FileLog } from "@warlock.js/logger";
|
|
515
|
+
|
|
516
|
+
log.configure({
|
|
517
|
+
channels: [
|
|
518
|
+
new ConsoleLog(),
|
|
519
|
+
new FileLog({ chunk: "daily", storagePath: "./storage/logs" }),
|
|
520
|
+
],
|
|
521
|
+
autoFlushOn: ["SIGINT", "SIGTERM", "beforeExit"],
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
await log.info("users", "register", "New user created");
|
|
525
|
+
await log.error("payments", "charge", new Error("Card declined"));
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
## The six levels
|
|
529
|
+
|
|
530
|
+
```ts
|
|
531
|
+
log.debug("module", "action", "verbose detail"); // dev-only diagnostics
|
|
532
|
+
log.info("module", "action", "neutral event"); // user-visible event
|
|
533
|
+
log.warn("module", "action", "something off"); // recoverable concern
|
|
534
|
+
log.error("module", "action", error); // handled failure, app continues
|
|
535
|
+
log.success("module", "action", "operation done"); // explicit success
|
|
536
|
+
log.fatal("module", "action", error); // unrecoverable, app is going down
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
`fatal` is purely informational — it does NOT auto-flush or exit. The caller decides whether to `await log.flush()` and `process.exit(...)`. See [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md) for the `uncaughtException` → `fatal` routing.
|
|
540
|
+
|
|
541
|
+
Every call signature is the same — `module`, `action`, `message`, optional `context`. `message` can be a string, object, or `Error` instance (file channels capture the stack).
|
|
542
|
+
|
|
543
|
+
## Pick a skill
|
|
544
|
+
|
|
545
|
+
| If the task is about… | Load |
|
|
546
|
+
| --- | --- |
|
|
547
|
+
| Picking a channel — what each built-in does, when to use which | [`@warlock.js/logger/pick-log-channel/SKILL.md`](@warlock.js/logger/pick-log-channel/SKILL.md) |
|
|
548
|
+
| Startup — registering channels, environment-based setup, the `configure` method | [`@warlock.js/logger/configure-logger/SKILL.md`](@warlock.js/logger/configure-logger/SKILL.md) |
|
|
549
|
+
| Filtering log output (`levels`, `filter`, per-channel routing, `minLevel`) | [`@warlock.js/logger/filter-log-entries/SKILL.md`](@warlock.js/logger/filter-log-entries/SKILL.md) |
|
|
550
|
+
| Graceful shutdown — `flushSync`, `autoFlushOn`, signal behavior | [`@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md) |
|
|
551
|
+
| Extending `LogChannel` to build a custom sink (Slack, database, HTTP) | [`@warlock.js/logger/write-custom-log-channel/SKILL.md`](@warlock.js/logger/write-custom-log-channel/SKILL.md) |
|
|
552
|
+
| Routing Node's `unhandledRejection` / `uncaughtException` through the logger | [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md) |
|
|
553
|
+
| `log.assert(...)` and `log.timer(...)` shorthand helpers | [`@warlock.js/logger/use-log-helpers/SKILL.md`](@warlock.js/logger/use-log-helpers/SKILL.md) |
|
|
554
|
+
| Redacting secrets — logger floor + additive channel paths | [`@warlock.js/logger/redact-sensitive-log-fields/SKILL.md`](@warlock.js/logger/redact-sensitive-log-fields/SKILL.md) |
|
|
555
|
+
| Tests that assert on log output, or code under test that logs | [`@warlock.js/logger/test-logging-code/SKILL.md`](@warlock.js/logger/test-logging-code/SKILL.md) |
|
|
556
|
+
|
|
557
|
+
## Things NOT to do
|
|
558
|
+
|
|
559
|
+
- Don't try `log(module, action, message)` or `log({...})` directly — `log` is a `Logger` instance, not a function. Use `log.info(...)`, `log.error(...)`, etc., or the explicit `log.log({ type, module, action, message })` for the data-object form.
|
|
560
|
+
- Don't set `extension` on `JSONFileLog` — it's hardcoded to `"json"` and your value is silently ignored.
|
|
561
|
+
- Don't register multiple `FileLog` instances with the same `name` in the same `storagePath` — the lookup via `log.channel("file")` returns only one, and they'll fight over the same file.
|
|
562
|
+
- Don't mix `autoFlushOn: ["SIGINT"]` with your own `process.on("SIGINT", ...)` handler — both fire, and ours re-raises mid-way through your async work.
|
|
563
|
+
- Don't `await log.info(...)` expecting the write to be on disk — `FileLog` buffers. Call `log.flushSync()` (or rely on `autoFlushOn`) before the process exits.
|
|
564
|
+
- Don't call `captureAnyUnhandledRejection()` more than once — it re-registers listeners every call and your rejections get logged N times.
|
|
565
|
+
- Don't shadow the import in local code: `for (const log of logEntries) { ... }` will hide the singleton inside that block. Rename loop variables (`entry`, `record`) when working with logger imports.
|
|
566
566
|
|
|
567
567
|
|
|
568
568
|
## overview `@warlock.js/logger/overview/SKILL.md`
|
package/llms.txt
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
- [configure-logger](@warlock.js/logger/configure-logger/SKILL.md): Register channels via log.addChannel / log.setChannels / log.configure({channels, autoFlushOn, redact, minLevel}) at boot. Triggers: `log.configure`, `log.addChannel`, `log.setChannels`, `Logger`, `autoFlushOn`, `disableAutoFlush`; "wire channels at startup", "branch logger by NODE_ENV", "isolate a library's logger", "replace channel list"; typical import `import { log, Logger, ConsoleLog, FileLog } from "@warlock.js/logger"`. Skip: channel picks — `@warlock.js/logger/pick-log-channel/SKILL.md`; flushing — `@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`; redaction — `@warlock.js/logger/redact-sensitive-log-fields/SKILL.md`; competing libs `winston.createLogger`, `pino`.
|
|
11
11
|
- [filter-log-entries](@warlock.js/logger/filter-log-entries/SKILL.md): (no description)
|
|
12
12
|
- [flush-logs-on-shutdown](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md): (no description)
|
|
13
|
-
- [logger-basics](@warlock.js/logger/logger-basics/SKILL.md): (
|
|
13
|
+
- [logger-basics](@warlock.js/logger/logger-basics/SKILL.md): Start with @warlock.js/logger — the log singleton, six levels (debug / info / warn / error / success / fatal), channel fan-out, foundations. Triggers: `log`, `Logger`, `log.info`, `log.error`, `log.fatal`, `log.debug`, `log.warn`, `log.success`, `ConsoleLog`, `FileLog`, `JSONFileLog`; "how do I log in node", "warlock logger basics", "which logger skill do I need"; typical import `import { log, ConsoleLog, FileLog } from "@warlock.js/logger"`. Skip: channel picks — `@warlock.js/logger/pick-log-channel/SKILL.md`; setup — `@warlock.js/logger/configure-logger/SKILL.md`; competing libs `winston`, `pino`, `bunyan`, `log4js`, `signale`; native `console.log`.
|
|
14
14
|
- [overview](@warlock.js/logger/overview/SKILL.md): (no description)
|
|
15
15
|
- [pick-log-channel](@warlock.js/logger/pick-log-channel/SKILL.md): (no description)
|
|
16
16
|
- [redact-sensitive-log-fields](@warlock.js/logger/redact-sensitive-log-fields/SKILL.md): Strip secrets from log output — a built-in secret-key denylist on by default (DEFAULT_REDACT_KEYS), plus two-layer additive redaction via log.configure({redact: {paths, keys}}) (logger floor) + per-channel redact (more on top). Dotted glob paths (*, **). Triggers: `redact`, `paths`, `keys`, `defaultKeys`, `censor`, `log.setRedact`, `applyRedact`; "redact passwords in logs", "strip tokens from log output", "hide authorization headers", "scrub PII before logging", "turn off default redaction"; typical import `import { log } from "@warlock.js/logger"`. Skip: filtering — `@warlock.js/logger/filter-log-entries/SKILL.md`; custom sinks — `@warlock.js/logger/write-custom-log-channel/SKILL.md`; competing libs `pino.redact`, `fast-redact`.
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@mongez/copper": "^2.1.2",
|
|
6
6
|
"@mongez/reinforcements": "^4.0.1",
|
|
7
|
-
"@warlock.js/fs": "5.
|
|
7
|
+
"@warlock.js/fs": "5.5.0",
|
|
8
8
|
"dayjs": "^1.11.9",
|
|
9
9
|
"safe-stable-stringify": "^2.5.0"
|
|
10
10
|
},
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"warlock": {
|
|
33
33
|
"environment": "server"
|
|
34
34
|
},
|
|
35
|
-
"version": "5.
|
|
35
|
+
"version": "5.5.0",
|
|
36
36
|
"main": "./cjs/index.cjs",
|
|
37
37
|
"module": "./esm/index.mjs",
|
|
38
38
|
"types": "./esm/index.d.mts",
|
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: logger-basics
|
|
3
|
-
description: 'Start with @warlock.js/logger — the log singleton, six levels (debug / info / warn / error / success / fatal), channel fan-out, foundations. Triggers: `log`, `Logger`, `log.info`, `log.error`, `log.fatal`, `log.debug`, `log.warn`, `log.success`, `ConsoleLog`, `FileLog`, `JSONFileLog`; "how do I log in node", "warlock logger basics", "which logger skill do I need"; typical import `import { log, ConsoleLog, FileLog } from "@warlock.js/logger"`. Skip: channel picks — `@warlock.js/logger/pick-log-channel/SKILL.md`; setup — `@warlock.js/logger/configure-logger/SKILL.md`; competing libs `winston`, `pino`, `bunyan`, `log4js`, `signale`; native `console.log`.'
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Log with channels
|
|
7
|
-
|
|
8
|
-
Multi-channel structured logger for Node.js. Four built-in channels (`ConsoleLog`, `FileLog`, `JSONFileLog`, `SentryLog`), an abstract `LogChannel` base for custom sinks, six severity levels, and a safe shutdown path via `Logger.enableAutoFlush(events)` plus async `log.flush()` for network channels.
|
|
9
|
-
|
|
10
|
-
> This skill is the logger **map** — read it first, then load the specific skill for the task.
|
|
11
|
-
|
|
12
|
-
## Install
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Foundations
|
|
19
|
-
|
|
20
|
-
The 11 things that are true in every logger use:
|
|
21
|
-
|
|
22
|
-
1. **Public API is the `log` singleton** (`import { log } from "@warlock.js/logger"`). It's a `Logger` instance — call `log.info(...)`, `log.configure(...)`, etc. No callable `log(data)` form.
|
|
23
|
-
2. **The singleton starts with zero channels.** Nothing is written until at least one channel is registered via `addChannel`, `setChannels`, or `configure`.
|
|
24
|
-
3. **Custom instances:** `new Logger()` gives an isolated logger with the identical API. Almost always you want the singleton — reach for the class only when you need an isolated channel set (libraries, test sandboxes).
|
|
25
|
-
4. **Six levels, closed union:** `"debug" | "info" | "warn" | "error" | "success" | "fatal"`. `fatal` ranks strictly above `error` — use it for unrecoverable failures where the app is going down (failed bootstrap, `uncaughtException`). There are no custom levels.
|
|
26
|
-
5. **Channels can be filtered two ways:** a `levels` array (whitelist) and a `filter` predicate (custom logic). Both run on every entry. See [`@warlock.js/logger/filter-log-entries/SKILL.md`](@warlock.js/logger/filter-log-entries/SKILL.md).
|
|
27
|
-
6. **Logger-wide minimum severity** is available via `log.setMinLevel("info")` (or `configure({ minLevel })`). Entries below the rank are dropped before fan-out — cheaper than per-channel filters.
|
|
28
|
-
7. **Redaction** is two-layer additive: `configure({ redact })` sets the logger floor; `new XxxChannel({ redact: { paths: [...] } })` adds more paths on top. Channels can never remove paths from the logger floor. See [`@warlock.js/logger/redact-sensitive-log-fields/SKILL.md`](@warlock.js/logger/redact-sensitive-log-fields/SKILL.md).
|
|
29
|
-
8. **`FileLog` and `JSONFileLog` buffer in memory.** They flush when `maxMessagesToWrite` (default `100`) is hit, when 5 seconds have elapsed since the last write, or when `flushSync()` is called. See [`@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md).
|
|
30
|
-
9. **Non-terminal channels receive ANSI-stripped messages.** `Logger.log` shallow-clones the entry per non-terminal channel before stripping, so later terminal channels still get the colored original.
|
|
31
|
-
10. **`JSONFileLog.extension` is always `"json"`.** The option is ignored for this channel.
|
|
32
|
-
11. **`captureAnyUnhandledRejection()` registers process listeners.** Call it once at startup, after channels are registered. Calling it twice installs duplicate listeners. See [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md).
|
|
33
|
-
|
|
34
|
-
## Minimal startup example
|
|
35
|
-
|
|
36
|
-
```ts
|
|
37
|
-
import { log, ConsoleLog, FileLog } from "@warlock.js/logger";
|
|
38
|
-
|
|
39
|
-
log.configure({
|
|
40
|
-
channels: [
|
|
41
|
-
new ConsoleLog(),
|
|
42
|
-
new FileLog({ chunk: "daily", storagePath: "./storage/logs" }),
|
|
43
|
-
],
|
|
44
|
-
autoFlushOn: ["SIGINT", "SIGTERM", "beforeExit"],
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
await log.info("users", "register", "New user created");
|
|
48
|
-
await log.error("payments", "charge", new Error("Card declined"));
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## The six levels
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
log.debug("module", "action", "verbose detail"); // dev-only diagnostics
|
|
55
|
-
log.info("module", "action", "neutral event"); // user-visible event
|
|
56
|
-
log.warn("module", "action", "something off"); // recoverable concern
|
|
57
|
-
log.error("module", "action", error); // handled failure, app continues
|
|
58
|
-
log.success("module", "action", "operation done"); // explicit success
|
|
59
|
-
log.fatal("module", "action", error); // unrecoverable, app is going down
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
`fatal` is purely informational — it does NOT auto-flush or exit. The caller decides whether to `await log.flush()` and `process.exit(...)`. See [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md) for the `uncaughtException` → `fatal` routing.
|
|
63
|
-
|
|
64
|
-
Every call signature is the same — `module`, `action`, `message`, optional `context`. `message` can be a string, object, or `Error` instance (file channels capture the stack).
|
|
65
|
-
|
|
66
|
-
## Pick a skill
|
|
67
|
-
|
|
68
|
-
| If the task is about… | Load |
|
|
69
|
-
| --- | --- |
|
|
70
|
-
| Picking a channel — what each built-in does, when to use which | [`@warlock.js/logger/pick-log-channel/SKILL.md`](@warlock.js/logger/pick-log-channel/SKILL.md) |
|
|
71
|
-
| Startup — registering channels, environment-based setup, the `configure` method | [`@warlock.js/logger/configure-logger/SKILL.md`](@warlock.js/logger/configure-logger/SKILL.md) |
|
|
72
|
-
| Filtering log output (`levels`, `filter`, per-channel routing, `minLevel`) | [`@warlock.js/logger/filter-log-entries/SKILL.md`](@warlock.js/logger/filter-log-entries/SKILL.md) |
|
|
73
|
-
| Graceful shutdown — `flushSync`, `autoFlushOn`, signal behavior | [`@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md) |
|
|
74
|
-
| Extending `LogChannel` to build a custom sink (Slack, database, HTTP) | [`@warlock.js/logger/write-custom-log-channel/SKILL.md`](@warlock.js/logger/write-custom-log-channel/SKILL.md) |
|
|
75
|
-
| Routing Node's `unhandledRejection` / `uncaughtException` through the logger | [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md) |
|
|
76
|
-
| `log.assert(...)` and `log.timer(...)` shorthand helpers | [`@warlock.js/logger/use-log-helpers/SKILL.md`](@warlock.js/logger/use-log-helpers/SKILL.md) |
|
|
77
|
-
| Redacting secrets — logger floor + additive channel paths | [`@warlock.js/logger/redact-sensitive-log-fields/SKILL.md`](@warlock.js/logger/redact-sensitive-log-fields/SKILL.md) |
|
|
78
|
-
| Tests that assert on log output, or code under test that logs | [`@warlock.js/logger/test-logging-code/SKILL.md`](@warlock.js/logger/test-logging-code/SKILL.md) |
|
|
79
|
-
|
|
80
|
-
## Things NOT to do
|
|
81
|
-
|
|
82
|
-
- Don't try `log(module, action, message)` or `log({...})` directly — `log` is a `Logger` instance, not a function. Use `log.info(...)`, `log.error(...)`, etc., or the explicit `log.log({ type, module, action, message })` for the data-object form.
|
|
83
|
-
- Don't set `extension` on `JSONFileLog` — it's hardcoded to `"json"` and your value is silently ignored.
|
|
84
|
-
- Don't register multiple `FileLog` instances with the same `name` in the same `storagePath` — the lookup via `log.channel("file")` returns only one, and they'll fight over the same file.
|
|
85
|
-
- Don't mix `autoFlushOn: ["SIGINT"]` with your own `process.on("SIGINT", ...)` handler — both fire, and ours re-raises mid-way through your async work.
|
|
86
|
-
- Don't `await log.info(...)` expecting the write to be on disk — `FileLog` buffers. Call `log.flushSync()` (or rely on `autoFlushOn`) before the process exits.
|
|
87
|
-
- Don't call `captureAnyUnhandledRejection()` more than once — it re-registers listeners every call and your rejections get logged N times.
|
|
88
|
-
- Don't shadow the import in local code: `for (const log of logEntries) { ... }` will hide the singleton inside that block. Rename loop variables (`entry`, `record`) when working with logger imports.
|
|
1
|
+
---
|
|
2
|
+
name: logger-basics
|
|
3
|
+
description: 'Start with @warlock.js/logger — the log singleton, six levels (debug / info / warn / error / success / fatal), channel fan-out, foundations. Triggers: `log`, `Logger`, `log.info`, `log.error`, `log.fatal`, `log.debug`, `log.warn`, `log.success`, `ConsoleLog`, `FileLog`, `JSONFileLog`; "how do I log in node", "warlock logger basics", "which logger skill do I need"; typical import `import { log, ConsoleLog, FileLog } from "@warlock.js/logger"`. Skip: channel picks — `@warlock.js/logger/pick-log-channel/SKILL.md`; setup — `@warlock.js/logger/configure-logger/SKILL.md`; competing libs `winston`, `pino`, `bunyan`, `log4js`, `signale`; native `console.log`.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Log with channels
|
|
7
|
+
|
|
8
|
+
Multi-channel structured logger for Node.js. Four built-in channels (`ConsoleLog`, `FileLog`, `JSONFileLog`, `SentryLog`), an abstract `LogChannel` base for custom sinks, six severity levels, and a safe shutdown path via `Logger.enableAutoFlush(events)` plus async `log.flush()` for network channels.
|
|
9
|
+
|
|
10
|
+
> This skill is the logger **map** — read it first, then load the specific skill for the task.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @warlock.js/logger
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Foundations
|
|
19
|
+
|
|
20
|
+
The 11 things that are true in every logger use:
|
|
21
|
+
|
|
22
|
+
1. **Public API is the `log` singleton** (`import { log } from "@warlock.js/logger"`). It's a `Logger` instance — call `log.info(...)`, `log.configure(...)`, etc. No callable `log(data)` form.
|
|
23
|
+
2. **The singleton starts with zero channels.** Nothing is written until at least one channel is registered via `addChannel`, `setChannels`, or `configure`.
|
|
24
|
+
3. **Custom instances:** `new Logger()` gives an isolated logger with the identical API. Almost always you want the singleton — reach for the class only when you need an isolated channel set (libraries, test sandboxes).
|
|
25
|
+
4. **Six levels, closed union:** `"debug" | "info" | "warn" | "error" | "success" | "fatal"`. `fatal` ranks strictly above `error` — use it for unrecoverable failures where the app is going down (failed bootstrap, `uncaughtException`). There are no custom levels.
|
|
26
|
+
5. **Channels can be filtered two ways:** a `levels` array (whitelist) and a `filter` predicate (custom logic). Both run on every entry. See [`@warlock.js/logger/filter-log-entries/SKILL.md`](@warlock.js/logger/filter-log-entries/SKILL.md).
|
|
27
|
+
6. **Logger-wide minimum severity** is available via `log.setMinLevel("info")` (or `configure({ minLevel })`). Entries below the rank are dropped before fan-out — cheaper than per-channel filters.
|
|
28
|
+
7. **Redaction** is two-layer additive: `configure({ redact })` sets the logger floor; `new XxxChannel({ redact: { paths: [...] } })` adds more paths on top. Channels can never remove paths from the logger floor. See [`@warlock.js/logger/redact-sensitive-log-fields/SKILL.md`](@warlock.js/logger/redact-sensitive-log-fields/SKILL.md).
|
|
29
|
+
8. **`FileLog` and `JSONFileLog` buffer in memory.** They flush when `maxMessagesToWrite` (default `100`) is hit, when 5 seconds have elapsed since the last write, or when `flushSync()` is called. See [`@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md).
|
|
30
|
+
9. **Non-terminal channels receive ANSI-stripped messages.** `Logger.log` shallow-clones the entry per non-terminal channel before stripping, so later terminal channels still get the colored original.
|
|
31
|
+
10. **`JSONFileLog.extension` is always `"json"`.** The option is ignored for this channel.
|
|
32
|
+
11. **`captureAnyUnhandledRejection()` registers process listeners.** Call it once at startup, after channels are registered. Calling it twice installs duplicate listeners. See [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md).
|
|
33
|
+
|
|
34
|
+
## Minimal startup example
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { log, ConsoleLog, FileLog } from "@warlock.js/logger";
|
|
38
|
+
|
|
39
|
+
log.configure({
|
|
40
|
+
channels: [
|
|
41
|
+
new ConsoleLog(),
|
|
42
|
+
new FileLog({ chunk: "daily", storagePath: "./storage/logs" }),
|
|
43
|
+
],
|
|
44
|
+
autoFlushOn: ["SIGINT", "SIGTERM", "beforeExit"],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await log.info("users", "register", "New user created");
|
|
48
|
+
await log.error("payments", "charge", new Error("Card declined"));
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## The six levels
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
log.debug("module", "action", "verbose detail"); // dev-only diagnostics
|
|
55
|
+
log.info("module", "action", "neutral event"); // user-visible event
|
|
56
|
+
log.warn("module", "action", "something off"); // recoverable concern
|
|
57
|
+
log.error("module", "action", error); // handled failure, app continues
|
|
58
|
+
log.success("module", "action", "operation done"); // explicit success
|
|
59
|
+
log.fatal("module", "action", error); // unrecoverable, app is going down
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`fatal` is purely informational — it does NOT auto-flush or exit. The caller decides whether to `await log.flush()` and `process.exit(...)`. See [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md) for the `uncaughtException` → `fatal` routing.
|
|
63
|
+
|
|
64
|
+
Every call signature is the same — `module`, `action`, `message`, optional `context`. `message` can be a string, object, or `Error` instance (file channels capture the stack).
|
|
65
|
+
|
|
66
|
+
## Pick a skill
|
|
67
|
+
|
|
68
|
+
| If the task is about… | Load |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| Picking a channel — what each built-in does, when to use which | [`@warlock.js/logger/pick-log-channel/SKILL.md`](@warlock.js/logger/pick-log-channel/SKILL.md) |
|
|
71
|
+
| Startup — registering channels, environment-based setup, the `configure` method | [`@warlock.js/logger/configure-logger/SKILL.md`](@warlock.js/logger/configure-logger/SKILL.md) |
|
|
72
|
+
| Filtering log output (`levels`, `filter`, per-channel routing, `minLevel`) | [`@warlock.js/logger/filter-log-entries/SKILL.md`](@warlock.js/logger/filter-log-entries/SKILL.md) |
|
|
73
|
+
| Graceful shutdown — `flushSync`, `autoFlushOn`, signal behavior | [`@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md) |
|
|
74
|
+
| Extending `LogChannel` to build a custom sink (Slack, database, HTTP) | [`@warlock.js/logger/write-custom-log-channel/SKILL.md`](@warlock.js/logger/write-custom-log-channel/SKILL.md) |
|
|
75
|
+
| Routing Node's `unhandledRejection` / `uncaughtException` through the logger | [`@warlock.js/logger/capture-unhandled-errors/SKILL.md`](@warlock.js/logger/capture-unhandled-errors/SKILL.md) |
|
|
76
|
+
| `log.assert(...)` and `log.timer(...)` shorthand helpers | [`@warlock.js/logger/use-log-helpers/SKILL.md`](@warlock.js/logger/use-log-helpers/SKILL.md) |
|
|
77
|
+
| Redacting secrets — logger floor + additive channel paths | [`@warlock.js/logger/redact-sensitive-log-fields/SKILL.md`](@warlock.js/logger/redact-sensitive-log-fields/SKILL.md) |
|
|
78
|
+
| Tests that assert on log output, or code under test that logs | [`@warlock.js/logger/test-logging-code/SKILL.md`](@warlock.js/logger/test-logging-code/SKILL.md) |
|
|
79
|
+
|
|
80
|
+
## Things NOT to do
|
|
81
|
+
|
|
82
|
+
- Don't try `log(module, action, message)` or `log({...})` directly — `log` is a `Logger` instance, not a function. Use `log.info(...)`, `log.error(...)`, etc., or the explicit `log.log({ type, module, action, message })` for the data-object form.
|
|
83
|
+
- Don't set `extension` on `JSONFileLog` — it's hardcoded to `"json"` and your value is silently ignored.
|
|
84
|
+
- Don't register multiple `FileLog` instances with the same `name` in the same `storagePath` — the lookup via `log.channel("file")` returns only one, and they'll fight over the same file.
|
|
85
|
+
- Don't mix `autoFlushOn: ["SIGINT"]` with your own `process.on("SIGINT", ...)` handler — both fire, and ours re-raises mid-way through your async work.
|
|
86
|
+
- Don't `await log.info(...)` expecting the write to be on disk — `FileLog` buffers. Call `log.flushSync()` (or rely on `autoFlushOn`) before the process exits.
|
|
87
|
+
- Don't call `captureAnyUnhandledRejection()` more than once — it re-registers listeners every call and your rejections get logged N times.
|
|
88
|
+
- Don't shadow the import in local code: `for (const log of logEntries) { ... }` will hide the singleton inside that block. Rename loop variables (`entry`, `record`) when working with logger imports.
|