@zudojs/logger 1.3.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 +55 -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 +18 -17
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.level.d.ts +7 -0
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.level.js +12 -0
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.lifecycle.d.ts +3 -3
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.lifecycle.js +8 -6
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.interfaces.d.ts +11 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.d.ts +7 -3
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.js +15 -13
- package/dist/loggerFactory/loggerFactory.core.d.ts +2 -2
- 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 +14 -0
- package/dist/loggerOptions/loggerOptions.type.d.ts +14 -3
- package/dist/loggerOptions/loggerOptions.type.js +7 -3
- 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.
|
|
@@ -164,10 +207,17 @@ tag of text output. Colour codes are emitted only around the fixed level
|
|
|
164
207
|
name, never around user-supplied text.
|
|
165
208
|
|
|
166
209
|
A formatter returns either a string or an object
|
|
167
|
-
(`LoggerFormattedOutput`). A string becomes the payload's `
|
|
168
|
-
object is merged OVER the
|
|
169
|
-
hands the transport its
|
|
170
|
-
`timestamp` and serialized
|
|
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.
|
|
171
221
|
|
|
172
222
|
## Use Cases
|
|
173
223
|
|
|
@@ -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,6 +4,7 @@
|
|
|
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 { toJsonLogLine } from "../../../loggerTransport/loggerTransportHelpers/loggerTransportHelpers.js";
|
|
7
8
|
import { LoggerFormatterError, LoggerTimeoutError, LoggerTransportError, } from "../../../loggerErrors/loggerError.base.js";
|
|
8
9
|
import { createLoggerFormatterError, createLoggerTransportError, } from "../../../loggerErrors/loggerError.helpers.js";
|
|
9
10
|
/**
|
|
@@ -60,16 +61,16 @@ async function withTransportTimeout(timeoutMs, transportName, operation) {
|
|
|
60
61
|
/**
|
|
61
62
|
* Builds the payload handed to a transport.
|
|
62
63
|
*
|
|
63
|
-
* `LoggerFormattedOutput` is `string | Record<string, unknown>`. A
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* and
|
|
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.
|
|
69
70
|
*/
|
|
70
71
|
function toTransportPayload(entry, formatted) {
|
|
71
72
|
if (typeof formatted === "string") {
|
|
72
|
-
return { ...entry,
|
|
73
|
+
return { ...entry, formatted };
|
|
73
74
|
}
|
|
74
75
|
if (formatted !== null &&
|
|
75
76
|
typeof formatted === "object" &&
|
|
@@ -77,6 +78,7 @@ function toTransportPayload(entry, formatted) {
|
|
|
77
78
|
return {
|
|
78
79
|
...entry,
|
|
79
80
|
...formatted,
|
|
81
|
+
formatted: toJsonLogLine(formatted),
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
return entry;
|
|
@@ -104,12 +106,12 @@ function toFormatterError(formatterName, error) {
|
|
|
104
106
|
/**
|
|
105
107
|
* Writes to a transport.
|
|
106
108
|
*/
|
|
107
|
-
async function writeTransport(configuration, transport,
|
|
109
|
+
async function writeTransport(configuration, transport, payload) {
|
|
108
110
|
const transportContext = {
|
|
109
111
|
loggerName: configuration.name,
|
|
110
112
|
environment: configuration.environment,
|
|
111
113
|
};
|
|
112
|
-
await writeLoggerTransport(transport.transport,
|
|
114
|
+
await writeLoggerTransport(transport.transport, payload, transportContext);
|
|
113
115
|
}
|
|
114
116
|
/**
|
|
115
117
|
* Formats an entry with the configured formatter.
|
|
@@ -132,12 +134,11 @@ function formatEntry(configuration, entry) {
|
|
|
132
134
|
* the transport directly lets a synchronous console/array transport
|
|
133
135
|
* complete inline, which is what `asynchronous: false` promises.
|
|
134
136
|
*/
|
|
135
|
-
function writeTransportMaybeSync(configuration, transport,
|
|
137
|
+
function writeTransportMaybeSync(configuration, transport, payload) {
|
|
136
138
|
const transportContext = {
|
|
137
139
|
loggerName: configuration.name,
|
|
138
140
|
environment: configuration.environment,
|
|
139
141
|
};
|
|
140
|
-
const payload = toTransportPayload(entry, formatted);
|
|
141
142
|
const target = transport.transport;
|
|
142
143
|
return typeof target === "function"
|
|
143
144
|
? target(payload, transportContext)
|
|
@@ -147,9 +148,9 @@ function writeTransportMaybeSync(configuration, transport, entry, formatted) {
|
|
|
147
148
|
* Dispatches an entry to the configured transports.
|
|
148
149
|
*/
|
|
149
150
|
export async function dispatchEntry(configuration, entry, handleError) {
|
|
150
|
-
let
|
|
151
|
+
let payload;
|
|
151
152
|
try {
|
|
152
|
-
|
|
153
|
+
payload = toTransportPayload(entry, formatEntry(configuration, entry));
|
|
153
154
|
}
|
|
154
155
|
catch (error) {
|
|
155
156
|
handleError(toFormatterError(resolveFormatterName(configuration), error));
|
|
@@ -166,7 +167,7 @@ export async function dispatchEntry(configuration, entry, handleError) {
|
|
|
166
167
|
if (!registered.enabled) {
|
|
167
168
|
continue;
|
|
168
169
|
}
|
|
169
|
-
await withTransportTimeout(configuration.transportTimeout, registered.name, writeTransport(configuration, registered,
|
|
170
|
+
await withTransportTimeout(configuration.transportTimeout, registered.name, writeTransport(configuration, registered, payload));
|
|
170
171
|
}
|
|
171
172
|
catch (error) {
|
|
172
173
|
handleError(toTransportError(transportName, error));
|
|
@@ -191,9 +192,9 @@ export function dispatchEntrySync(configuration, entry, handleError) {
|
|
|
191
192
|
// caller off the transport's critical path.
|
|
192
193
|
return Promise.resolve().then(() => dispatchEntry(configuration, entry, handleError));
|
|
193
194
|
}
|
|
194
|
-
let
|
|
195
|
+
let payload;
|
|
195
196
|
try {
|
|
196
|
-
|
|
197
|
+
payload = toTransportPayload(entry, formatEntry(configuration, entry));
|
|
197
198
|
}
|
|
198
199
|
catch (error) {
|
|
199
200
|
handleError(toFormatterError(resolveFormatterName(configuration), error));
|
|
@@ -211,7 +212,7 @@ export function dispatchEntrySync(configuration, entry, handleError) {
|
|
|
211
212
|
if (!registered.enabled) {
|
|
212
213
|
continue;
|
|
213
214
|
}
|
|
214
|
-
const result = writeTransportMaybeSync(configuration, registered,
|
|
215
|
+
const result = writeTransportMaybeSync(configuration, registered, payload);
|
|
215
216
|
if (result instanceof Promise) {
|
|
216
217
|
pending.push(withTransportTimeout(configuration.transportTimeout, registered.name, result).catch((error) => {
|
|
217
218
|
handleError(toTransportError(registered.name, error));
|
|
@@ -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
|
*/
|
|
@@ -6,6 +6,18 @@ import { InvalidLoggerEntryError, LoggerConfigurationError, } from "../../../log
|
|
|
6
6
|
import { toLoggerError } from "../../../loggerErrors/loggerError.helpers.js";
|
|
7
7
|
import { createEntry } from "./loggerCoreMethods.entry.js";
|
|
8
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
|
+
}
|
|
9
21
|
/**
|
|
10
22
|
* Level logging methods extracted from ZudojsLogger.
|
|
11
23
|
*/
|
|
@@ -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
|
*/
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ZudojsLogger lifecycle methods.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { resolveLoggerLevel, } from "../../../loggerLevel/loggerLevel.type.js";
|
|
5
5
|
import { createLoggerTransport } from "../../../loggerTransport/loggerTransport.core.js";
|
|
6
6
|
import { isLoggerTransport } from "../../../loggerTransport/loggerTransportGuard.js";
|
|
7
7
|
import { LoggerConfigurationError } from "../../../loggerErrors/loggerError.base.js";
|
|
8
8
|
import { throwCollectedFailures } from "../../../loggerErrors/loggerError.helpers.js";
|
|
9
9
|
/**
|
|
10
|
-
* Sets the logger level.
|
|
10
|
+
* Sets the logger level from an enum value or a case-insensitive name.
|
|
11
11
|
*/
|
|
12
12
|
export function setLoggerLevel(ctx, level) {
|
|
13
13
|
ctx.assertActive();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
let resolved;
|
|
15
|
+
try {
|
|
16
|
+
resolved = resolveLoggerLevel(level);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
17
19
|
throw new LoggerConfigurationError(`Invalid logger level: ${String(level)}.`);
|
|
18
20
|
}
|
|
19
21
|
ctx.assertMutable();
|
|
20
22
|
ctx.updateConfiguration({
|
|
21
23
|
...ctx.configuration,
|
|
22
|
-
level,
|
|
24
|
+
level: resolved,
|
|
23
25
|
});
|
|
24
26
|
}
|
|
25
27
|
/**
|
|
@@ -20,9 +20,19 @@ export interface LoggerEntry {
|
|
|
20
20
|
*/
|
|
21
21
|
readonly levelName: LoggerLevelName;
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* The message as the caller logged it. A transport receives it unchanged;
|
|
24
|
+
* the formatter's rendering of the whole record is in `formatted`.
|
|
24
25
|
*/
|
|
25
26
|
readonly message: string;
|
|
27
|
+
/**
|
|
28
|
+
* The record rendered as one line by the logger's formatter: the string a
|
|
29
|
+
* text or JSON formatter returned, or the JSON line of the record an
|
|
30
|
+
* object formatter (`createStructuredLoggerFormatter`) returned. Set on
|
|
31
|
+
* entries a logger hands to its transports. Line-oriented transports
|
|
32
|
+
* print `entry.formatted ?? entry.message`; `message` is always the raw
|
|
33
|
+
* message the caller logged.
|
|
34
|
+
*/
|
|
35
|
+
readonly formatted?: string;
|
|
26
36
|
/**
|
|
27
37
|
* Structured metadata.
|
|
28
38
|
*/
|
|
@@ -3,19 +3,23 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* Serializes an error-like object into a plain object.
|
|
6
|
+
*
|
|
7
|
+
* @param includeStack - `false` leaves the stack out (its frames carry
|
|
8
|
+
* absolute file paths). Defaults to `true`.
|
|
6
9
|
*/
|
|
7
10
|
export declare function serializeLoggerError(error: {
|
|
8
11
|
name?: string;
|
|
9
12
|
message: string;
|
|
10
13
|
stack?: string;
|
|
11
|
-
}): Record<string, unknown>;
|
|
14
|
+
}, includeStack?: boolean): Record<string, unknown>;
|
|
12
15
|
/**
|
|
13
16
|
* Converts arbitrary values into safer serializable values.
|
|
14
17
|
*
|
|
15
18
|
* `seen` tracks the ANCESTOR PATH only, so only a genuine back-edge
|
|
16
19
|
* becomes "[Circular]"; `Map` and `Set` keep their contents; and a
|
|
17
20
|
* property whose getter throws becomes "[Unreadable]" rather than
|
|
18
|
-
* taking the whole log line down.
|
|
21
|
+
* taking the whole log line down. `includeErrorStack: false` leaves the
|
|
22
|
+
* stack out of every Error found in the value.
|
|
19
23
|
*/
|
|
20
|
-
export declare function serializeLoggerValue(value: unknown, seen?: WeakSet<object
|
|
24
|
+
export declare function serializeLoggerValue(value: unknown, seen?: WeakSet<object>, includeErrorStack?: boolean): unknown;
|
|
21
25
|
//# sourceMappingURL=loggerEntryHelpers.valueSerialize.d.ts.map
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
import { LOGGER_UNREADABLE_TOKEN } from "./loggerEntryHelpers.sanitize.js";
|
|
5
5
|
/**
|
|
6
6
|
* Serializes an error-like object into a plain object.
|
|
7
|
+
*
|
|
8
|
+
* @param includeStack - `false` leaves the stack out (its frames carry
|
|
9
|
+
* absolute file paths). Defaults to `true`.
|
|
7
10
|
*/
|
|
8
|
-
export function serializeLoggerError(error) {
|
|
9
|
-
return
|
|
10
|
-
name: error.name,
|
|
11
|
-
message: error.message
|
|
12
|
-
stack: error.stack,
|
|
13
|
-
};
|
|
11
|
+
export function serializeLoggerError(error, includeStack = true) {
|
|
12
|
+
return includeStack
|
|
13
|
+
? { name: error.name, message: error.message, stack: error.stack }
|
|
14
|
+
: { name: error.name, message: error.message };
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* Converts arbitrary values into safer serializable values.
|
|
@@ -18,9 +19,10 @@ export function serializeLoggerError(error) {
|
|
|
18
19
|
* `seen` tracks the ANCESTOR PATH only, so only a genuine back-edge
|
|
19
20
|
* becomes "[Circular]"; `Map` and `Set` keep their contents; and a
|
|
20
21
|
* property whose getter throws becomes "[Unreadable]" rather than
|
|
21
|
-
* taking the whole log line down.
|
|
22
|
+
* taking the whole log line down. `includeErrorStack: false` leaves the
|
|
23
|
+
* stack out of every Error found in the value.
|
|
22
24
|
*/
|
|
23
|
-
export function serializeLoggerValue(value, seen = new WeakSet()) {
|
|
25
|
+
export function serializeLoggerValue(value, seen = new WeakSet(), includeErrorStack = true) {
|
|
24
26
|
if (value === null ||
|
|
25
27
|
value === undefined ||
|
|
26
28
|
typeof value === "string" ||
|
|
@@ -35,7 +37,7 @@ export function serializeLoggerValue(value, seen = new WeakSet()) {
|
|
|
35
37
|
return value.toISOString();
|
|
36
38
|
}
|
|
37
39
|
if (value instanceof Error) {
|
|
38
|
-
return serializeLoggerError(value);
|
|
40
|
+
return serializeLoggerError(value, includeErrorStack);
|
|
39
41
|
}
|
|
40
42
|
if (typeof value === "function") {
|
|
41
43
|
return `[Function ${value.name || "anonymous"}]`;
|
|
@@ -52,10 +54,10 @@ export function serializeLoggerValue(value, seen = new WeakSet()) {
|
|
|
52
54
|
seen.add(value);
|
|
53
55
|
try {
|
|
54
56
|
if (Array.isArray(value)) {
|
|
55
|
-
return value.map((item) => serializeLoggerValue(item, seen));
|
|
57
|
+
return value.map((item) => serializeLoggerValue(item, seen, includeErrorStack));
|
|
56
58
|
}
|
|
57
59
|
if (value instanceof Set) {
|
|
58
|
-
return Array.from(value, (item) => serializeLoggerValue(item, seen));
|
|
60
|
+
return Array.from(value, (item) => serializeLoggerValue(item, seen, includeErrorStack));
|
|
59
61
|
}
|
|
60
62
|
const result = {};
|
|
61
63
|
// defineProperty, never assignment: a "__proto__" key from an
|
|
@@ -71,7 +73,7 @@ export function serializeLoggerValue(value, seen = new WeakSet()) {
|
|
|
71
73
|
};
|
|
72
74
|
if (value instanceof Map) {
|
|
73
75
|
for (const [key, item] of value.entries()) {
|
|
74
|
-
define(typeof key === "string" ? key : String(key), serializeLoggerValue(item, seen));
|
|
76
|
+
define(typeof key === "string" ? key : String(key), serializeLoggerValue(item, seen, includeErrorStack));
|
|
75
77
|
}
|
|
76
78
|
return result;
|
|
77
79
|
}
|
|
@@ -84,7 +86,7 @@ export function serializeLoggerValue(value, seen = new WeakSet()) {
|
|
|
84
86
|
define(key, LOGGER_UNREADABLE_TOKEN);
|
|
85
87
|
continue;
|
|
86
88
|
}
|
|
87
|
-
define(key, serializeLoggerValue(item, seen));
|
|
89
|
+
define(key, serializeLoggerValue(item, seen, includeErrorStack));
|
|
88
90
|
}
|
|
89
91
|
return result;
|
|
90
92
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Logger } from "../loggerCore/core/loggerCore.type.js";
|
|
2
|
-
import type { LoggerOptions,
|
|
2
|
+
import type { LoggerOptions, ChildLoggerOptionsInput } from "../loggerOptions/loggerOptions.type.js";
|
|
3
3
|
/**
|
|
4
4
|
* Factory responsible for creating and managing Zudojs loggers.
|
|
5
5
|
*
|
|
@@ -29,7 +29,7 @@ export declare class LoggerFactory {
|
|
|
29
29
|
/** Gets an existing logger or creates it. */
|
|
30
30
|
getOrCreate(name: string, options?: LoggerOptions): Logger;
|
|
31
31
|
/** Creates a child logger from an existing logger. */
|
|
32
|
-
child(parent: Logger, options?:
|
|
32
|
+
child(parent: Logger, options?: ChildLoggerOptionsInput): Logger;
|
|
33
33
|
/**
|
|
34
34
|
* Removes a logger from the factory registry.
|
|
35
35
|
*
|
package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.d.ts
CHANGED
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* Formats metadata as key=value pairs.
|
|
6
|
+
*
|
|
7
|
+
* @param includeStackTrace - `false` leaves the stack out of any Error in
|
|
8
|
+
* the metadata, as the text formatter's option of the same name promises.
|
|
6
9
|
*/
|
|
7
|
-
export declare function formatMetadata(metadata: Record<string, unknown>, separator: string): string;
|
|
10
|
+
export declare function formatMetadata(metadata: Record<string, unknown>, separator: string, includeStackTrace?: boolean): string;
|
|
8
11
|
/**
|
|
9
12
|
* Formats an arbitrary metadata value.
|
|
10
13
|
*/
|
|
11
|
-
export declare function formatValue(value: unknown): string;
|
|
14
|
+
export declare function formatValue(value: unknown, includeStackTrace?: boolean): string;
|
|
12
15
|
/**
|
|
13
16
|
* Formats an Error.
|
|
14
17
|
*
|
package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.js
CHANGED
|
@@ -5,19 +5,22 @@ import { serializeLoggerError, serializeLoggerValue, } from "../../loggerEntry/l
|
|
|
5
5
|
import { escapeLogText } from "../../loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.js";
|
|
6
6
|
/**
|
|
7
7
|
* Formats metadata as key=value pairs.
|
|
8
|
+
*
|
|
9
|
+
* @param includeStackTrace - `false` leaves the stack out of any Error in
|
|
10
|
+
* the metadata, as the text formatter's option of the same name promises.
|
|
8
11
|
*/
|
|
9
|
-
export function formatMetadata(metadata, separator) {
|
|
12
|
+
export function formatMetadata(metadata, separator, includeStackTrace = true) {
|
|
10
13
|
return (Object.entries(metadata)
|
|
11
14
|
.filter(([, value]) => value !== undefined)
|
|
12
15
|
// Metadata KEYS are as attacker-influenceable as values (a header
|
|
13
16
|
// name, a form field) and were previously interpolated raw.
|
|
14
|
-
.map(([key, value]) => `${escapeLogText(key)}=${formatValue(value)}`)
|
|
17
|
+
.map(([key, value]) => `${escapeLogText(key)}=${formatValue(value, includeStackTrace)}`)
|
|
15
18
|
.join(separator));
|
|
16
19
|
}
|
|
17
20
|
/**
|
|
18
21
|
* Formats an arbitrary metadata value.
|
|
19
22
|
*/
|
|
20
|
-
export function formatValue(value) {
|
|
23
|
+
export function formatValue(value, includeStackTrace = true) {
|
|
21
24
|
if (value === null) {
|
|
22
25
|
return "null";
|
|
23
26
|
}
|
|
@@ -31,7 +34,8 @@ export function formatValue(value) {
|
|
|
31
34
|
return escapeLogText(value);
|
|
32
35
|
}
|
|
33
36
|
if (typeof value === "object") {
|
|
34
|
-
|
|
37
|
+
const serialized = serializeLoggerValue(value, new WeakSet(), includeStackTrace);
|
|
38
|
+
return escapeLogText(JSON.stringify(serialized));
|
|
35
39
|
}
|
|
36
40
|
return escapeLogText(String(value));
|
|
37
41
|
}
|
|
@@ -79,7 +83,10 @@ export function formatError(error, includeStackTrace) {
|
|
|
79
83
|
}
|
|
80
84
|
return `\n${lines.join("\n")}`;
|
|
81
85
|
}
|
|
82
|
-
|
|
86
|
+
// Name and message only: the fallback used to serialize the stack as
|
|
87
|
+
// well, so `includeStackTrace: false` still printed every frame (and the
|
|
88
|
+
// absolute paths in them) inside the JSON.
|
|
89
|
+
const serialized = serializeLoggerError(error, false);
|
|
83
90
|
return `error=${escapeLogText(JSON.stringify(serialized))}`;
|
|
84
91
|
}
|
|
85
92
|
//# sourceMappingURL=loggerFormatterFormatters.metadata.js.map
|
|
@@ -65,12 +65,16 @@ export function createTextLoggerFormatter(options = {}) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
if (includeMetadata && Object.keys(entry.metadata).length > 0) {
|
|
68
|
-
parts.push(formatMetadata(entry.metadata, metadataSeparator));
|
|
68
|
+
parts.push(formatMetadata(entry.metadata, metadataSeparator, includeStackTrace));
|
|
69
69
|
}
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
const line = parts.join(" ");
|
|
71
|
+
if (!entry.error) {
|
|
72
|
+
return line;
|
|
72
73
|
}
|
|
73
|
-
|
|
74
|
+
// A stack starts on its own line; joining it with " " left a trailing
|
|
75
|
+
// space after the message.
|
|
76
|
+
const error = formatError(entry.error, includeStackTrace);
|
|
77
|
+
return error.startsWith("\n") ? `${line}${error}` : `${line} ${error}`;
|
|
74
78
|
}, { name: options.name ?? "text" });
|
|
75
79
|
}
|
|
76
80
|
//# sourceMappingURL=loggerFormatterFormatters.text.js.map
|
|
@@ -14,10 +14,23 @@ export declare enum LoggerLevel {
|
|
|
14
14
|
}
|
|
15
15
|
/** String representation of supported logger levels. */
|
|
16
16
|
export type LoggerLevelName = "fatal" | "error" | "warn" | "info" | "debug" | "trace";
|
|
17
|
+
/**
|
|
18
|
+
* A level as configuration accepts it: the enum value, or its name in any
|
|
19
|
+
* case (`"error"`, `"ERROR"`). `"warning"` and `"information"` are accepted
|
|
20
|
+
* at runtime as aliases of `"warn"` and `"info"`.
|
|
21
|
+
*/
|
|
22
|
+
export type LoggerLevelLike = LoggerLevel | LoggerLevelName | Uppercase<LoggerLevelName>;
|
|
17
23
|
/** Converts a logger level into its canonical name. */
|
|
18
24
|
export declare function loggerLevelToName(level: LoggerLevel): LoggerLevelName;
|
|
19
25
|
/** Converts a logger level name into its enum value. */
|
|
20
26
|
export declare function loggerLevelFromName(name: LoggerLevelName | string): LoggerLevel;
|
|
27
|
+
/**
|
|
28
|
+
* Resolves a configured level (enum value or case-insensitive name) to its
|
|
29
|
+
* enum value.
|
|
30
|
+
*
|
|
31
|
+
* @throws InvalidLoggerLevelError when the value is neither.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveLoggerLevel(level: LoggerLevelLike): LoggerLevel;
|
|
21
34
|
/** Checks whether a value is a valid LoggerLevel. */
|
|
22
35
|
export declare function isLoggerLevel(value: unknown): value is LoggerLevel;
|
|
23
36
|
/** Checks whether a value is a valid logger level name. */
|
|
@@ -54,6 +54,20 @@ export function loggerLevelFromName(name) {
|
|
|
54
54
|
throw new InvalidLoggerLevelError(name);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolves a configured level (enum value or case-insensitive name) to its
|
|
59
|
+
* enum value.
|
|
60
|
+
*
|
|
61
|
+
* @throws InvalidLoggerLevelError when the value is neither.
|
|
62
|
+
*/
|
|
63
|
+
export function resolveLoggerLevel(level) {
|
|
64
|
+
const value = level;
|
|
65
|
+
if (isLoggerLevel(value))
|
|
66
|
+
return value;
|
|
67
|
+
if (typeof value === "string")
|
|
68
|
+
return loggerLevelFromName(value.trim());
|
|
69
|
+
throw new InvalidLoggerLevelError(value);
|
|
70
|
+
}
|
|
57
71
|
/** Checks whether a value is a valid LoggerLevel. */
|
|
58
72
|
export function isLoggerLevel(value) {
|
|
59
73
|
return (typeof value === "number" &&
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LoggerLevel } from "../loggerLevel/loggerLevel.type.js";
|
|
1
|
+
import { LoggerLevel, type LoggerLevelLike } from "../loggerLevel/loggerLevel.type.js";
|
|
2
2
|
import type { LoggerContextData } from "../loggerContext/loggerContext.core.js";
|
|
3
3
|
import type { LoggerFormatterLike } from "../loggerFormatter/loggerFormatter.type.js";
|
|
4
4
|
import type { LoggerTransportLike } from "../loggerTransport/loggerTransport.type.js";
|
|
@@ -6,7 +6,8 @@ import type { LoggerRedactionOptions } from "../loggerEntry/loggerEntryHelpers/l
|
|
|
6
6
|
/** Options used to configure a Zudojs logger. */
|
|
7
7
|
export interface LoggerOptions {
|
|
8
8
|
readonly name?: string;
|
|
9
|
-
|
|
9
|
+
/** Threshold: `LoggerLevel.WARN`, or a name such as `"warn"` / `"WARN"`. */
|
|
10
|
+
readonly level?: LoggerLevelLike;
|
|
10
11
|
readonly environment?: string;
|
|
11
12
|
readonly metadata?: LoggerContextData;
|
|
12
13
|
readonly formatter?: LoggerFormatterLike;
|
|
@@ -33,6 +34,16 @@ export interface ChildLoggerOptions {
|
|
|
33
34
|
readonly metadata?: LoggerContextData;
|
|
34
35
|
readonly level?: LoggerLevel;
|
|
35
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* What `Logger.child()` accepts: `ChildLoggerOptions` whose `level` may also
|
|
39
|
+
* be a name (`"debug"`, `"DEBUG"`). `ChildLoggerOptions` itself keeps the
|
|
40
|
+
* enum, so a custom logger that reads `options.level` still compiles; one
|
|
41
|
+
* that may be handed a name should pass it through `resolveLoggerLevel()`.
|
|
42
|
+
*/
|
|
43
|
+
export interface ChildLoggerOptionsInput extends Omit<ChildLoggerOptions, "level"> {
|
|
44
|
+
/** Threshold: `LoggerLevel.DEBUG`, or a name such as `"debug"`. */
|
|
45
|
+
readonly level?: LoggerLevelLike;
|
|
46
|
+
}
|
|
36
47
|
/** Options for a single log operation. */
|
|
37
48
|
export interface LogOptions {
|
|
38
49
|
readonly metadata?: LoggerContextData;
|
|
@@ -74,5 +85,5 @@ export declare function resolveLoggerOptions(options?: LoggerOptions): LoggerCon
|
|
|
74
85
|
/** Merges two logger option objects. Values from `override` take precedence. */
|
|
75
86
|
export declare function mergeLoggerOptions(base: LoggerOptions, override: LoggerOptions): LoggerOptions;
|
|
76
87
|
/** Creates options for a child logger. */
|
|
77
|
-
export declare function createChildLoggerOptions(parent: LoggerConfiguration, options?:
|
|
88
|
+
export declare function createChildLoggerOptions(parent: LoggerConfiguration, options?: ChildLoggerOptionsInput): LoggerOptions;
|
|
78
89
|
//# sourceMappingURL=loggerOptions.type.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LoggerLevel } from "../loggerLevel/loggerLevel.type.js";
|
|
1
|
+
import { LoggerLevel, resolveLoggerLevel, } from "../loggerLevel/loggerLevel.type.js";
|
|
2
2
|
/** Default logger configuration values. */
|
|
3
3
|
export const DEFAULT_LOGGER_OPTIONS = {
|
|
4
4
|
enabled: true,
|
|
@@ -29,7 +29,9 @@ export function resolveLoggerOptions(options = {}) {
|
|
|
29
29
|
validateLoggerOptions(options);
|
|
30
30
|
return Object.freeze({
|
|
31
31
|
name: options.name ?? "zudojs",
|
|
32
|
-
level: options.level
|
|
32
|
+
level: options.level === undefined
|
|
33
|
+
? LoggerLevel.INFO
|
|
34
|
+
: resolveLoggerLevel(options.level),
|
|
33
35
|
environment: options.environment,
|
|
34
36
|
metadata: Object.freeze({ ...(options.metadata ?? {}) }),
|
|
35
37
|
formatter: options.formatter ?? "text",
|
|
@@ -57,7 +59,9 @@ export function mergeLoggerOptions(base, override) {
|
|
|
57
59
|
export function createChildLoggerOptions(parent, options = {}) {
|
|
58
60
|
return {
|
|
59
61
|
name: options.name ?? parent.name,
|
|
60
|
-
level: options.level
|
|
62
|
+
level: options.level === undefined
|
|
63
|
+
? parent.level
|
|
64
|
+
: resolveLoggerLevel(options.level),
|
|
61
65
|
environment: parent.environment,
|
|
62
66
|
metadata: { ...parent.metadata, ...(options.metadata ?? {}) },
|
|
63
67
|
formatter: parent.formatter,
|
|
@@ -5,8 +5,9 @@ import type { LoggerTransportOptions, RegisteredLoggerTransport } from "../logge
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates a simple console transport.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* Node.js-specific APIs.
|
|
8
|
+
* Prints one line per record through the standard console methods (no
|
|
9
|
+
* Node.js-specific APIs): `entry.formatted` when the logger's formatter
|
|
10
|
+
* produced it, otherwise the entry as a single JSON line.
|
|
10
11
|
*/
|
|
11
12
|
export declare function createConsoleLoggerTransport(options?: LoggerTransportOptions): RegisteredLoggerTransport;
|
|
12
13
|
//# sourceMappingURL=loggerTransportConsole.core.d.ts.map
|
|
@@ -2,19 +2,24 @@
|
|
|
2
2
|
* Console logger transport.
|
|
3
3
|
*/
|
|
4
4
|
import { createLoggerTransport } from "../loggerTransport.core.js";
|
|
5
|
-
import {
|
|
5
|
+
import { formatTransportLine } from "../loggerTransportHelpers/loggerTransportHelpers.js";
|
|
6
6
|
/**
|
|
7
7
|
* Creates a simple console transport.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* Node.js-specific APIs.
|
|
9
|
+
* Prints one line per record through the standard console methods (no
|
|
10
|
+
* Node.js-specific APIs): `entry.formatted` when the logger's formatter
|
|
11
|
+
* produced it, otherwise the entry as a single JSON line.
|
|
11
12
|
*/
|
|
12
13
|
export function createConsoleLoggerTransport(options = {}) {
|
|
13
14
|
const transport = {
|
|
14
15
|
name: options.name ?? "console",
|
|
15
16
|
enabled: options.enabled ?? true,
|
|
16
17
|
write(entry) {
|
|
17
|
-
|
|
18
|
+
// One line per record: the formatter's line (text or JSON), or the
|
|
19
|
+
// entry as JSON. Printing the record object showed the timestamp and
|
|
20
|
+
// level twice beside a text line, and spread a structured record over
|
|
21
|
+
// several lines of console output.
|
|
22
|
+
const payload = formatTransportLine(entry);
|
|
18
23
|
switch (entry.levelName) {
|
|
19
24
|
case "fatal":
|
|
20
25
|
case "error":
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Transport helper functions.
|
|
5
5
|
*/
|
|
6
|
-
export { serializeTransportEntry, closeLoggerTransport, flushLoggerTransport, } from "./loggerTransportHelpers.js";
|
|
6
|
+
export { serializeTransportEntry, toJsonLogLine, formatTransportLine, closeLoggerTransport, flushLoggerTransport, } from "./loggerTransportHelpers.js";
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Transport helper functions.
|
|
5
5
|
*/
|
|
6
|
-
export { serializeTransportEntry, closeLoggerTransport, flushLoggerTransport, } from "./loggerTransportHelpers.js";
|
|
6
|
+
export { serializeTransportEntry, toJsonLogLine, formatTransportLine, closeLoggerTransport, flushLoggerTransport, } from "./loggerTransportHelpers.js";
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -7,6 +7,21 @@ import type { LoggerTransportLike } from "../loggerTransport.type.js";
|
|
|
7
7
|
* Converts a LoggerEntry into a console-friendly object.
|
|
8
8
|
*/
|
|
9
9
|
export declare function serializeTransportEntry(entry: LoggerEntry): Record<string, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Renders a record as one line of JSON.
|
|
12
|
+
*
|
|
13
|
+
* Values go through `serializeLoggerValue` first, so a cycle becomes
|
|
14
|
+
* `"[Circular]"`, a BigInt its decimal string and an Error its name,
|
|
15
|
+
* message and stack. `JSON.stringify` escapes `\n`; U+2028 and U+2029,
|
|
16
|
+
* which it leaves raw and some viewers break lines on, are escaped too.
|
|
17
|
+
*/
|
|
18
|
+
export declare function toJsonLogLine(record: unknown): string;
|
|
19
|
+
/**
|
|
20
|
+
* The text a line-oriented transport (console, file, stream) prints for an
|
|
21
|
+
* entry: the formatter's line when there is one, otherwise the entry as a
|
|
22
|
+
* single JSON line.
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatTransportLine(entry: LoggerEntry): string;
|
|
10
25
|
/**
|
|
11
26
|
* Safely closes a transport.
|
|
12
27
|
*/
|
|
@@ -42,6 +42,28 @@ export function serializeTransportEntry(entry) {
|
|
|
42
42
|
: {}),
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Renders a record as one line of JSON.
|
|
47
|
+
*
|
|
48
|
+
* Values go through `serializeLoggerValue` first, so a cycle becomes
|
|
49
|
+
* `"[Circular]"`, a BigInt its decimal string and an Error its name,
|
|
50
|
+
* message and stack. `JSON.stringify` escapes `\n`; U+2028 and U+2029,
|
|
51
|
+
* which it leaves raw and some viewers break lines on, are escaped too.
|
|
52
|
+
*/
|
|
53
|
+
export function toJsonLogLine(record) {
|
|
54
|
+
const json = JSON.stringify(serializeLoggerValue(record)) ?? "null";
|
|
55
|
+
return json.replace(/\u2028/gu, "\\u2028").replace(/\u2029/gu, "\\u2029");
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The text a line-oriented transport (console, file, stream) prints for an
|
|
59
|
+
* entry: the formatter's line when there is one, otherwise the entry as a
|
|
60
|
+
* single JSON line.
|
|
61
|
+
*/
|
|
62
|
+
export function formatTransportLine(entry) {
|
|
63
|
+
return typeof entry.formatted === "string"
|
|
64
|
+
? entry.formatted
|
|
65
|
+
: toJsonLogLine(serializeTransportEntry(entry));
|
|
66
|
+
}
|
|
45
67
|
/**
|
|
46
68
|
* Safely closes a transport.
|
|
47
69
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/logger",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Structured logging with transports, log levels, and context propagation for Zudojs applications.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"node": ">=24.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@zudojs/errors": "1.
|
|
31
|
+
"@zudojs/errors": "1.3.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"typescript": "7.0.2",
|
|
35
|
-
"vitest": "^
|
|
35
|
+
"vitest": "^5.0.1"
|
|
36
36
|
},
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"structured-logs",
|
|
44
44
|
"transports"
|
|
45
45
|
],
|
|
46
|
-
"homepage": "https://
|
|
46
|
+
"homepage": "https://zudojs.oyinlola.site/docs/packages-logger",
|
|
47
47
|
"bugs": {
|
|
48
48
|
"url": "https://github.com/oyinlola-tech/zudo/issues"
|
|
49
49
|
},
|