@warlock.js/logger 4.1.15 → 4.2.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 +30 -0
- package/LICENSE +21 -0
- package/README.md +146 -145
- package/cjs/index.cjs +276 -11
- package/cjs/index.cjs.map +1 -1
- package/esm/channels/console-log.d.mts +1 -1
- package/esm/channels/console-log.d.mts.map +1 -1
- package/esm/channels/console-log.mjs +4 -1
- package/esm/channels/console-log.mjs.map +1 -1
- package/esm/channels/file-log.d.mts +13 -3
- package/esm/channels/file-log.d.mts.map +1 -1
- package/esm/channels/file-log.mjs +15 -1
- package/esm/channels/file-log.mjs.map +1 -1
- package/esm/channels/index.mjs +1 -0
- package/esm/channels/json-file-log.d.mts +1 -1
- package/esm/channels/json-file-log.d.mts.map +1 -1
- package/esm/channels/json-file-log.mjs +1 -1
- package/esm/channels/json-file-log.mjs.map +1 -1
- package/esm/channels/sentry-log.d.mts +182 -0
- package/esm/channels/sentry-log.d.mts.map +1 -0
- package/esm/channels/sentry-log.mjs +202 -0
- package/esm/channels/sentry-log.mjs.map +1 -0
- package/esm/index.d.mts +2 -1
- package/esm/index.mjs +2 -1
- package/esm/log-channel.d.mts +9 -1
- package/esm/log-channel.d.mts.map +1 -1
- package/esm/log-channel.mjs +1 -1
- package/esm/log-channel.mjs.map +1 -1
- package/esm/logger.d.mts +32 -1
- package/esm/logger.d.mts.map +1 -1
- package/esm/logger.mjs +44 -2
- package/esm/logger.mjs.map +1 -1
- package/esm/redact/redact.d.mts +1 -1
- package/esm/redact/redact.d.mts.map +1 -1
- package/esm/redact/redact.mjs +1 -1
- package/esm/redact/redact.mjs.map +1 -1
- package/esm/types.d.mts +19 -3
- package/esm/types.d.mts.map +1 -1
- package/esm/utils/capture-unhandled-errors.d.mts +9 -1
- package/esm/utils/capture-unhandled-errors.d.mts.map +1 -1
- package/esm/utils/capture-unhandled-errors.mjs +10 -2
- package/esm/utils/capture-unhandled-errors.mjs.map +1 -1
- package/esm/utils/clear-message.d.mts +1 -1
- package/esm/utils/clear-message.d.mts.map +1 -1
- package/esm/utils/clear-message.mjs +1 -1
- package/esm/utils/clear-message.mjs.map +1 -1
- package/esm/utils/safe-json-stringify.d.mts +1 -1
- package/esm/utils/safe-json-stringify.d.mts.map +1 -1
- package/esm/utils/safe-json-stringify.mjs +1 -1
- package/esm/utils/safe-json-stringify.mjs.map +1 -1
- package/llms-full.txt +1497 -1296
- package/llms.txt +20 -19
- package/package.json +5 -2
- package/skills/capture-unhandled-errors/SKILL.md +103 -103
- package/skills/filter-log-entries/SKILL.md +120 -120
- package/skills/flush-logs-on-shutdown/SKILL.md +117 -91
- package/skills/logger-basics/SKILL.md +88 -85
- package/skills/overview/SKILL.md +90 -86
- package/skills/pick-log-channel/SKILL.md +155 -139
- package/skills/ship-logs-to-sentry/SKILL.md +118 -0
- package/skills/write-custom-log-channel/SKILL.md +190 -160
package/cjs/index.cjs
CHANGED
|
@@ -39,7 +39,7 @@ path = __toESM(path, 1);
|
|
|
39
39
|
let safe_stable_stringify = require("safe-stable-stringify");
|
|
40
40
|
let _mongez_reinforcements = require("@mongez/reinforcements");
|
|
41
41
|
|
|
42
|
-
//#region
|
|
42
|
+
//#region ../@warlock.js/logger/src/log-channel.ts
|
|
43
43
|
var LogChannel = class {
|
|
44
44
|
/**
|
|
45
45
|
* Constructor
|
|
@@ -112,7 +112,7 @@ var LogChannel = class {
|
|
|
112
112
|
};
|
|
113
113
|
|
|
114
114
|
//#endregion
|
|
115
|
-
//#region
|
|
115
|
+
//#region ../@warlock.js/logger/src/channels/console-log.ts
|
|
116
116
|
var ConsoleLog = class extends LogChannel {
|
|
117
117
|
constructor(..._args) {
|
|
118
118
|
super(..._args);
|
|
@@ -142,6 +142,9 @@ var ConsoleLog = class extends LogChannel {
|
|
|
142
142
|
case "success":
|
|
143
143
|
console.log(_mongez_copper.colors.green("✓"), _mongez_copper.colors.yellow(`(${date})`), _mongez_copper.colors.cyan(`[${module}]`), _mongez_copper.colors.magenta(`[${action}]`), _mongez_copper.colors.greenBright(message));
|
|
144
144
|
break;
|
|
145
|
+
case "fatal":
|
|
146
|
+
console.log(_mongez_copper.colors.bgRedBright(_mongez_copper.colors.bold(" ☠ ")), _mongez_copper.colors.yellow(`(${date})`), _mongez_copper.colors.cyan(`[${module}]`), _mongez_copper.colors.magenta(`[${action}]`), _mongez_copper.colors.redBright.bold(message));
|
|
147
|
+
break;
|
|
145
148
|
default: console.log("[log]", _mongez_copper.colors.yellow(`(${date})`), _mongez_copper.colors.cyan(`[${module}]`), _mongez_copper.colors.magenta(`[${action}]`), message);
|
|
146
149
|
}
|
|
147
150
|
if (typeof message === "object") console.log(message);
|
|
@@ -157,7 +160,7 @@ var ConsoleLog = class extends LogChannel {
|
|
|
157
160
|
};
|
|
158
161
|
|
|
159
162
|
//#endregion
|
|
160
|
-
//#region
|
|
163
|
+
//#region ../@warlock.js/logger/src/channels/file-log.ts
|
|
161
164
|
var FileLog = class extends LogChannel {
|
|
162
165
|
constructor(..._args) {
|
|
163
166
|
super(..._args);
|
|
@@ -305,6 +308,20 @@ var FileLog = class extends LogChannel {
|
|
|
305
308
|
this.onSave();
|
|
306
309
|
}
|
|
307
310
|
/**
|
|
311
|
+
* Asynchronously drain buffered entries to disk.
|
|
312
|
+
*
|
|
313
|
+
* The async analogue of {@link flushSync}: it reuses the same async writer
|
|
314
|
+
* as the background interval, so a caller on a graceful-shutdown path can
|
|
315
|
+
* `await channel.flush()` (or `await log.flush()`) and rely on the buffer
|
|
316
|
+
* being on disk once it resolves. `JSONFileLog` inherits this unchanged —
|
|
317
|
+
* its overridden `writeMessagesToFile` performs the JSON merge.
|
|
318
|
+
*/
|
|
319
|
+
async flush() {
|
|
320
|
+
if (this.messages.length === 0 && Object.keys(this.groupedMessages).length === 0) return;
|
|
321
|
+
this.isWriting = false;
|
|
322
|
+
await this.writeMessagesToFile();
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
308
325
|
* {@inheritdoc}
|
|
309
326
|
*/
|
|
310
327
|
async log(data) {
|
|
@@ -415,7 +432,7 @@ var FileLog = class extends LogChannel {
|
|
|
415
432
|
};
|
|
416
433
|
|
|
417
434
|
//#endregion
|
|
418
|
-
//#region
|
|
435
|
+
//#region ../@warlock.js/logger/src/utils/safe-json-stringify.ts
|
|
419
436
|
/**
|
|
420
437
|
* Replacer that surfaces Error data — `name`, `message`, and `stack` are
|
|
421
438
|
* non-enumerable on `Error`, so neither default JSON serialization nor an
|
|
@@ -446,7 +463,7 @@ function safeJsonStringify(value, space) {
|
|
|
446
463
|
}
|
|
447
464
|
|
|
448
465
|
//#endregion
|
|
449
|
-
//#region
|
|
466
|
+
//#region ../@warlock.js/logger/src/channels/json-file-log.ts
|
|
450
467
|
var JSONFileLog = class extends FileLog {
|
|
451
468
|
constructor(..._args) {
|
|
452
469
|
super(..._args);
|
|
@@ -574,7 +591,204 @@ var JSONFileLog = class extends FileLog {
|
|
|
574
591
|
};
|
|
575
592
|
|
|
576
593
|
//#endregion
|
|
577
|
-
//#region
|
|
594
|
+
//#region ../@warlock.js/logger/src/channels/sentry-log.ts
|
|
595
|
+
let Sentry;
|
|
596
|
+
let isModuleExists = null;
|
|
597
|
+
let loadingPromise;
|
|
598
|
+
const SENTRY_INSTALL_INSTRUCTIONS = `
|
|
599
|
+
The Sentry log channel requires the @sentry/node package.
|
|
600
|
+
Install it with:
|
|
601
|
+
|
|
602
|
+
npm install @sentry/node
|
|
603
|
+
|
|
604
|
+
Or with your preferred package manager:
|
|
605
|
+
|
|
606
|
+
pnpm add @sentry/node
|
|
607
|
+
yarn add @sentry/node
|
|
608
|
+
`.trim();
|
|
609
|
+
/**
|
|
610
|
+
* Load @sentry/node once, lazily and concurrency-safely. A bare catch maps any
|
|
611
|
+
* import failure to "not installed" — the curated install message surfaces at
|
|
612
|
+
* `log()` time, never as a boot-time module-resolution crash.
|
|
613
|
+
*/
|
|
614
|
+
function loadSentry() {
|
|
615
|
+
if (isModuleExists !== null) return Promise.resolve();
|
|
616
|
+
if (loadingPromise) return loadingPromise;
|
|
617
|
+
loadingPromise = (async () => {
|
|
618
|
+
try {
|
|
619
|
+
Sentry = await import("@sentry/node");
|
|
620
|
+
isModuleExists = true;
|
|
621
|
+
} catch {
|
|
622
|
+
isModuleExists = false;
|
|
623
|
+
}
|
|
624
|
+
})();
|
|
625
|
+
return loadingPromise;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Forwards log entries to Sentry.
|
|
629
|
+
*
|
|
630
|
+
* Entries at an `eventLevels` level (`error` / `warn` by default) become Sentry
|
|
631
|
+
* **events**: an `Error` message via `captureException` (preserving the real
|
|
632
|
+
* stack), any other message via `captureMessage`. Every other level becomes a
|
|
633
|
+
* **breadcrumb** — buffered and attached to the next event, consuming no error
|
|
634
|
+
* quota. `module` / `action` are attached as searchable tags and the entry's
|
|
635
|
+
* `context` as a structured Sentry context.
|
|
636
|
+
*
|
|
637
|
+
* The SDK is an optional peer: pass an existing `client` (reused as-is) or
|
|
638
|
+
* `options` (the channel lazily imports `@sentry/node` and initializes it). On
|
|
639
|
+
* graceful shutdown, `await log.flush()` drains pending events via
|
|
640
|
+
* `Sentry.flush(timeout)`.
|
|
641
|
+
*
|
|
642
|
+
* @example
|
|
643
|
+
* // Existing app — reuse the initialized Sentry client
|
|
644
|
+
* import * as Sentry from "@sentry/node";
|
|
645
|
+
* log.addChannel(new SentryLog({ client: Sentry }));
|
|
646
|
+
*
|
|
647
|
+
* @example
|
|
648
|
+
* // New app — let the channel initialize Sentry
|
|
649
|
+
* log.addChannel(new SentryLog({ options: { dsn: process.env.SENTRY_DSN } }));
|
|
650
|
+
*/
|
|
651
|
+
var SentryLog = class extends LogChannel {
|
|
652
|
+
/**
|
|
653
|
+
* Resolve an injected `client` (the Sentry namespace) **synchronously**, so an
|
|
654
|
+
* entry logged on the same tick as construction — e.g. at app boot, before
|
|
655
|
+
* the base schedules `init()` on the next tick via `setTimeout(0)` — is not
|
|
656
|
+
* silently dropped. The `options` (lazy-import) path is inherently async and
|
|
657
|
+
* still resolves in `init()`.
|
|
658
|
+
*/
|
|
659
|
+
constructor(configurations) {
|
|
660
|
+
super(configurations);
|
|
661
|
+
this.name = "sentry";
|
|
662
|
+
this.description = "Forwards entries to Sentry as events (error/warn) or breadcrumbs (everything else)";
|
|
663
|
+
this.defaultConfigurations = {
|
|
664
|
+
eventLevels: [
|
|
665
|
+
"fatal",
|
|
666
|
+
"error",
|
|
667
|
+
"warn"
|
|
668
|
+
],
|
|
669
|
+
flushTimeout: 2e3
|
|
670
|
+
};
|
|
671
|
+
this.warnedMissing = false;
|
|
672
|
+
const injected = this.config("client");
|
|
673
|
+
if (injected) this.sentry = injected;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Resolve the forwarder: reuse the injected client, otherwise lazily import
|
|
677
|
+
* `@sentry/node` and (only when explicit `options` are supplied and no client
|
|
678
|
+
* exists yet) initialize it. Never throws — the base runs `init()` inside an
|
|
679
|
+
* un-awaited `setTimeout`, so a throw would become an unhandled rejection and
|
|
680
|
+
* `isInitialized` would never flip; a missing SDK is reported from `log()`.
|
|
681
|
+
*/
|
|
682
|
+
async init() {
|
|
683
|
+
const injected = this.config("client");
|
|
684
|
+
if (injected) {
|
|
685
|
+
this.sentry = injected;
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
await loadSentry();
|
|
689
|
+
if (!Sentry) return;
|
|
690
|
+
const options = this.config("options");
|
|
691
|
+
if (options && !Sentry.getClient()) Sentry.init(options);
|
|
692
|
+
this.sentry = Sentry;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* {@inheritdoc}
|
|
696
|
+
*/
|
|
697
|
+
async log(data) {
|
|
698
|
+
if (!this.shouldBeLogged(data)) return;
|
|
699
|
+
if (isModuleExists === null) await loadSentry();
|
|
700
|
+
if (!this.sentry) {
|
|
701
|
+
this.reportMissingSdk();
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
const { module, action, message, type: level, context } = data;
|
|
705
|
+
if (this.isEventLevel(level)) {
|
|
706
|
+
this.captureEvent(this.sentry, {
|
|
707
|
+
module,
|
|
708
|
+
action,
|
|
709
|
+
message,
|
|
710
|
+
level,
|
|
711
|
+
context
|
|
712
|
+
});
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
this.sentry.addBreadcrumb({
|
|
716
|
+
category: module,
|
|
717
|
+
message: this.toText(message),
|
|
718
|
+
level: this.toSentryLevel(level),
|
|
719
|
+
data: context
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Drain pending Sentry events. Bounded by `flushTimeout` so an unreachable
|
|
724
|
+
* Sentry can never hang a graceful shutdown. No-op when the SDK is absent.
|
|
725
|
+
*/
|
|
726
|
+
async flush() {
|
|
727
|
+
if (!this.sentry) return;
|
|
728
|
+
await this.sentry.flush(this.config("flushTimeout"));
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Whether the level should be sent as a Sentry event (vs a breadcrumb).
|
|
732
|
+
*/
|
|
733
|
+
isEventLevel(level) {
|
|
734
|
+
return Boolean(this.config("eventLevels")?.includes(level));
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Send an entry as a Sentry event. An `Error` message goes through
|
|
738
|
+
* `captureException` so Sentry parses the real stack and groups properly;
|
|
739
|
+
* any other message goes through `captureMessage`. `module` / `action` are
|
|
740
|
+
* attached as tags and `context` as a structured context, scoped to this
|
|
741
|
+
* event only via `withScope`.
|
|
742
|
+
*/
|
|
743
|
+
captureEvent(sentry, entry) {
|
|
744
|
+
const { module, action, message, level, context } = entry;
|
|
745
|
+
const sentryLevel = this.toSentryLevel(level);
|
|
746
|
+
sentry.withScope((scope) => {
|
|
747
|
+
scope.setLevel(sentryLevel);
|
|
748
|
+
scope.setTags({
|
|
749
|
+
module,
|
|
750
|
+
action
|
|
751
|
+
});
|
|
752
|
+
if (context) scope.setContext("context", context);
|
|
753
|
+
if (message instanceof Error) sentry.captureException(message);
|
|
754
|
+
else sentry.captureMessage(this.toText(message), sentryLevel);
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Map a logger level to a Sentry severity. `success` has no Sentry
|
|
759
|
+
* equivalent, so it is reported as informational.
|
|
760
|
+
*/
|
|
761
|
+
toSentryLevel(level) {
|
|
762
|
+
switch (level) {
|
|
763
|
+
case "warn": return "warning";
|
|
764
|
+
case "success": return "info";
|
|
765
|
+
default: return level;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Coerce a message into the string Sentry's APIs expect — an `Error`'s
|
|
770
|
+
* `.message`, a string as-is, anything else safely JSON-serialized.
|
|
771
|
+
*/
|
|
772
|
+
toText(message) {
|
|
773
|
+
if (typeof message === "string") return message;
|
|
774
|
+
if (message instanceof Error) return message.message;
|
|
775
|
+
return safeJsonStringify(message);
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Surface the install instructions exactly once when the SDK is absent. The
|
|
779
|
+
* logger can't log through itself here, so this writes to stderr — matching
|
|
780
|
+
* how the file channels report write failures.
|
|
781
|
+
*/
|
|
782
|
+
reportMissingSdk() {
|
|
783
|
+
if (isModuleExists === false && !this.warnedMissing) {
|
|
784
|
+
this.warnedMissing = true;
|
|
785
|
+
console.error(SENTRY_INSTALL_INSTRUCTIONS);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
//#endregion
|
|
791
|
+
//#region ../@warlock.js/logger/src/redact/redact.ts
|
|
578
792
|
/**
|
|
579
793
|
* Deep-clone a value with structural fidelity for log entries — handles plain
|
|
580
794
|
* objects, arrays, `Date`, `Error`, and primitives. Anything else is copied
|
|
@@ -681,7 +895,7 @@ function mergeRedact(base, extra) {
|
|
|
681
895
|
}
|
|
682
896
|
|
|
683
897
|
//#endregion
|
|
684
|
-
//#region
|
|
898
|
+
//#region ../@warlock.js/logger/src/utils/clear-message.ts
|
|
685
899
|
/**
|
|
686
900
|
* Clear message from any terminal codes
|
|
687
901
|
*/
|
|
@@ -691,7 +905,7 @@ function clearMessage(message) {
|
|
|
691
905
|
}
|
|
692
906
|
|
|
693
907
|
//#endregion
|
|
694
|
-
//#region
|
|
908
|
+
//#region ../@warlock.js/logger/src/logger.ts
|
|
695
909
|
const SIGNAL_EVENTS = new Set([
|
|
696
910
|
"SIGINT",
|
|
697
911
|
"SIGTERM",
|
|
@@ -711,7 +925,8 @@ const LEVEL_RANK = {
|
|
|
711
925
|
info: 1,
|
|
712
926
|
success: 1,
|
|
713
927
|
warn: 2,
|
|
714
|
-
error: 3
|
|
928
|
+
error: 3,
|
|
929
|
+
fatal: 4
|
|
715
930
|
};
|
|
716
931
|
var Logger = class {
|
|
717
932
|
constructor() {
|
|
@@ -863,6 +1078,19 @@ var Logger = class {
|
|
|
863
1078
|
return this.log(data);
|
|
864
1079
|
}
|
|
865
1080
|
/**
|
|
1081
|
+
* Make fatal log — for unrecoverable failures where the application is going
|
|
1082
|
+
* down (failed bootstrap, lost connection to a required dependency that the
|
|
1083
|
+
* caller has decided not to retry, an `uncaughtException`).
|
|
1084
|
+
*
|
|
1085
|
+
* Identical shape to {@link error}; the level is purely informational —
|
|
1086
|
+
* `fatal` does NOT auto-flush or exit. The caller decides whether to call
|
|
1087
|
+
* `await log.flush()` and `process.exit(...)`.
|
|
1088
|
+
*/
|
|
1089
|
+
fatal(dataOrModule, action, message = "", context) {
|
|
1090
|
+
const data = this.normalizeLogData(dataOrModule, action, message, "fatal", context);
|
|
1091
|
+
return this.log(data);
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
866
1094
|
* Log an `error` entry when `condition` is falsy. No-op otherwise — the
|
|
867
1095
|
* entry is never built and channels are not invoked, so this is genuinely
|
|
868
1096
|
* free in the happy path. Mirrors the spirit of `console.assert` but routes
|
|
@@ -908,6 +1136,34 @@ var Logger = class {
|
|
|
908
1136
|
for (const channel of this.channels) if (channel.flushSync) channel.flushSync();
|
|
909
1137
|
}
|
|
910
1138
|
/**
|
|
1139
|
+
* Asynchronously drain every channel that implements `flush()`.
|
|
1140
|
+
*
|
|
1141
|
+
* Unlike {@link flushSync}, this awaits each channel's async I/O — the
|
|
1142
|
+
* correct call for a graceful shutdown that can afford to wait
|
|
1143
|
+
* (`await log.flush()` after closing the HTTP server, before
|
|
1144
|
+
* `process.exit`). A channel whose delivery is async (a network transport,
|
|
1145
|
+
* an async disk write) implements `flush()`, not `flushSync()`.
|
|
1146
|
+
*
|
|
1147
|
+
* Channels are isolated: a channel whose flush rejects can neither prevent
|
|
1148
|
+
* the others from draining nor escape as an unhandled rejection. Channels
|
|
1149
|
+
* without `flush()` are skipped.
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* async function shutdown() {
|
|
1153
|
+
* await httpServer.close();
|
|
1154
|
+
* await log.flush();
|
|
1155
|
+
* process.exit(0);
|
|
1156
|
+
* }
|
|
1157
|
+
*/
|
|
1158
|
+
async flush() {
|
|
1159
|
+
await Promise.allSettled(this.channels.map(async (channel) => {
|
|
1160
|
+
if (!channel.flush) return;
|
|
1161
|
+
try {
|
|
1162
|
+
await channel.flush();
|
|
1163
|
+
} catch {}
|
|
1164
|
+
}));
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
911
1167
|
* Register one process-level handler per event that calls `flushSync()`
|
|
912
1168
|
* before the process terminates.
|
|
913
1169
|
*
|
|
@@ -967,7 +1223,7 @@ var Logger = class {
|
|
|
967
1223
|
const log = new Logger();
|
|
968
1224
|
|
|
969
1225
|
//#endregion
|
|
970
|
-
//#region
|
|
1226
|
+
//#region ../@warlock.js/logger/src/utils/capture-unhandled-errors.ts
|
|
971
1227
|
/**
|
|
972
1228
|
* Route Node's process-level failure events through the logger so they land in
|
|
973
1229
|
* every configured channel with full stack context. Registers one listener for
|
|
@@ -975,6 +1231,14 @@ const log = new Logger();
|
|
|
975
1231
|
* after channels are configured. Pair with `autoFlushOn: ["beforeExit"]` so the
|
|
976
1232
|
* final entry survives the process exit that follows an uncaught exception.
|
|
977
1233
|
*
|
|
1234
|
+
* Levels chosen for semantic honesty:
|
|
1235
|
+
*
|
|
1236
|
+
* - `uncaughtException` → `log.fatal` — by default Node terminates the process,
|
|
1237
|
+
* so the failure is unrecoverable.
|
|
1238
|
+
* - `unhandledRejection` → `log.error` — a rejected promise is a failure, but
|
|
1239
|
+
* not necessarily process-ending (depends on Node's `--unhandled-rejections`
|
|
1240
|
+
* policy and your app's recovery), so it stays at error.
|
|
1241
|
+
*
|
|
978
1242
|
* @example
|
|
979
1243
|
* log.configure({ channels: [new ConsoleLog(), new FileLog()] });
|
|
980
1244
|
* captureAnyUnhandledRejection();
|
|
@@ -984,7 +1248,7 @@ function captureAnyUnhandledRejection() {
|
|
|
984
1248
|
log.error("app", "unhandledRejection", reason);
|
|
985
1249
|
});
|
|
986
1250
|
process.on("uncaughtException", (error) => {
|
|
987
|
-
log.
|
|
1251
|
+
log.fatal("app", "uncaughtException", error);
|
|
988
1252
|
});
|
|
989
1253
|
}
|
|
990
1254
|
|
|
@@ -994,6 +1258,7 @@ exports.FileLog = FileLog;
|
|
|
994
1258
|
exports.JSONFileLog = JSONFileLog;
|
|
995
1259
|
exports.LogChannel = LogChannel;
|
|
996
1260
|
exports.Logger = Logger;
|
|
1261
|
+
exports.SentryLog = SentryLog;
|
|
997
1262
|
exports.applyRedact = applyRedact;
|
|
998
1263
|
exports.captureAnyUnhandledRejection = captureAnyUnhandledRejection;
|
|
999
1264
|
exports.clearMessage = clearMessage;
|