@zudojs/logger 1.2.0 → 1.4.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/README.md +74 -5
- package/dist/loggerCore/core/loggerCore.context.d.ts +4 -4
- package/dist/loggerCore/core/loggerCore.core.d.ts +4 -4
- package/dist/loggerCore/core/loggerCore.core.js +8 -8
- package/dist/loggerCore/core/loggerCore.type.d.ts +14 -4
- package/dist/loggerCore/helpers/loggerCore.helper.d.ts +2 -2
- package/dist/loggerCore/helpers/loggerCoreMethods/index.d.ts +1 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/index.js +1 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.child.d.ts +2 -2
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.dispatch.js +71 -25
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.entry.d.ts +6 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.entry.js +8 -3
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.level.d.ts +7 -0
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.level.js +35 -2
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.lifecycle.d.ts +3 -3
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.lifecycle.js +8 -6
- package/dist/loggerEntry/loggerEntryCreate.js +2 -1
- package/dist/loggerEntry/loggerEntryHelpers/index.d.ts +1 -1
- package/dist/loggerEntry/loggerEntryHelpers/index.js +1 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.interfaces.d.ts +11 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.d.ts +18 -5
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.js +66 -21
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.serialize.js +2 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.d.ts +11 -2
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.js +53 -20
- package/dist/loggerFactory/loggerFactory.core.d.ts +9 -2
- package/dist/loggerFactory/loggerFactory.core.js +10 -0
- package/dist/loggerFormatter/loggerFormatter.core.js +3 -2
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.json.js +26 -13
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.d.ts +5 -2
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.js +12 -5
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.text.js +8 -4
- package/dist/loggerLevel/loggerLevel.type.d.ts +13 -0
- package/dist/loggerLevel/loggerLevel.type.js +17 -2
- package/dist/loggerManager/loggerManager.core.d.ts +10 -0
- package/dist/loggerManager/loggerManager.core.js +24 -7
- package/dist/loggerOptions/loggerOptions.type.d.ts +14 -3
- package/dist/loggerOptions/loggerOptions.type.js +7 -3
- package/dist/loggerTransport/loggerTransportComposite/loggerTransportComposite.buffered.js +9 -0
- package/dist/loggerTransport/loggerTransportConsole/loggerTransportConsole.core.d.ts +3 -2
- package/dist/loggerTransport/loggerTransportConsole/loggerTransportConsole.core.js +9 -4
- package/dist/loggerTransport/loggerTransportHelpers/index.d.ts +1 -1
- package/dist/loggerTransport/loggerTransportHelpers/index.js +1 -1
- package/dist/loggerTransport/loggerTransportHelpers/loggerTransportHelpers.d.ts +15 -0
- package/dist/loggerTransport/loggerTransportHelpers/loggerTransportHelpers.js +22 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -34,13 +34,56 @@ await logger.flush(); // drain in-flight writes before exit
|
|
|
34
34
|
(5). A logger emits every message at or below its configured level;
|
|
35
35
|
`level` defaults to `info`.
|
|
36
36
|
|
|
37
|
+
Wherever a level is configured (the `level` option, `setLevel()` and
|
|
38
|
+
`child({ level })`) it may be the enum value or its name in any case:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
createLogger({ level: "error" }); // same as LoggerLevel.ERROR
|
|
42
|
+
logger.setLevel("DEBUG");
|
|
43
|
+
logger.child({ level: LoggerLevel.TRACE });
|
|
44
|
+
createLogger({ level: process.env.LOG_LEVEL as LoggerLevelName });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The type is `LoggerLevelLike` (`LoggerLevel | LoggerLevelName | Uppercase<LoggerLevelName>`);
|
|
48
|
+
`"warning"` and `"information"` are accepted as aliases at runtime, and
|
|
49
|
+
`resolveLoggerLevel(value)` converts one to the enum. An unknown name
|
|
50
|
+
throws (`InvalidLoggerLevelError` from the options and `child`,
|
|
51
|
+
`LoggerConfigurationError` from `setLevel`) rather than leaving a logger
|
|
52
|
+
that silently emits nothing. A custom `Logger` implementation keeps
|
|
53
|
+
compiling (`ChildLoggerOptions.level` is still the enum; `child()` accepts
|
|
54
|
+
`ChildLoggerOptionsInput`), but may now be handed a name in `setLevel()` or
|
|
55
|
+
`child()`: pass it through `resolveLoggerLevel()`.
|
|
56
|
+
|
|
37
57
|
## Transports
|
|
38
58
|
|
|
39
59
|
A transport is either a `{ name, enabled, write, flush?, close? }`
|
|
40
60
|
object or a `(entry, context) => void | Promise<void>` function. When no
|
|
41
61
|
transport is configured the logger writes to the console.
|
|
42
62
|
|
|
43
|
-
|
|
63
|
+
### What a transport receives
|
|
64
|
+
|
|
65
|
+
`entry.message` is the message exactly as it was logged. The logger's
|
|
66
|
+
formatter renders the whole record into `entry.formatted`:
|
|
67
|
+
|
|
68
|
+
- a text formatter (the default): the line with timestamp, level, logger
|
|
69
|
+
name, message, metadata and, if enabled, the stack;
|
|
70
|
+
- the JSON formatter: its JSON string;
|
|
71
|
+
- an object formatter such as `createStructuredLoggerFormatter()`: its
|
|
72
|
+
record is merged over the entry, and `entry.formatted` is that record as
|
|
73
|
+
one line of JSON (cycles become `"[Circular]"`, BigInt a string).
|
|
74
|
+
|
|
75
|
+
A transport that prints text should print `entry.formatted ?? entry.message`
|
|
76
|
+
(or call `formatTransportLine(entry)`, which falls back to the entry as one
|
|
77
|
+
JSON line); one that ships records can ignore `formatted`.
|
|
78
|
+
|
|
79
|
+
> **Changed in this release.** A string formatter's output used to replace
|
|
80
|
+
> `entry.message`, so a custom transport printing `entry.message` got the
|
|
81
|
+
> formatted line and could not recover the raw message. It now receives
|
|
82
|
+
> the raw message; switch such a transport to
|
|
83
|
+
> `entry.formatted ?? entry.message` to keep printing the formatted line.
|
|
84
|
+
|
|
85
|
+
Built in: `createConsoleLoggerTransport` (prints one line per record:
|
|
86
|
+
`entry.formatted`, or the entry as JSON), and the composites
|
|
44
87
|
`createMultiLoggerTransport`, `createConditionalLoggerTransport` and
|
|
45
88
|
`createBufferedLoggerTransport`. File and HTTP transports are not
|
|
46
89
|
included — implement the `LoggerTransport` interface for those.
|
|
@@ -55,7 +98,11 @@ that entry, and a failure from a timer-triggered flush is rethrown by the
|
|
|
55
98
|
next `flush()` or `close()`.
|
|
56
99
|
|
|
57
100
|
`transportTimeout` (default 10s) bounds every transport write, so a
|
|
58
|
-
transport that stops responding cannot hang `flush()` or `close()`.
|
|
101
|
+
transport that stops responding cannot hang `flush()` or `close()`. A
|
|
102
|
+
write that exceeds it fails with `LoggerTimeoutError`, carrying
|
|
103
|
+
`transportName` and `timeout`; other write failures are reported as
|
|
104
|
+
`LoggerTransportError` with `transportName` set, and formatter failures
|
|
105
|
+
as `LoggerFormatterError` with `formatterName` set.
|
|
59
106
|
|
|
60
107
|
`throwTransportErrors` (default `false`) rethrows transport and formatter
|
|
61
108
|
failures instead of dropping them. A synchronous transport throws from the
|
|
@@ -88,8 +135,14 @@ against `DEFAULT_LOGGER_SECRET_FIELDS` — password, passphrase, secret,
|
|
|
88
135
|
token, jwt, bearer, auth, authorization, cookie, session, sid,
|
|
89
136
|
credential, api key, private key, client secret, card number, cvv, ssn,
|
|
90
137
|
pin, otp and more — so `sessionId` and `cardNumber` are redacted while
|
|
91
|
-
`passenger` and `authorId` are not. Nested objects, arrays
|
|
92
|
-
are all covered
|
|
138
|
+
`passenger` and `authorId` are not. Nested objects, arrays, `Map`,
|
|
139
|
+
`Set` and getters are all covered — a `Map` is redacted per key and a
|
|
140
|
+
`Set` becomes an array. A getter that THROWS yields `"[Unreadable]"`
|
|
141
|
+
for that field: the rest of the entry is logged and the read failure is
|
|
142
|
+
reported through the same path as transport and formatter failures
|
|
143
|
+
(dropped by default, rethrown with `throwTransportErrors`), so a lazy
|
|
144
|
+
ORM relation can never abort the caller's log statement. Passing
|
|
145
|
+
`redact.pattern` replaces the word matcher with
|
|
93
146
|
your own RegExp (the old substring default is still exported as
|
|
94
147
|
`DEFAULT_LOGGER_SECRET_PATTERN`).
|
|
95
148
|
|
|
@@ -115,7 +168,10 @@ indented so none can start at column 0 and pass for a record. The JSON formatter
|
|
|
115
168
|
|
|
116
169
|
Metadata is normalized before serialization, so circular references
|
|
117
170
|
(`"[Circular]"`), BigInt values and functions never make a formatter
|
|
118
|
-
throw and silently drop the record.
|
|
171
|
+
throw and silently drop the record. Only a genuine back-edge becomes
|
|
172
|
+
`"[Circular]"` — the walk tracks the ancestor path, so an object
|
|
173
|
+
referenced from two places in one payload (`{ actor: user, target: user }`)
|
|
174
|
+
is logged in full both times.
|
|
119
175
|
|
|
120
176
|
## Context
|
|
121
177
|
|
|
@@ -150,6 +206,19 @@ Pass `{ colors: true }` in the formatter context to colourize the level
|
|
|
150
206
|
tag of text output. Colour codes are emitted only around the fixed level
|
|
151
207
|
name, never around user-supplied text.
|
|
152
208
|
|
|
209
|
+
A formatter returns either a string or an object
|
|
210
|
+
(`LoggerFormattedOutput`). A string becomes the payload's `formatted`
|
|
211
|
+
line (`message` stays the raw message); an object is merged OVER the
|
|
212
|
+
entry, so `createStructuredLoggerFormatter()` hands the transport its
|
|
213
|
+
structured record (with an ISO-string `timestamp` and serialized
|
|
214
|
+
metadata) rather than the raw entry, and `formatted` is the record as one
|
|
215
|
+
JSON line. See "What a transport receives".
|
|
216
|
+
|
|
217
|
+
`includeStackTrace: false` on the text formatter leaves every stack out:
|
|
218
|
+
an entry's error prints as `error={"name":"Error","message":"..."}`, and
|
|
219
|
+
an `Error` inside metadata is serialized without its stack, so no frame
|
|
220
|
+
(and no absolute file path) reaches the log.
|
|
221
|
+
|
|
153
222
|
## Use Cases
|
|
154
223
|
|
|
155
224
|
- Application logging
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ContextLogger wrapper implementation.
|
|
3
3
|
*/
|
|
4
|
-
import type { LoggerLevel } from "../../loggerLevel/loggerLevel.type.js";
|
|
4
|
+
import type { LoggerLevel, LoggerLevelLike } from "../../loggerLevel/loggerLevel.type.js";
|
|
5
5
|
import type { LogMetadata } from "../../loggerEntry/loggerEntry.type.js";
|
|
6
6
|
import type { LoggerContext, LoggerContextStorage } from "../../loggerContext/loggerContext.core.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ChildLoggerOptionsInput, LogOptions } from "../../loggerOptions/loggerOptions.type.js";
|
|
8
8
|
import type { Logger } from "./loggerCore.type.js";
|
|
9
9
|
/**
|
|
10
10
|
* Logger wrapper that provides scoped context.
|
|
@@ -30,9 +30,9 @@ export declare class ContextLogger implements Logger {
|
|
|
30
30
|
debug(message: string, metadata?: LogMetadata): void;
|
|
31
31
|
trace(message: string, metadata?: LogMetadata): void;
|
|
32
32
|
log(level: LoggerLevel, message: string, options?: LogOptions): void;
|
|
33
|
-
child(options?:
|
|
33
|
+
child(options?: ChildLoggerOptionsInput): Logger;
|
|
34
34
|
withContext(context: LoggerContext): Logger;
|
|
35
|
-
setLevel(level:
|
|
35
|
+
setLevel(level: LoggerLevelLike): void;
|
|
36
36
|
enable(): void;
|
|
37
37
|
disable(): void;
|
|
38
38
|
flush(): Promise<void>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core logger implementation.
|
|
3
3
|
*/
|
|
4
|
-
import { LoggerLevel } from "../../loggerLevel/loggerLevel.type.js";
|
|
4
|
+
import { LoggerLevel, type LoggerLevelLike } from "../../loggerLevel/loggerLevel.type.js";
|
|
5
5
|
import type { LogMetadata } from "../../loggerEntry/loggerEntry.type.js";
|
|
6
6
|
import type { LoggerContext, LoggerContextStorage } from "../../loggerContext/loggerContext.core.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ChildLoggerOptionsInput, LoggerConfiguration, LoggerOptions, LogOptions } from "../../loggerOptions/loggerOptions.type.js";
|
|
8
8
|
import type { Logger } from "./loggerCore.type.js";
|
|
9
9
|
/**
|
|
10
10
|
* Internal context passed to extracted methods.
|
|
@@ -54,9 +54,9 @@ export declare class ZudojsLogger implements Logger, ZudojsLoggerContext {
|
|
|
54
54
|
debug(message: string, metadata?: LogMetadata): void;
|
|
55
55
|
trace(message: string, metadata?: LogMetadata): void;
|
|
56
56
|
log(level: LoggerLevel, message: string, options?: LogOptions): void;
|
|
57
|
-
child(options?:
|
|
57
|
+
child(options?: ChildLoggerOptionsInput): Logger;
|
|
58
58
|
withContext(context: LoggerContext): Logger;
|
|
59
|
-
setLevel(level:
|
|
59
|
+
setLevel(level: LoggerLevelLike): void;
|
|
60
60
|
enable(): void;
|
|
61
61
|
disable(): void;
|
|
62
62
|
flush(): Promise<void>;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core logger implementation.
|
|
3
3
|
*/
|
|
4
|
-
import { LoggerLevel } from "../../loggerLevel/loggerLevel.type.js";
|
|
4
|
+
import { LoggerLevel, } from "../../loggerLevel/loggerLevel.type.js";
|
|
5
5
|
import { createLoggerContextStorage } from "../../loggerContext/loggerContextStorage.js";
|
|
6
6
|
import { resolveLoggerOptions } from "../../loggerOptions/loggerOptions.type.js";
|
|
7
7
|
import { normalizeConfiguration, assertActive as assertActiveHelper, assertMutable as assertMutableHelper, handleInfrastructureError as handleInfrastructureErrorHelper, } from "../helpers/loggerCoreHelpers.js";
|
|
8
|
-
import { logAtLevel, childLogger, withContextLogger, setLoggerLevel, enableLogger, disableLogger, flushLogger, closeLogger, } from "../helpers/loggerCoreMethods/index.js";
|
|
8
|
+
import { logAtLevel, levelOptions, childLogger, withContextLogger, setLoggerLevel, enableLogger, disableLogger, flushLogger, closeLogger, } from "../helpers/loggerCoreMethods/index.js";
|
|
9
9
|
import { getLoggerName, getLoggerLevel, getLoggerEnabled, } from "../helpers/loggerCoreMethods.loggerProps.js";
|
|
10
10
|
/** Upper bound on dispatch failures retained between two flushes. */
|
|
11
11
|
const MAX_RETAINED_DISPATCH_FAILURES = 32;
|
|
@@ -48,22 +48,22 @@ export class ZudojsLogger {
|
|
|
48
48
|
return getLoggerEnabled(this);
|
|
49
49
|
}
|
|
50
50
|
fatal(message, metadata) {
|
|
51
|
-
logAtLevel(this, LoggerLevel.FATAL, message,
|
|
51
|
+
logAtLevel(this, LoggerLevel.FATAL, message, levelOptions(metadata));
|
|
52
52
|
}
|
|
53
53
|
error(message, metadata) {
|
|
54
|
-
logAtLevel(this, LoggerLevel.ERROR, message,
|
|
54
|
+
logAtLevel(this, LoggerLevel.ERROR, message, levelOptions(metadata));
|
|
55
55
|
}
|
|
56
56
|
warn(message, metadata) {
|
|
57
|
-
logAtLevel(this, LoggerLevel.WARN, message,
|
|
57
|
+
logAtLevel(this, LoggerLevel.WARN, message, levelOptions(metadata));
|
|
58
58
|
}
|
|
59
59
|
info(message, metadata) {
|
|
60
|
-
logAtLevel(this, LoggerLevel.INFO, message,
|
|
60
|
+
logAtLevel(this, LoggerLevel.INFO, message, levelOptions(metadata));
|
|
61
61
|
}
|
|
62
62
|
debug(message, metadata) {
|
|
63
|
-
logAtLevel(this, LoggerLevel.DEBUG, message,
|
|
63
|
+
logAtLevel(this, LoggerLevel.DEBUG, message, levelOptions(metadata));
|
|
64
64
|
}
|
|
65
65
|
trace(message, metadata) {
|
|
66
|
-
logAtLevel(this, LoggerLevel.TRACE, message,
|
|
66
|
+
logAtLevel(this, LoggerLevel.TRACE, message, levelOptions(metadata));
|
|
67
67
|
}
|
|
68
68
|
log(level, message, options = {}) {
|
|
69
69
|
logAtLevel(this, level, message, options);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Logger core types and interfaces.
|
|
3
3
|
*/
|
|
4
|
-
import type { LoggerLevel } from "../../loggerLevel/loggerLevel.type.js";
|
|
4
|
+
import type { LoggerLevel, LoggerLevelLike } from "../../loggerLevel/loggerLevel.type.js";
|
|
5
5
|
import type { LogMetadata } from "../../loggerEntry/loggerEntry.type.js";
|
|
6
6
|
import type { LoggerContext } from "../../loggerContext/loggerContext.core.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ChildLoggerOptionsInput, LogOptions } from "../../loggerOptions/loggerOptions.type.js";
|
|
8
8
|
/**
|
|
9
9
|
* Main Zudojs logger contract.
|
|
10
10
|
*/
|
|
@@ -19,9 +19,19 @@ export interface Logger {
|
|
|
19
19
|
debug(message: string, metadata?: LogMetadata): void;
|
|
20
20
|
trace(message: string, metadata?: LogMetadata): void;
|
|
21
21
|
log(level: LoggerLevel, message: string, options?: LogOptions): void;
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Creates a child logger. `level` may be a name (`"debug"`); an
|
|
24
|
+
* implementation declared with `ChildLoggerOptions` still satisfies this
|
|
25
|
+
* interface and can resolve a name with `resolveLoggerLevel()`.
|
|
26
|
+
*/
|
|
27
|
+
child(options?: ChildLoggerOptionsInput): Logger;
|
|
23
28
|
withContext(context: LoggerContext): Logger;
|
|
24
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Sets the threshold. Accepts `LoggerLevel.ERROR` or a name such as
|
|
31
|
+
* `"error"` (any case). An implementation declared with a `LoggerLevel`
|
|
32
|
+
* parameter still satisfies this interface.
|
|
33
|
+
*/
|
|
34
|
+
setLevel(level: LoggerLevelLike): void;
|
|
25
35
|
enable(): void;
|
|
26
36
|
disable(): void;
|
|
27
37
|
flush(): Promise<void>;
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { LogMetadata } from "../../loggerEntry/loggerEntry.type.js";
|
|
5
5
|
import type { LoggerContext } from "../../loggerContext/loggerContext.core.js";
|
|
6
|
-
import type {
|
|
6
|
+
import type { ChildLoggerOptionsInput } from "../../loggerOptions/loggerOptions.type.js";
|
|
7
7
|
import type { Logger } from "../core/loggerCore.type.js";
|
|
8
8
|
/**
|
|
9
9
|
* Creates a child logger.
|
|
10
10
|
*/
|
|
11
|
-
export declare function createChildLogger(parent: Logger, options?:
|
|
11
|
+
export declare function createChildLogger(parent: Logger, options?: ChildLoggerOptionsInput): Logger;
|
|
12
12
|
/**
|
|
13
13
|
* Creates a logger specifically for an error.
|
|
14
14
|
*/
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { createEntry } from "./loggerCoreMethods.entry.js";
|
|
7
7
|
export { dispatchEntry, dispatchEntrySync, } from "./loggerCoreMethods.dispatch.js";
|
|
8
|
-
export { logAtLevel } from "./loggerCoreMethods.level.js";
|
|
8
|
+
export { logAtLevel, levelOptions } from "./loggerCoreMethods.level.js";
|
|
9
9
|
export { childLogger, withContextLogger } from "./loggerCoreMethods.child.js";
|
|
10
10
|
export { setLoggerLevel, enableLogger, disableLogger, flushLogger, closeLogger, } from "./loggerCoreMethods.lifecycle.js";
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { createEntry } from "./loggerCoreMethods.entry.js";
|
|
7
7
|
export { dispatchEntry, dispatchEntrySync, } from "./loggerCoreMethods.dispatch.js";
|
|
8
|
-
export { logAtLevel } from "./loggerCoreMethods.level.js";
|
|
8
|
+
export { logAtLevel, levelOptions } from "./loggerCoreMethods.level.js";
|
|
9
9
|
export { childLogger, withContextLogger } from "./loggerCoreMethods.child.js";
|
|
10
10
|
export { setLoggerLevel, enableLogger, disableLogger, flushLogger, closeLogger, } from "./loggerCoreMethods.lifecycle.js";
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* ZudojsLogger child and context methods.
|
|
3
3
|
*/
|
|
4
4
|
import type { LoggerContext } from "../../../loggerContext/loggerContext.core.js";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ChildLoggerOptionsInput } from "../../../loggerOptions/loggerOptions.type.js";
|
|
6
6
|
import type { Logger } from "../../core/loggerCore.type.js";
|
|
7
7
|
import type { ZudojsLoggerContext } from "../../core/loggerCore.core.js";
|
|
8
8
|
/**
|
|
9
9
|
* Creates a child logger.
|
|
10
10
|
*/
|
|
11
|
-
export declare function childLogger(ctx: ZudojsLoggerContext, options?:
|
|
11
|
+
export declare function childLogger(ctx: ZudojsLoggerContext, options?: ChildLoggerOptionsInput): Logger;
|
|
12
12
|
/**
|
|
13
13
|
* Creates a logger with scoped context.
|
|
14
14
|
*/
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
import { formatLoggerEntry } from "../../../loggerFormatter/loggerFormatter.core.js";
|
|
5
5
|
import { createLoggerTransport, writeLoggerTransport, } from "../../../loggerTransport/loggerTransport.core.js";
|
|
6
6
|
import { isLoggerTransport } from "../../../loggerTransport/loggerTransportGuard.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { toJsonLogLine } from "../../../loggerTransport/loggerTransportHelpers/loggerTransportHelpers.js";
|
|
8
|
+
import { LoggerFormatterError, LoggerTimeoutError, LoggerTransportError, } from "../../../loggerErrors/loggerError.base.js";
|
|
9
|
+
import { createLoggerFormatterError, createLoggerTransportError, } from "../../../loggerErrors/loggerError.helpers.js";
|
|
9
10
|
/**
|
|
10
11
|
* Default formatter used when no formatter is configured.
|
|
11
12
|
*/
|
|
@@ -33,7 +34,11 @@ async function withTransportTimeout(timeoutMs, transportName, operation) {
|
|
|
33
34
|
let timer;
|
|
34
35
|
const expiry = new Promise((_resolve, reject) => {
|
|
35
36
|
timer = setTimeout(() => {
|
|
36
|
-
|
|
37
|
+
// LoggerTimeoutError carries `transportName` and `timeout`, which
|
|
38
|
+
// the bare LoggerTransportError raised here before did not — so
|
|
39
|
+
// `catch (e) { if (e instanceof LoggerTimeoutError) retry() }`
|
|
40
|
+
// could never match.
|
|
41
|
+
reject(new LoggerTimeoutError(transportName, timeoutMs));
|
|
37
42
|
}, timeoutMs);
|
|
38
43
|
// This timer bounds a write; it is not work in its own right. Left
|
|
39
44
|
// referenced it keeps the event loop alive, so a process that has
|
|
@@ -53,20 +58,60 @@ async function withTransportTimeout(timeoutMs, transportName, operation) {
|
|
|
53
58
|
void operation.catch(() => { });
|
|
54
59
|
}
|
|
55
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Builds the payload handed to a transport.
|
|
63
|
+
*
|
|
64
|
+
* `LoggerFormattedOutput` is `string | Record<string, unknown>`. A string
|
|
65
|
+
* is the formatted line and is carried in `formatted`; `message` stays the
|
|
66
|
+
* caller's raw message. (It used to be replaced by the line, so a transport
|
|
67
|
+
* could not get the message back without parsing it out again.) An OBJECT
|
|
68
|
+
* is the formatted record: it is merged over the entry, so a transport sees
|
|
69
|
+
* the formatter's fields, and `formatted` is that record as one JSON line.
|
|
70
|
+
*/
|
|
71
|
+
function toTransportPayload(entry, formatted) {
|
|
72
|
+
if (typeof formatted === "string") {
|
|
73
|
+
return { ...entry, formatted };
|
|
74
|
+
}
|
|
75
|
+
if (formatted !== null &&
|
|
76
|
+
typeof formatted === "object" &&
|
|
77
|
+
!Array.isArray(formatted)) {
|
|
78
|
+
return {
|
|
79
|
+
...entry,
|
|
80
|
+
...formatted,
|
|
81
|
+
formatted: toJsonLogLine(formatted),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return entry;
|
|
85
|
+
}
|
|
86
|
+
/** Name of the configured formatter, for error reporting. */
|
|
87
|
+
function resolveFormatterName(configuration) {
|
|
88
|
+
const formatter = configuration.formatter;
|
|
89
|
+
if (typeof formatter === "string") {
|
|
90
|
+
return formatter;
|
|
91
|
+
}
|
|
92
|
+
return formatter.name ?? "formatter";
|
|
93
|
+
}
|
|
94
|
+
/** Wraps a transport failure, keeping an already-typed logger error. */
|
|
95
|
+
function toTransportError(transportName, error) {
|
|
96
|
+
return error instanceof LoggerTransportError
|
|
97
|
+
? error
|
|
98
|
+
: createLoggerTransportError(transportName, error);
|
|
99
|
+
}
|
|
100
|
+
/** Wraps a formatter failure, keeping an already-typed logger error. */
|
|
101
|
+
function toFormatterError(formatterName, error) {
|
|
102
|
+
return error instanceof LoggerFormatterError
|
|
103
|
+
? error
|
|
104
|
+
: createLoggerFormatterError(formatterName, error);
|
|
105
|
+
}
|
|
56
106
|
/**
|
|
57
107
|
* Writes to a transport.
|
|
58
108
|
*/
|
|
59
|
-
async function writeTransport(configuration, transport,
|
|
109
|
+
async function writeTransport(configuration, transport, payload) {
|
|
60
110
|
const transportContext = {
|
|
61
111
|
loggerName: configuration.name,
|
|
62
112
|
environment: configuration.environment,
|
|
63
113
|
};
|
|
64
|
-
|
|
65
|
-
const formattedEntry = { ...entry, message: formatted };
|
|
66
|
-
await writeLoggerTransport(transport.transport, formattedEntry, transportContext);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
await writeLoggerTransport(transport.transport, entry, transportContext);
|
|
114
|
+
await writeLoggerTransport(transport.transport, payload, transportContext);
|
|
70
115
|
}
|
|
71
116
|
/**
|
|
72
117
|
* Formats an entry with the configured formatter.
|
|
@@ -89,12 +134,11 @@ function formatEntry(configuration, entry) {
|
|
|
89
134
|
* the transport directly lets a synchronous console/array transport
|
|
90
135
|
* complete inline, which is what `asynchronous: false` promises.
|
|
91
136
|
*/
|
|
92
|
-
function writeTransportMaybeSync(configuration, transport,
|
|
137
|
+
function writeTransportMaybeSync(configuration, transport, payload) {
|
|
93
138
|
const transportContext = {
|
|
94
139
|
loggerName: configuration.name,
|
|
95
140
|
environment: configuration.environment,
|
|
96
141
|
};
|
|
97
|
-
const payload = typeof formatted === "string" ? { ...entry, message: formatted } : entry;
|
|
98
142
|
const target = transport.transport;
|
|
99
143
|
return typeof target === "function"
|
|
100
144
|
? target(payload, transportContext)
|
|
@@ -104,29 +148,29 @@ function writeTransportMaybeSync(configuration, transport, entry, formatted) {
|
|
|
104
148
|
* Dispatches an entry to the configured transports.
|
|
105
149
|
*/
|
|
106
150
|
export async function dispatchEntry(configuration, entry, handleError) {
|
|
107
|
-
let
|
|
151
|
+
let payload;
|
|
108
152
|
try {
|
|
109
|
-
|
|
153
|
+
payload = toTransportPayload(entry, formatEntry(configuration, entry));
|
|
110
154
|
}
|
|
111
155
|
catch (error) {
|
|
112
|
-
|
|
113
|
-
handleError(formatterError);
|
|
156
|
+
handleError(toFormatterError(resolveFormatterName(configuration), error));
|
|
114
157
|
return;
|
|
115
158
|
}
|
|
116
159
|
for (const transport of configuration.transports) {
|
|
160
|
+
let transportName = "transport";
|
|
117
161
|
try {
|
|
118
162
|
if (!isLoggerTransport(transport)) {
|
|
119
163
|
continue;
|
|
120
164
|
}
|
|
121
165
|
const registered = createLoggerTransport(transport);
|
|
166
|
+
transportName = registered.name;
|
|
122
167
|
if (!registered.enabled) {
|
|
123
168
|
continue;
|
|
124
169
|
}
|
|
125
|
-
await withTransportTimeout(configuration.transportTimeout, registered.name, writeTransport(configuration, registered,
|
|
170
|
+
await withTransportTimeout(configuration.transportTimeout, registered.name, writeTransport(configuration, registered, payload));
|
|
126
171
|
}
|
|
127
172
|
catch (error) {
|
|
128
|
-
|
|
129
|
-
handleError(transportError);
|
|
173
|
+
handleError(toTransportError(transportName, error));
|
|
130
174
|
}
|
|
131
175
|
}
|
|
132
176
|
}
|
|
@@ -148,33 +192,35 @@ export function dispatchEntrySync(configuration, entry, handleError) {
|
|
|
148
192
|
// caller off the transport's critical path.
|
|
149
193
|
return Promise.resolve().then(() => dispatchEntry(configuration, entry, handleError));
|
|
150
194
|
}
|
|
151
|
-
let
|
|
195
|
+
let payload;
|
|
152
196
|
try {
|
|
153
|
-
|
|
197
|
+
payload = toTransportPayload(entry, formatEntry(configuration, entry));
|
|
154
198
|
}
|
|
155
199
|
catch (error) {
|
|
156
|
-
handleError(
|
|
200
|
+
handleError(toFormatterError(resolveFormatterName(configuration), error));
|
|
157
201
|
return;
|
|
158
202
|
}
|
|
159
203
|
const pending = [];
|
|
160
204
|
for (const transport of configuration.transports) {
|
|
205
|
+
let transportName = "transport";
|
|
161
206
|
try {
|
|
162
207
|
if (!isLoggerTransport(transport)) {
|
|
163
208
|
continue;
|
|
164
209
|
}
|
|
165
210
|
const registered = createLoggerTransport(transport);
|
|
211
|
+
transportName = registered.name;
|
|
166
212
|
if (!registered.enabled) {
|
|
167
213
|
continue;
|
|
168
214
|
}
|
|
169
|
-
const result = writeTransportMaybeSync(configuration, registered,
|
|
215
|
+
const result = writeTransportMaybeSync(configuration, registered, payload);
|
|
170
216
|
if (result instanceof Promise) {
|
|
171
217
|
pending.push(withTransportTimeout(configuration.transportTimeout, registered.name, result).catch((error) => {
|
|
172
|
-
handleError(
|
|
218
|
+
handleError(toTransportError(registered.name, error));
|
|
173
219
|
}));
|
|
174
220
|
}
|
|
175
221
|
}
|
|
176
222
|
catch (error) {
|
|
177
|
-
handleError(
|
|
223
|
+
handleError(toTransportError(transportName, error));
|
|
178
224
|
}
|
|
179
225
|
}
|
|
180
226
|
if (pending.length === 0) {
|
|
@@ -6,8 +6,13 @@ import type { LoggerEntry } from "../../../loggerEntry/loggerEntry.type.js";
|
|
|
6
6
|
import type { LoggerConfiguration, LogOptions } from "../../../loggerOptions/loggerOptions.type.js";
|
|
7
7
|
/**
|
|
8
8
|
* Creates a normalized log entry.
|
|
9
|
+
*
|
|
10
|
+
* @param onMetadataError - Notified when a metadata property could not
|
|
11
|
+
* be read (a throwing getter). The field is replaced with a marker
|
|
12
|
+
* and the entry is still produced, so the caller's log statement
|
|
13
|
+
* never aborts; reporting is the caller's job.
|
|
9
14
|
*/
|
|
10
15
|
export declare function createEntry(configuration: LoggerConfiguration, contextStorage: {
|
|
11
16
|
get(): import("../../../loggerContext/loggerContext.core.js").LoggerContext | undefined;
|
|
12
|
-
}, level: LoggerLevel, message: string, options: LogOptions): LoggerEntry;
|
|
17
|
+
}, level: LoggerLevel, message: string, options: LogOptions, onMetadataError?: (key: string, error: unknown) => void): LoggerEntry;
|
|
13
18
|
//# sourceMappingURL=loggerCoreMethods.entry.d.ts.map
|
|
@@ -6,8 +6,13 @@ import { createSecretMatcher, redactLogValue, LOGGER_REDACTION_TOKEN, } from "..
|
|
|
6
6
|
import { contextToLogMetadata, createLoggerContext, } from "../../../loggerContext/loggerContext.core.js";
|
|
7
7
|
/**
|
|
8
8
|
* Creates a normalized log entry.
|
|
9
|
+
*
|
|
10
|
+
* @param onMetadataError - Notified when a metadata property could not
|
|
11
|
+
* be read (a throwing getter). The field is replaced with a marker
|
|
12
|
+
* and the entry is still produced, so the caller's log statement
|
|
13
|
+
* never aborts; reporting is the caller's job.
|
|
9
14
|
*/
|
|
10
|
-
export function createEntry(configuration, contextStorage, level, message, options) {
|
|
15
|
+
export function createEntry(configuration, contextStorage, level, message, options, onMetadataError) {
|
|
11
16
|
const activeContext = configuration.inheritContext
|
|
12
17
|
? contextStorage.get()
|
|
13
18
|
: undefined;
|
|
@@ -29,7 +34,7 @@ export function createEntry(configuration, contextStorage, level, message, optio
|
|
|
29
34
|
// path can bypass it — including nested objects, arrays and getters.
|
|
30
35
|
const isSecret = createSecretMatcher(configuration.redact);
|
|
31
36
|
const replacement = configuration.redact.replacement ?? LOGGER_REDACTION_TOKEN;
|
|
32
|
-
const metadata = redactLogValue(rawMetadata, isSecret, replacement);
|
|
37
|
+
const metadata = redactLogValue(rawMetadata, isSecret, replacement, undefined, onMetadataError);
|
|
33
38
|
const context = options.context
|
|
34
39
|
? createLoggerContext({
|
|
35
40
|
parent: activeContext,
|
|
@@ -46,7 +51,7 @@ export function createEntry(configuration, contextStorage, level, message, optio
|
|
|
46
51
|
context: context
|
|
47
52
|
? {
|
|
48
53
|
...context.identifiers,
|
|
49
|
-
metadata: redactLogValue(context.metadata, isSecret, replacement),
|
|
54
|
+
metadata: redactLogValue(context.metadata, isSecret, replacement, undefined, onMetadataError),
|
|
50
55
|
}
|
|
51
56
|
: undefined,
|
|
52
57
|
source: options.source,
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
import { LoggerLevel } from "../../../loggerLevel/loggerLevel.type.js";
|
|
5
5
|
import type { LogOptions } from "../../../loggerOptions/loggerOptions.type.js";
|
|
6
6
|
import type { ZudojsLoggerContext } from "../../core/loggerCore.core.js";
|
|
7
|
+
/**
|
|
8
|
+
* Turns the second argument of `logger.error(message, x)` and friends into
|
|
9
|
+
* log options. An `Error` becomes the entry's `error` (with its stack)
|
|
10
|
+
* instead of being read as metadata, where it has no enumerable fields and
|
|
11
|
+
* vanished without trace.
|
|
12
|
+
*/
|
|
13
|
+
export declare function levelOptions(metadata: LogOptions["metadata"] | undefined): LogOptions;
|
|
7
14
|
/**
|
|
8
15
|
* Level logging methods extracted from ZudojsLogger.
|
|
9
16
|
*/
|
|
@@ -2,9 +2,22 @@
|
|
|
2
2
|
* ZudojsLogger level methods.
|
|
3
3
|
*/
|
|
4
4
|
import { LoggerLevel, shouldLog, } from "../../../loggerLevel/loggerLevel.type.js";
|
|
5
|
-
import { LoggerConfigurationError } from "../../../loggerErrors/loggerError.base.js";
|
|
5
|
+
import { InvalidLoggerEntryError, LoggerConfigurationError, } from "../../../loggerErrors/loggerError.base.js";
|
|
6
|
+
import { toLoggerError } from "../../../loggerErrors/loggerError.helpers.js";
|
|
6
7
|
import { createEntry } from "./loggerCoreMethods.entry.js";
|
|
7
8
|
import { dispatchEntrySync } from "./loggerCoreMethods.dispatch.js";
|
|
9
|
+
/**
|
|
10
|
+
* Turns the second argument of `logger.error(message, x)` and friends into
|
|
11
|
+
* log options. An `Error` becomes the entry's `error` (with its stack)
|
|
12
|
+
* instead of being read as metadata, where it has no enumerable fields and
|
|
13
|
+
* vanished without trace.
|
|
14
|
+
*/
|
|
15
|
+
export function levelOptions(metadata) {
|
|
16
|
+
// The static type says metadata, but JavaScript callers (and code typed
|
|
17
|
+
// loosely) routinely pass the caught error here.
|
|
18
|
+
const value = metadata;
|
|
19
|
+
return value instanceof Error ? { error: value } : { metadata };
|
|
20
|
+
}
|
|
8
21
|
/**
|
|
9
22
|
* Level logging methods extracted from ZudojsLogger.
|
|
10
23
|
*/
|
|
@@ -17,7 +30,24 @@ export function logAtLevel(ctx, level, message, options = {}) {
|
|
|
17
30
|
if (typeof message !== "string") {
|
|
18
31
|
throw new LoggerConfigurationError("Logger message must be a string.");
|
|
19
32
|
}
|
|
20
|
-
|
|
33
|
+
// Entry construction reads caller-supplied metadata, including
|
|
34
|
+
// getters. A throwing accessor used to propagate straight out of
|
|
35
|
+
// logger.info(...) and abort the caller — and only when the level
|
|
36
|
+
// let the call through, so the same code was a silent no-op at one
|
|
37
|
+
// log level and a crash at another. The offending field becomes a
|
|
38
|
+
// marker and the failure is reported like every other infrastructure
|
|
39
|
+
// failure, AFTER the line has been dispatched.
|
|
40
|
+
const metadataFailures = [];
|
|
41
|
+
let entry;
|
|
42
|
+
try {
|
|
43
|
+
entry = createEntry(ctx.configuration, ctx.contextStorage, level, message, options, (key, error) => {
|
|
44
|
+
metadataFailures.push(new InvalidLoggerEntryError(`Failed to read log metadata field "${key}": ${toLoggerError(error).message}`, { cause: error }));
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
ctx.handleInfrastructureError(new InvalidLoggerEntryError(`Failed to build log entry: ${toLoggerError(error).message}`, { cause: error }));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
21
51
|
// Dispatch is asynchronous. It used to be fired and forgotten, so
|
|
22
52
|
// flush() and close() could return while entries were still in
|
|
23
53
|
// flight — messages were lost on process exit. Registering the
|
|
@@ -26,5 +56,8 @@ export function logAtLevel(ctx, level, message, options = {}) {
|
|
|
26
56
|
if (dispatch) {
|
|
27
57
|
ctx.trackDispatch(dispatch);
|
|
28
58
|
}
|
|
59
|
+
for (const failure of metadataFailures) {
|
|
60
|
+
ctx.handleInfrastructureError(failure);
|
|
61
|
+
}
|
|
29
62
|
}
|
|
30
63
|
//# sourceMappingURL=loggerCoreMethods.level.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ZudojsLogger lifecycle methods.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { type LoggerLevelLike } from "../../../loggerLevel/loggerLevel.type.js";
|
|
5
5
|
import type { ZudojsLoggerContext } from "../../core/loggerCore.core.js";
|
|
6
6
|
/**
|
|
7
|
-
* Sets the logger level.
|
|
7
|
+
* Sets the logger level from an enum value or a case-insensitive name.
|
|
8
8
|
*/
|
|
9
|
-
export declare function setLoggerLevel(ctx: ZudojsLoggerContext, level:
|
|
9
|
+
export declare function setLoggerLevel(ctx: ZudojsLoggerContext, level: LoggerLevelLike): void;
|
|
10
10
|
/**
|
|
11
11
|
* Enables the logger.
|
|
12
12
|
*/
|