@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
|
@@ -1,139 +1,155 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pick-log-channel
|
|
3
|
-
description: 'Pick one of the
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Channels — which one to pick and how to configure it
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## The decision
|
|
11
|
-
|
|
12
|
-
| Need | Pick |
|
|
13
|
-
|---|---|
|
|
14
|
-
| Local dev, colored output in the terminal | `ConsoleLog` |
|
|
15
|
-
| Plain text `.log` files on disk — humans read them | `FileLog` |
|
|
16
|
-
| Structured `.json` files — a log aggregator (Loki / Datadog / Elastic) reads them | `JSONFileLog` |
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
-
|
|
77
|
-
- **`
|
|
78
|
-
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
"
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
- `
|
|
105
|
-
-
|
|
106
|
-
- `
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
1
|
+
---
|
|
2
|
+
name: pick-log-channel
|
|
3
|
+
description: 'Pick one of the four built-in channels — ConsoleLog (terminal), FileLog (plain text on disk), JSONFileLog (structured JSON for aggregators like Loki / Datadog / Elastic), SentryLog (forwards errors + breadcrumbs to Sentry). Triggers: `ConsoleLog`, `FileLog`, `JSONFileLog`, `SentryLog`, `chunk`, `rotate`, `groupBy`, `maxFileSize`, `showContext`, `log.channel`; "log to a file", "rotate log files", "daily log chunks", "json logs for datadog / loki / elastic", "send logs to Sentry"; typical import `import { ConsoleLog, FileLog, JSONFileLog, SentryLog } from "@warlock.js/logger"`. Skip: Sentry-specific setup — `@warlock.js/logger/ship-logs-to-sentry/SKILL.md`; custom sinks — `@warlock.js/logger/write-custom-log-channel/SKILL.md`; registration — `@warlock.js/logger/configure-logger/SKILL.md`; competing libs `winston-daily-rotate-file`, `pino-pretty`.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Channels — which one to pick and how to configure it
|
|
7
|
+
|
|
8
|
+
Four built-in channels (`SentryLog` needs the optional `@sentry/node` peer). A channel is a destination for a log entry — the logger fans out every entry to every registered channel in parallel.
|
|
9
|
+
|
|
10
|
+
## The decision
|
|
11
|
+
|
|
12
|
+
| Need | Pick |
|
|
13
|
+
|---|---|
|
|
14
|
+
| Local dev, colored output in the terminal | `ConsoleLog` |
|
|
15
|
+
| Plain text `.log` files on disk — humans read them | `FileLog` |
|
|
16
|
+
| Structured `.json` files — a log aggregator (Loki / Datadog / Elastic) reads them | `JSONFileLog` |
|
|
17
|
+
| Errors & warnings into Sentry (events + breadcrumbs) | `SentryLog` |
|
|
18
|
+
|
|
19
|
+
Most production setups use **two** channels: `ConsoleLog` + one file channel. Dev uses `ConsoleLog` only.
|
|
20
|
+
|
|
21
|
+
## `ConsoleLog`
|
|
22
|
+
|
|
23
|
+
Zero config. Colored, icon-prefixed lines to the terminal.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { ConsoleLog } from "@warlock.js/logger";
|
|
27
|
+
|
|
28
|
+
new ConsoleLog();
|
|
29
|
+
// ⚙ (2024-03-15T10:22:00.000Z) [auth] [hashPassword] Hashing started
|
|
30
|
+
// ℹ (2024-03-15T10:22:01.482Z) [users] [register] New user created
|
|
31
|
+
// ✗ (2024-03-15T10:22:03.111Z) [payments] [charge] Card declined
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Properties:
|
|
35
|
+
- `name = "console"`, `terminal = true`
|
|
36
|
+
- Accepts `ConsoleLogConfig` — `levels`, `filter`, `dateFormat`, `showContext`, `contextDepth`
|
|
37
|
+
- If `message` is an object, a second `console.log(message)` is issued so Node's inspector can expand it
|
|
38
|
+
|
|
39
|
+
### Showing context
|
|
40
|
+
|
|
41
|
+
By default `ConsoleLog` drops the `context` payload (the file/JSON channels still keep it). Flip `showContext: true` to render it on a second line — useful in development:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
new ConsoleLog({ showContext: true });
|
|
45
|
+
|
|
46
|
+
log.info("payments", "charge", "card declined", { userId: 42, amount: 1999 });
|
|
47
|
+
// ℹ (…) [payments] [charge] card declined
|
|
48
|
+
// ↳ { userId: 42, amount: 1999 }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Tune `contextDepth` (default `4`) to clamp how deep `util.inspect` recurses into nested objects.
|
|
52
|
+
|
|
53
|
+
## `FileLog`
|
|
54
|
+
|
|
55
|
+
Plain text. Buffers in memory, flushes to disk periodically.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { FileLog } from "@warlock.js/logger";
|
|
59
|
+
|
|
60
|
+
new FileLog({
|
|
61
|
+
storagePath: "./storage/logs", // default: process.cwd() + "/storage/logs"
|
|
62
|
+
name: "app", // default: "app"
|
|
63
|
+
extension: "log", // default: "log"
|
|
64
|
+
chunk: "daily", // "single" (default) | "daily" | "hourly"
|
|
65
|
+
rotate: true, // default: true
|
|
66
|
+
maxFileSize: 10 * 1024 * 1024, // default: 10MB — triggers rotation
|
|
67
|
+
maxMessagesToWrite: 100, // default: 100 — flush threshold
|
|
68
|
+
groupBy: ["level", "module"], // optional subdirectory nesting
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Line format: `[date time] [level] [module][action]: message` — or a `[trace]` block when `message` is an `Error`.
|
|
73
|
+
|
|
74
|
+
### Key gotchas
|
|
75
|
+
|
|
76
|
+
- **Buffers!** Messages sit in memory until either `maxMessagesToWrite` is reached, 5 seconds pass, or `flushSync()` is called. A process that crashes without flushing loses buffered entries.
|
|
77
|
+
- **`chunk: "daily"` picks a filename per day.** File name becomes `DD-MM-YYYY.log`. Combined with `rotate: true`, rotated archives get `Date.now()` suffixed.
|
|
78
|
+
- **`groupBy` nests directories.** `groupBy: ["level", "module"]` produces `storage/logs/error/payments/app.log`. Order matters.
|
|
79
|
+
- **Dispose channels you discard.** A live `FileLog` keeps a 5-second flush interval running. If you swap the channel list at runtime (reconfigure the logger), call `channel.dispose()` on the old instance — it clears that timer and drains the buffer one last time. Skipping it leaks one timer per discarded channel and keeps the event loop alive. (Channels that live for the whole process don't need this — process exit clears the timer.)
|
|
80
|
+
|
|
81
|
+
## `JSONFileLog`
|
|
82
|
+
|
|
83
|
+
Subclass of `FileLog` — same buffering, chunking, rotation, grouping. Output is a JSON object with a `messages` array:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"messages": [
|
|
88
|
+
{
|
|
89
|
+
"content": "Card declined",
|
|
90
|
+
"level": "error",
|
|
91
|
+
"date": "15-03-2024 10:22:03",
|
|
92
|
+
"module": "payments",
|
|
93
|
+
"action": "charge",
|
|
94
|
+
"stack": [
|
|
95
|
+
"Error: Card declined",
|
|
96
|
+
" at chargeCard (/app/src/payments.ts:42:11)"
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Differences from `FileLog`:
|
|
104
|
+
- `name = "fileJson"` (**not** `"json"` — use this exact string for `log.channel("fileJson")`)
|
|
105
|
+
- `extension` is always `"json"` — the option is silently ignored
|
|
106
|
+
- Error `stack` is stored as `string[]` (split on newlines) — easy to query in aggregators
|
|
107
|
+
- `content` holds the original user-supplied `message` (not a pre-formatted line)
|
|
108
|
+
- Corrupted existing file → reinitialized to `{ messages: [] }` on next write (does not throw)
|
|
109
|
+
- **Safe serialization by construction.** All writes go through `safe-stable-stringify` with a custom `Error` replacer — circular refs become `"[Circular]"`, BigInt is stringified, functions/symbols are dropped, nested `Error` instances expand to `{ name, message, stack, ...enumerable }`. A context payload with a class graph or circular reference will never throw during the write.
|
|
110
|
+
|
|
111
|
+
## `SentryLog`
|
|
112
|
+
|
|
113
|
+
Forwards entries to Sentry — `error` / `warn` become events (`captureException` for `Error` messages, `captureMessage` otherwise), every other level a breadcrumb (no quota). `@sentry/node` is an optional peer, lazily imported; pass an existing `client` or `options`.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import * as Sentry from "@sentry/node";
|
|
117
|
+
import { SentryLog } from "@warlock.js/logger";
|
|
118
|
+
|
|
119
|
+
new SentryLog({ client: Sentry, eventLevels: ["error", "warn"] });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Full guide — level mapping, init modes, shutdown draining: [`ship-logs-to-sentry`](@warlock.js/logger/ship-logs-to-sentry/SKILL.md).
|
|
123
|
+
|
|
124
|
+
## Shared config — `BasicLogConfigurations`
|
|
125
|
+
|
|
126
|
+
Every channel constructor accepts at minimum:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
type BasicLogConfigurations = {
|
|
130
|
+
levels?: LogLevel[]; // whitelist — omit or [] to allow all
|
|
131
|
+
filter?: (data: LoggingData) => boolean; // custom predicate
|
|
132
|
+
dateFormat?: { date?: string; time?: string }; // Day.js format strings
|
|
133
|
+
context?: (data) => Promise<Record<string, any>>; // reserved — not yet read
|
|
134
|
+
};
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Concrete file channels extend this with their storage/chunk/rotate/groupBy options via intersection.
|
|
138
|
+
|
|
139
|
+
## Picking a channel by name at runtime
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
log.channel("console"); // → ConsoleLog | undefined
|
|
143
|
+
log.channel("file"); // → FileLog | undefined
|
|
144
|
+
log.channel("fileJson"); // ← note the name — NOT "json"
|
|
145
|
+
log.channel("sentry"); // → SentryLog | undefined
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
If two channels share a `name`, only one is reachable this way — the search returns the first match.
|
|
149
|
+
|
|
150
|
+
## See also
|
|
151
|
+
|
|
152
|
+
- [`@warlock.js/logger/configure-logger/SKILL.md`](@warlock.js/logger/configure-logger/SKILL.md) — registering channels at startup
|
|
153
|
+
- [`@warlock.js/logger/filter-log-entries/SKILL.md`](@warlock.js/logger/filter-log-entries/SKILL.md) — `levels` and `filter` config in detail
|
|
154
|
+
- [`@warlock.js/logger/ship-logs-to-sentry/SKILL.md`](@warlock.js/logger/ship-logs-to-sentry/SKILL.md) — the `SentryLog` channel in depth
|
|
155
|
+
- [`@warlock.js/logger/write-custom-log-channel/SKILL.md`](@warlock.js/logger/write-custom-log-channel/SKILL.md) — extending `LogChannel` for custom sinks
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ship-logs-to-sentry
|
|
3
|
+
description: 'Forward log entries to Sentry with the SentryLog channel — error/warn become events (captureException/captureMessage), every other level a breadcrumb (no quota). @sentry/node is an OPTIONAL peer, lazily imported. Triggers: `SentryLog`, `@sentry/node`, `eventLevels`, `flushTimeout`, `Sentry.flush`, `captureException`, `addBreadcrumb`, `withScope`; "send logs to Sentry", "report errors to Sentry", "Sentry log channel", "Sentry breadcrumbs from logs", "log channel for Sentry"; typical import `import { SentryLog } from "@warlock.js/logger"`. Skip: file/console channels — `@warlock.js/logger/pick-log-channel/SKILL.md`; custom sinks — `@warlock.js/logger/write-custom-log-channel/SKILL.md`; graceful-shutdown flushing — `@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`; Slack alerting recipe.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Ship logs to Sentry — the `SentryLog` channel
|
|
7
|
+
|
|
8
|
+
`SentryLog` forwards log entries to Sentry. It's the one built-in channel that needs an external SDK, so `@sentry/node` is an **optional peer** — install it only if you use this channel:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @sentry/node
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Two ways to wire it
|
|
15
|
+
|
|
16
|
+
### Reuse an existing Sentry client (existing apps)
|
|
17
|
+
|
|
18
|
+
If your app already calls `Sentry.init(...)`, pass the namespace as `client`. The channel forwards through it and never re-imports or re-initializes the SDK:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import * as Sentry from "@sentry/node";
|
|
22
|
+
import { log, SentryLog } from "@warlock.js/logger";
|
|
23
|
+
|
|
24
|
+
Sentry.init({ dsn: process.env.SENTRY_DSN, environment: "production" });
|
|
25
|
+
|
|
26
|
+
log.addChannel(new SentryLog({ client: Sentry }));
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Let the channel initialize Sentry (new apps)
|
|
30
|
+
|
|
31
|
+
Pass `options`; the channel lazily imports `@sentry/node` and calls `Sentry.init` once — guarded so it never clobbers an existing client:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { log, SentryLog } from "@warlock.js/logger";
|
|
35
|
+
|
|
36
|
+
log.addChannel(
|
|
37
|
+
new SentryLog({
|
|
38
|
+
options: {
|
|
39
|
+
dsn: process.env.SENTRY_DSN,
|
|
40
|
+
environment: process.env.NODE_ENV,
|
|
41
|
+
release: process.env.GIT_SHA,
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
With neither `client` nor `options`, the channel reuses whatever global Sentry client the host already initialized.
|
|
48
|
+
|
|
49
|
+
## How levels map to Sentry
|
|
50
|
+
|
|
51
|
+
This is the quota-control decision. Only `eventLevels` create Sentry **events** (which consume your error quota); every other level becomes a **breadcrumb** that rides along with the next event for free.
|
|
52
|
+
|
|
53
|
+
| Logger level | Default | Sentry call |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `fatal` | event | `captureException` for an `Error` message, else `captureMessage(…, "fatal")` |
|
|
56
|
+
| `error` | event | `captureException` for an `Error` message, else `captureMessage(…, "error")` |
|
|
57
|
+
| `warn` | event | `captureMessage(…, "warning")` |
|
|
58
|
+
| `success` | breadcrumb | `addBreadcrumb({ level: "info" })` |
|
|
59
|
+
| `info` | breadcrumb | `addBreadcrumb({ level: "info" })` |
|
|
60
|
+
| `debug` | breadcrumb | `addBreadcrumb({ level: "debug" })` |
|
|
61
|
+
|
|
62
|
+
- **Errors keep their stack.** A `message` that is an `Error` goes through `captureException`, so Sentry parses the real stack and groups correctly — never pre-stringify the error.
|
|
63
|
+
- **`module` / `action` become tags** and the entry's `context` becomes a structured Sentry context, both scoped to that single event via `withScope`.
|
|
64
|
+
- **`success` has no Sentry severity** — it's reported as `info`.
|
|
65
|
+
|
|
66
|
+
### Tuning what becomes an event
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
// Only errors create events; warnings drop to breadcrumbs.
|
|
70
|
+
new SentryLog({ client: Sentry, eventLevels: ["error"] });
|
|
71
|
+
|
|
72
|
+
// Errors + warnings + an info stream as events (noisier, more quota).
|
|
73
|
+
new SentryLog({ client: Sentry, eventLevels: ["error", "warn", "info"] });
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`levels` and `filter` from `BasicLogConfigurations` apply first — a channel-level `levels: ["error", "warn"]` drops everything else before it reaches Sentry at all.
|
|
77
|
+
|
|
78
|
+
## Draining on shutdown
|
|
79
|
+
|
|
80
|
+
Sentry sends events asynchronously over the network, so a synchronous flush can't wait on them. `SentryLog.flush()` calls `Sentry.flush(timeout)`; drain it on your graceful-shutdown path:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
async function shutdown() {
|
|
84
|
+
await httpServer.close();
|
|
85
|
+
await log.flush(); // SentryLog.flush() → Sentry.flush(flushTimeout)
|
|
86
|
+
process.exit(0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
process.once("SIGTERM", shutdown);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`flushTimeout` (default `2000` ms) bounds the wait so an unreachable Sentry can't hang shutdown. `autoFlushOn` uses the **synchronous** `flushSync()`, which does *not* drain Sentry — wire `await log.flush()` yourself. See [`flush-logs-on-shutdown`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md).
|
|
93
|
+
|
|
94
|
+
## If `@sentry/node` isn't installed
|
|
95
|
+
|
|
96
|
+
The channel never crashes your app: the dynamic import failure is swallowed, the install instructions are written to stderr **once**, and entries are dropped silently thereafter. So registering `SentryLog` in shared config is safe even in an environment where Sentry isn't installed.
|
|
97
|
+
|
|
98
|
+
## Config reference
|
|
99
|
+
|
|
100
|
+
| Option | Type | Default | Description |
|
|
101
|
+
|---|---|---|---|
|
|
102
|
+
| `client` | Sentry namespace / forwarder | — | Reuse an already-initialized Sentry instance. |
|
|
103
|
+
| `options` | `SentryInitOptions` | — | Sentry init options (mirrors `@sentry/node`'s `NodeOptions`) — used when the channel owns Sentry. |
|
|
104
|
+
| `eventLevels` | `LogLevel[]` | `["fatal", "error", "warn"]` | Levels sent as events; the rest become breadcrumbs. |
|
|
105
|
+
| `flushTimeout` | `number` | `2000` | Ms `flush()` waits for the transport to drain. |
|
|
106
|
+
| `levels`, `filter`, `dateFormat`, `redact` | — | — | Inherited from `BasicLogConfigurations`. |
|
|
107
|
+
|
|
108
|
+
## Don't do
|
|
109
|
+
|
|
110
|
+
- **Don't double-init Sentry.** Pass *either* `client` *or* `options`, not both. The channel guards against double-init, but a single owner of `Sentry.init` is cleaner.
|
|
111
|
+
- **Don't send every level as an event.** `eventLevels` with `info`/`debug`/`success` will flood your Sentry quota — keep them as breadcrumbs.
|
|
112
|
+
- **Don't rely on `autoFlushOn` for Sentry.** It's synchronous; a network channel needs `await log.flush()`.
|
|
113
|
+
|
|
114
|
+
## See also
|
|
115
|
+
|
|
116
|
+
- [`@warlock.js/logger/flush-logs-on-shutdown/SKILL.md`](@warlock.js/logger/flush-logs-on-shutdown/SKILL.md) — `await log.flush()` on shutdown
|
|
117
|
+
- [`@warlock.js/logger/pick-log-channel/SKILL.md`](@warlock.js/logger/pick-log-channel/SKILL.md) — the console / file channels
|
|
118
|
+
- [`@warlock.js/logger/write-custom-log-channel/SKILL.md`](@warlock.js/logger/write-custom-log-channel/SKILL.md) — build your own sink
|