@zudojs/logger 0.1.0 → 1.1.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/LICENSE +21 -0
- package/README.md +98 -8
- package/dist/loggerCore/core/loggerCore.context.d.ts +9 -2
- package/dist/loggerCore/core/loggerCore.context.js +12 -6
- package/dist/loggerCore/core/loggerCore.core.d.ts +10 -0
- package/dist/loggerCore/core/loggerCore.core.js +52 -1
- package/dist/loggerCore/helpers/loggerCore.helper.d.ts +7 -2
- package/dist/loggerCore/helpers/loggerCore.helper.js +10 -9
- 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.js +3 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.dispatch.d.ts +11 -0
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.dispatch.js +121 -11
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.entry.js +18 -2
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.level.js +9 -2
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.lifecycle.js +33 -0
- package/dist/loggerEntry/loggerEntry.core.js +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/index.d.ts +2 -0
- package/dist/loggerEntry/loggerEntryHelpers/index.js +1 -0
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.d.ts +69 -0
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.js +113 -0
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.serialize.d.ts +5 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.serialize.js +9 -5
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.js +9 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.context.js +15 -3
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.js +3 -2
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.json.js +19 -3
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.js +14 -6
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.text.js +31 -4
- package/dist/loggerOptions/loggerOptions.type.d.ts +12 -1
- package/dist/loggerOptions/loggerOptions.type.js +4 -1
- package/dist/loggerTransport/loggerTransportComposite/loggerTransportComposite.buffered.js +4 -0
- package/dist/loggerTransport/loggerTransportHelpers/loggerTransportHelpers.js +4 -3
- package/package.json +23 -12
- package/dist/.tsbuildinfo +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/loggerContext/index.d.ts.map +0 -1
- package/dist/loggerContext/index.js.map +0 -1
- package/dist/loggerContext/loggerContext.core.d.ts.map +0 -1
- package/dist/loggerContext/loggerContext.core.js.map +0 -1
- package/dist/loggerContext/loggerContext.type.d.ts.map +0 -1
- package/dist/loggerContext/loggerContext.type.js.map +0 -1
- package/dist/loggerContext/loggerContextCreate.d.ts.map +0 -1
- package/dist/loggerContext/loggerContextCreate.js.map +0 -1
- package/dist/loggerContext/loggerContextSerialize.d.ts.map +0 -1
- package/dist/loggerContext/loggerContextSerialize.js.map +0 -1
- package/dist/loggerContext/loggerContextStorage.d.ts.map +0 -1
- package/dist/loggerContext/loggerContextStorage.js.map +0 -1
- package/dist/loggerCore/core/index.d.ts.map +0 -1
- package/dist/loggerCore/core/index.js.map +0 -1
- package/dist/loggerCore/core/loggerCore.context.d.ts.map +0 -1
- package/dist/loggerCore/core/loggerCore.context.js.map +0 -1
- package/dist/loggerCore/core/loggerCore.core.d.ts.map +0 -1
- package/dist/loggerCore/core/loggerCore.core.js.map +0 -1
- package/dist/loggerCore/core/loggerCore.type.d.ts.map +0 -1
- package/dist/loggerCore/core/loggerCore.type.js.map +0 -1
- package/dist/loggerCore/helpers/index.d.ts.map +0 -1
- package/dist/loggerCore/helpers/index.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCore.helper.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCore.helper.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreHelpers.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreHelpers.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/index.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/index.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.child.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.child.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.dispatch.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.dispatch.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.entry.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.entry.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.level.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.level.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.lifecycle.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.lifecycle.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods.logLevels.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods.logLevels.js.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods.loggerProps.d.ts.map +0 -1
- package/dist/loggerCore/helpers/loggerCoreMethods.loggerProps.js.map +0 -1
- package/dist/loggerCore/index.d.ts.map +0 -1
- package/dist/loggerCore/index.js.map +0 -1
- package/dist/loggerEntry/index.d.ts.map +0 -1
- package/dist/loggerEntry/index.js.map +0 -1
- package/dist/loggerEntry/loggerEntry.core.d.ts.map +0 -1
- package/dist/loggerEntry/loggerEntry.core.js.map +0 -1
- package/dist/loggerEntry/loggerEntry.type.d.ts.map +0 -1
- package/dist/loggerEntry/loggerEntry.type.js.map +0 -1
- package/dist/loggerEntry/loggerEntryCreate.d.ts.map +0 -1
- package/dist/loggerEntry/loggerEntryCreate.js.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/index.d.ts.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/index.js.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.interfaces.d.ts.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.interfaces.js.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.serialize.d.ts.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.serialize.js.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.types.d.ts.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.types.js.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.d.ts.map +0 -1
- package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.js.map +0 -1
- package/dist/loggerEntry/loggerEntrySerialize.d.ts.map +0 -1
- package/dist/loggerEntry/loggerEntrySerialize.js.map +0 -1
- package/dist/loggerErrors/index.d.ts.map +0 -1
- package/dist/loggerErrors/index.js.map +0 -1
- package/dist/loggerErrors/loggerError.base.d.ts.map +0 -1
- package/dist/loggerErrors/loggerError.base.js.map +0 -1
- package/dist/loggerErrors/loggerError.helpers.d.ts.map +0 -1
- package/dist/loggerErrors/loggerError.helpers.js.map +0 -1
- package/dist/loggerFactory/index.d.ts.map +0 -1
- package/dist/loggerFactory/index.js.map +0 -1
- package/dist/loggerFactory/loggerFactory.core.d.ts.map +0 -1
- package/dist/loggerFactory/loggerFactory.core.js.map +0 -1
- package/dist/loggerFormatter/index.d.ts.map +0 -1
- package/dist/loggerFormatter/index.js.map +0 -1
- package/dist/loggerFormatter/loggerFormatter.core.d.ts.map +0 -1
- package/dist/loggerFormatter/loggerFormatter.core.js.map +0 -1
- package/dist/loggerFormatter/loggerFormatter.type.d.ts.map +0 -1
- package/dist/loggerFormatter/loggerFormatter.type.js.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/index.d.ts.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/index.js.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.context.d.ts.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.context.js.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.d.ts.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.js.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.json.d.ts.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.json.js.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.d.ts.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.js.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.text.d.ts.map +0 -1
- package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.text.js.map +0 -1
- package/dist/loggerFormatter/loggerFormatterGuard.d.ts.map +0 -1
- package/dist/loggerFormatter/loggerFormatterGuard.js.map +0 -1
- package/dist/loggerLevel/index.d.ts.map +0 -1
- package/dist/loggerLevel/index.js.map +0 -1
- package/dist/loggerLevel/loggerLevel.type.d.ts.map +0 -1
- package/dist/loggerLevel/loggerLevel.type.js.map +0 -1
- package/dist/loggerManager/index.d.ts.map +0 -1
- package/dist/loggerManager/index.js.map +0 -1
- package/dist/loggerManager/loggerManager.core.d.ts.map +0 -1
- package/dist/loggerManager/loggerManager.core.js.map +0 -1
- package/dist/loggerOptions/index.d.ts.map +0 -1
- package/dist/loggerOptions/index.js.map +0 -1
- package/dist/loggerOptions/loggerOptions.type.d.ts.map +0 -1
- package/dist/loggerOptions/loggerOptions.type.js.map +0 -1
- package/dist/loggerTransport/index.d.ts.map +0 -1
- package/dist/loggerTransport/index.js.map +0 -1
- package/dist/loggerTransport/loggerTransport.core.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransport.core.js.map +0 -1
- package/dist/loggerTransport/loggerTransport.registry.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransport.registry.js.map +0 -1
- package/dist/loggerTransport/loggerTransport.type.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransport.type.js.map +0 -1
- package/dist/loggerTransport/loggerTransportComposite/index.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransportComposite/index.js.map +0 -1
- package/dist/loggerTransport/loggerTransportComposite/loggerTransportComposite.buffered.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransportComposite/loggerTransportComposite.buffered.js.map +0 -1
- package/dist/loggerTransport/loggerTransportComposite/loggerTransportComposite.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransportComposite/loggerTransportComposite.js.map +0 -1
- package/dist/loggerTransport/loggerTransportConsole/index.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransportConsole/index.js.map +0 -1
- package/dist/loggerTransport/loggerTransportConsole/loggerTransportConsole.core.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransportConsole/loggerTransportConsole.core.js.map +0 -1
- package/dist/loggerTransport/loggerTransportGuard.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransportGuard.js.map +0 -1
- package/dist/loggerTransport/loggerTransportHelpers/index.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransportHelpers/index.js.map +0 -1
- package/dist/loggerTransport/loggerTransportHelpers/loggerTransportHelpers.d.ts.map +0 -1
- package/dist/loggerTransport/loggerTransportHelpers/loggerTransportHelpers.js.map +0 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { LoggerLevel, shouldLog, } from "../../../loggerLevel/loggerLevel.type.js";
|
|
5
5
|
import { LoggerConfigurationError } from "../../../loggerErrors/loggerError.base.js";
|
|
6
6
|
import { createEntry } from "./loggerCoreMethods.entry.js";
|
|
7
|
-
import {
|
|
7
|
+
import { dispatchEntrySync } from "./loggerCoreMethods.dispatch.js";
|
|
8
8
|
/**
|
|
9
9
|
* Level logging methods extracted from ZudojsLogger.
|
|
10
10
|
*/
|
|
@@ -18,6 +18,13 @@ export function logAtLevel(ctx, level, message, options = {}) {
|
|
|
18
18
|
throw new LoggerConfigurationError("Logger message must be a string.");
|
|
19
19
|
}
|
|
20
20
|
const entry = createEntry(ctx.configuration, ctx.contextStorage, level, message, options);
|
|
21
|
-
|
|
21
|
+
// Dispatch is asynchronous. It used to be fired and forgotten, so
|
|
22
|
+
// flush() and close() could return while entries were still in
|
|
23
|
+
// flight — messages were lost on process exit. Registering the
|
|
24
|
+
// promise lets the lifecycle methods drain it.
|
|
25
|
+
const dispatch = dispatchEntrySync(ctx.configuration, entry, (error) => ctx.handleInfrastructureError(error));
|
|
26
|
+
if (dispatch) {
|
|
27
|
+
ctx.trackDispatch(dispatch);
|
|
28
|
+
}
|
|
22
29
|
}
|
|
23
30
|
//# sourceMappingURL=loggerCoreMethods.level.js.map
|
|
@@ -48,6 +48,20 @@ export function disableLogger(ctx) {
|
|
|
48
48
|
*/
|
|
49
49
|
export async function flushLogger(ctx) {
|
|
50
50
|
ctx.assertActive();
|
|
51
|
+
// In-flight dispatches must land in the transports before those
|
|
52
|
+
// transports are asked to flush, otherwise flush() is a no-op for
|
|
53
|
+
// everything logged in the same tick. A dispatch failure (surfaced
|
|
54
|
+
// when `throwTransportErrors` is on) is rethrown only after the
|
|
55
|
+
// transports have still been flushed.
|
|
56
|
+
let failure;
|
|
57
|
+
let failed = false;
|
|
58
|
+
try {
|
|
59
|
+
await ctx.drainDispatches();
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
failure = error;
|
|
63
|
+
failed = true;
|
|
64
|
+
}
|
|
51
65
|
for (const transport of ctx.configuration.transports) {
|
|
52
66
|
if (!isLoggerTransport(transport)) {
|
|
53
67
|
continue;
|
|
@@ -60,6 +74,8 @@ export async function flushLogger(ctx) {
|
|
|
60
74
|
await registered.flush();
|
|
61
75
|
}
|
|
62
76
|
}
|
|
77
|
+
if (failed)
|
|
78
|
+
throw failure;
|
|
63
79
|
}
|
|
64
80
|
/**
|
|
65
81
|
* Closes all transports and marks logger as disposed.
|
|
@@ -68,15 +84,32 @@ export async function closeLogger(ctx) {
|
|
|
68
84
|
if (ctx.isDisposed()) {
|
|
69
85
|
return;
|
|
70
86
|
}
|
|
87
|
+
// Closing is terminal: transports are flushed and closed and the logger
|
|
88
|
+
// is marked disposed even when a dispatch failed; the failure is rethrown
|
|
89
|
+
// afterwards.
|
|
90
|
+
let failure;
|
|
91
|
+
let failed = false;
|
|
92
|
+
try {
|
|
93
|
+
await ctx.drainDispatches();
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
failure = error;
|
|
97
|
+
failed = true;
|
|
98
|
+
}
|
|
71
99
|
for (const transport of ctx.configuration.transports) {
|
|
72
100
|
if (!isLoggerTransport(transport)) {
|
|
73
101
|
continue;
|
|
74
102
|
}
|
|
75
103
|
const registered = createLoggerTransport(transport);
|
|
104
|
+
if (registered.flush) {
|
|
105
|
+
await registered.flush();
|
|
106
|
+
}
|
|
76
107
|
if (registered.close) {
|
|
77
108
|
await registered.close();
|
|
78
109
|
}
|
|
79
110
|
}
|
|
80
111
|
ctx.markDisposed();
|
|
112
|
+
if (failed)
|
|
113
|
+
throw failure;
|
|
81
114
|
}
|
|
82
115
|
//# sourceMappingURL=loggerCoreMethods.lifecycle.js.map
|
|
@@ -6,4 +6,6 @@
|
|
|
6
6
|
export type { LogValue, LogMetadata, LoggerSource, LoggerEntryContext, } from "./loggerEntryHelpers.types.js";
|
|
7
7
|
export type { LoggerEntry, LoggerEntryInput, } from "./loggerEntryHelpers.interfaces.js";
|
|
8
8
|
export { serializeLoggerEntry, serializeLoggerError, serializeLoggerValue, loggerLevelNameFallback, } from "./loggerEntryHelpers.serialize.js";
|
|
9
|
+
export { LOGGER_REDACTION_TOKEN, DEFAULT_LOGGER_SECRET_PATTERN, escapeLogText, hasLogControlCharacters, createSecretMatcher, redactLogValue, } from "./loggerEntryHelpers.sanitize.js";
|
|
10
|
+
export type { LoggerRedactionOptions } from "./loggerEntryHelpers.sanitize.js";
|
|
9
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -4,4 +4,5 @@
|
|
|
4
4
|
* Logger entry helper types and utilities.
|
|
5
5
|
*/
|
|
6
6
|
export { serializeLoggerEntry, serializeLoggerError, serializeLoggerValue, loggerLevelNameFallback, } from "./loggerEntryHelpers.serialize.js";
|
|
7
|
+
export { LOGGER_REDACTION_TOKEN, DEFAULT_LOGGER_SECRET_PATTERN, escapeLogText, hasLogControlCharacters, createSecretMatcher, redactLogValue, } from "./loggerEntryHelpers.sanitize.js";
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log text sanitization and secret redaction.
|
|
3
|
+
*
|
|
4
|
+
* Log records routinely carry attacker-controlled strings (a username,
|
|
5
|
+
* a URL, an error message echoing request input). Written verbatim to a
|
|
6
|
+
* line-oriented sink, a single newline lets that input FORGE a complete
|
|
7
|
+
* additional log line, and an ESC byte lets it drive the operator's
|
|
8
|
+
* terminal. Every string that reaches a text-shaped formatter is
|
|
9
|
+
* therefore escaped here first.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Replacement token written in place of a redacted value.
|
|
13
|
+
*/
|
|
14
|
+
export declare const LOGGER_REDACTION_TOKEN = "[REDACTED]";
|
|
15
|
+
/**
|
|
16
|
+
* Field names treated as secrets by default.
|
|
17
|
+
*
|
|
18
|
+
* Matching is case-insensitive and substring-based so `dbPassword`,
|
|
19
|
+
* `X-Api-Key` and `refresh_token` are all covered.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_LOGGER_SECRET_PATTERN: RegExp;
|
|
22
|
+
/**
|
|
23
|
+
* Controls secret redaction for a logger.
|
|
24
|
+
*/
|
|
25
|
+
export interface LoggerRedactionOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Whether redaction runs at all. Defaults to true.
|
|
28
|
+
*/
|
|
29
|
+
readonly enabled?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Exact field names to redact, in addition to `pattern`.
|
|
32
|
+
*/
|
|
33
|
+
readonly keys?: readonly string[];
|
|
34
|
+
/**
|
|
35
|
+
* Field-name pattern. Defaults to DEFAULT_LOGGER_SECRET_PATTERN.
|
|
36
|
+
* Pass a pattern that never matches to rely on `keys` alone.
|
|
37
|
+
*/
|
|
38
|
+
readonly pattern?: RegExp;
|
|
39
|
+
/**
|
|
40
|
+
* Replacement written in place of a secret.
|
|
41
|
+
*/
|
|
42
|
+
readonly replacement?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Escapes control characters that could forge log records.
|
|
46
|
+
*
|
|
47
|
+
* CR, LF, TAB and the ANSI escape byte become printable escapes; every
|
|
48
|
+
* other C0 control character and DEL becomes `\xNN`. Ordinary text,
|
|
49
|
+
* including every non-ASCII character, is returned unchanged.
|
|
50
|
+
*/
|
|
51
|
+
export declare function escapeLogText(value: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Returns whether a string contains characters that can forge a record.
|
|
54
|
+
*/
|
|
55
|
+
export declare function hasLogControlCharacters(value: string): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Builds a predicate deciding whether a field name holds a secret.
|
|
58
|
+
*/
|
|
59
|
+
export declare function createSecretMatcher(options?: LoggerRedactionOptions): (key: string) => boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Recursively replaces secret-named fields with a redaction token.
|
|
62
|
+
*
|
|
63
|
+
* Nesting, arrays and getters are all covered: the walk descends into
|
|
64
|
+
* every enumerable own property, and a getter is read here — once,
|
|
65
|
+
* before the value can reach a transport. Cycles resolve to
|
|
66
|
+
* "[Circular]" rather than recursing forever.
|
|
67
|
+
*/
|
|
68
|
+
export declare function redactLogValue(value: unknown, isSecret: (key: string) => boolean, replacement?: string, seen?: WeakSet<object>): unknown;
|
|
69
|
+
//# sourceMappingURL=loggerEntryHelpers.sanitize.d.ts.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log text sanitization and secret redaction.
|
|
3
|
+
*
|
|
4
|
+
* Log records routinely carry attacker-controlled strings (a username,
|
|
5
|
+
* a URL, an error message echoing request input). Written verbatim to a
|
|
6
|
+
* line-oriented sink, a single newline lets that input FORGE a complete
|
|
7
|
+
* additional log line, and an ESC byte lets it drive the operator's
|
|
8
|
+
* terminal. Every string that reaches a text-shaped formatter is
|
|
9
|
+
* therefore escaped here first.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Matches C0 control characters plus DEL — everything that can forge a
|
|
13
|
+
* record boundary or drive a terminal.
|
|
14
|
+
*/
|
|
15
|
+
const CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/g;
|
|
16
|
+
/**
|
|
17
|
+
* Replacement token written in place of a redacted value.
|
|
18
|
+
*/
|
|
19
|
+
export const LOGGER_REDACTION_TOKEN = "[REDACTED]";
|
|
20
|
+
/**
|
|
21
|
+
* Field names treated as secrets by default.
|
|
22
|
+
*
|
|
23
|
+
* Matching is case-insensitive and substring-based so `dbPassword`,
|
|
24
|
+
* `X-Api-Key` and `refresh_token` are all covered.
|
|
25
|
+
*/
|
|
26
|
+
export const DEFAULT_LOGGER_SECRET_PATTERN = /(pass(word|wd)?|secret|token|api[-_.]?key|private[-_.]?key|credential|authorization|cookie)/i;
|
|
27
|
+
/**
|
|
28
|
+
* Escapes control characters that could forge log records.
|
|
29
|
+
*
|
|
30
|
+
* CR, LF, TAB and the ANSI escape byte become printable escapes; every
|
|
31
|
+
* other C0 control character and DEL becomes `\xNN`. Ordinary text,
|
|
32
|
+
* including every non-ASCII character, is returned unchanged.
|
|
33
|
+
*/
|
|
34
|
+
export function escapeLogText(value) {
|
|
35
|
+
return value.replace(CONTROL_CHARACTERS, (character) => {
|
|
36
|
+
switch (character) {
|
|
37
|
+
case "\n":
|
|
38
|
+
return "\\n";
|
|
39
|
+
case "\r":
|
|
40
|
+
return "\\r";
|
|
41
|
+
case "\t":
|
|
42
|
+
return "\\t";
|
|
43
|
+
case "\u001b":
|
|
44
|
+
return "\\u001b";
|
|
45
|
+
default: {
|
|
46
|
+
const code = character.charCodeAt(0);
|
|
47
|
+
return `\\x${code.toString(16).padStart(2, "0")}`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns whether a string contains characters that can forge a record.
|
|
54
|
+
*/
|
|
55
|
+
export function hasLogControlCharacters(value) {
|
|
56
|
+
return new RegExp(CONTROL_CHARACTERS.source).test(value);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Builds a predicate deciding whether a field name holds a secret.
|
|
60
|
+
*/
|
|
61
|
+
export function createSecretMatcher(options = {}) {
|
|
62
|
+
if (options.enabled === false) {
|
|
63
|
+
return () => false;
|
|
64
|
+
}
|
|
65
|
+
// Copy the pattern without `g`/`y`: those flags make `test()` advance
|
|
66
|
+
// `lastIndex`, so a shared pattern would match a secret-named field on
|
|
67
|
+
// one entry and let it through unredacted on the next.
|
|
68
|
+
const configured = options.pattern ?? DEFAULT_LOGGER_SECRET_PATTERN;
|
|
69
|
+
const pattern = configured.global || configured.sticky
|
|
70
|
+
? new RegExp(configured.source, configured.flags.replace(/[gy]/gu, ""))
|
|
71
|
+
: configured;
|
|
72
|
+
const exact = new Set((options.keys ?? []).map((key) => key.toLowerCase()));
|
|
73
|
+
return (key) => exact.has(key.toLowerCase()) || pattern.test(key);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Recursively replaces secret-named fields with a redaction token.
|
|
77
|
+
*
|
|
78
|
+
* Nesting, arrays and getters are all covered: the walk descends into
|
|
79
|
+
* every enumerable own property, and a getter is read here — once,
|
|
80
|
+
* before the value can reach a transport. Cycles resolve to
|
|
81
|
+
* "[Circular]" rather than recursing forever.
|
|
82
|
+
*/
|
|
83
|
+
export function redactLogValue(value, isSecret, replacement = LOGGER_REDACTION_TOKEN, seen = new WeakSet()) {
|
|
84
|
+
if (value === null || typeof value !== "object") {
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
if (value instanceof Date || value instanceof Error) {
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
if (seen.has(value)) {
|
|
91
|
+
return "[Circular]";
|
|
92
|
+
}
|
|
93
|
+
seen.add(value);
|
|
94
|
+
if (Array.isArray(value)) {
|
|
95
|
+
return value.map((item) => redactLogValue(item, isSecret, replacement, seen));
|
|
96
|
+
}
|
|
97
|
+
const result = {};
|
|
98
|
+
for (const [key, item] of Object.entries(value)) {
|
|
99
|
+
// defineProperty, never assignment: a "__proto__" key coming from
|
|
100
|
+
// JSON.parse of untrusted input would otherwise reach the inherited
|
|
101
|
+
// setter and replace this object's prototype.
|
|
102
|
+
Object.defineProperty(result, key, {
|
|
103
|
+
value: isSecret(key)
|
|
104
|
+
? replacement
|
|
105
|
+
: redactLogValue(item, isSecret, replacement, seen),
|
|
106
|
+
enumerable: true,
|
|
107
|
+
writable: true,
|
|
108
|
+
configurable: true,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=loggerEntryHelpers.sanitize.js.map
|
|
@@ -5,7 +5,11 @@ import type { LoggerEntry } from "./loggerEntryHelpers.interfaces.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* Returns a plain serializable representation of an entry.
|
|
7
7
|
*
|
|
8
|
-
* This intentionally does not call JSON.stringify itself
|
|
8
|
+
* This intentionally does not call JSON.stringify itself, but every
|
|
9
|
+
* caller-supplied value IS normalized first. Metadata and context used
|
|
10
|
+
* to be embedded by reference, so a circular object or a BigInt made
|
|
11
|
+
* the JSON formatter throw — and because dispatch swallows formatter
|
|
12
|
+
* errors by default, the whole log line vanished silently.
|
|
9
13
|
*/
|
|
10
14
|
export declare function serializeLoggerEntry(entry: LoggerEntry): Record<string, unknown>;
|
|
11
15
|
export { serializeLoggerError, serializeLoggerValue, } from "./loggerEntryHelpers.valueSerialize.js";
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Logger entry serialization helpers.
|
|
3
3
|
*/
|
|
4
|
-
import { serializeLoggerError } from "./loggerEntryHelpers.valueSerialize.js";
|
|
4
|
+
import { serializeLoggerError, serializeLoggerValue, } from "./loggerEntryHelpers.valueSerialize.js";
|
|
5
5
|
/**
|
|
6
6
|
* Returns a plain serializable representation of an entry.
|
|
7
7
|
*
|
|
8
|
-
* This intentionally does not call JSON.stringify itself
|
|
8
|
+
* This intentionally does not call JSON.stringify itself, but every
|
|
9
|
+
* caller-supplied value IS normalized first. Metadata and context used
|
|
10
|
+
* to be embedded by reference, so a circular object or a BigInt made
|
|
11
|
+
* the JSON formatter throw — and because dispatch swallows formatter
|
|
12
|
+
* errors by default, the whole log line vanished silently.
|
|
9
13
|
*/
|
|
10
14
|
export function serializeLoggerEntry(entry) {
|
|
11
15
|
return {
|
|
@@ -13,9 +17,9 @@ export function serializeLoggerEntry(entry) {
|
|
|
13
17
|
level: entry.level,
|
|
14
18
|
levelName: entry.levelName,
|
|
15
19
|
message: entry.message,
|
|
16
|
-
metadata: entry.metadata,
|
|
17
|
-
context: entry.context,
|
|
18
|
-
source: entry.source,
|
|
20
|
+
metadata: serializeLoggerValue(entry.metadata),
|
|
21
|
+
context: serializeLoggerValue(entry.context),
|
|
22
|
+
source: serializeLoggerValue(entry.source),
|
|
19
23
|
error: entry.error ? serializeLoggerError(entry.error) : undefined,
|
|
20
24
|
logger: entry.logger,
|
|
21
25
|
timestamp: entry.timestamp.toISOString(),
|
|
@@ -49,7 +49,15 @@ export function serializeLoggerValue(value, seen = new WeakSet()) {
|
|
|
49
49
|
}
|
|
50
50
|
const result = {};
|
|
51
51
|
for (const [key, item] of Object.entries(value)) {
|
|
52
|
-
|
|
52
|
+
// defineProperty, never assignment: a "__proto__" key from an
|
|
53
|
+
// untrusted payload would otherwise reach the inherited setter and
|
|
54
|
+
// replace the serialized object's prototype.
|
|
55
|
+
Object.defineProperty(result, key, {
|
|
56
|
+
value: serializeLoggerValue(item, seen),
|
|
57
|
+
enumerable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
configurable: true,
|
|
60
|
+
});
|
|
53
61
|
}
|
|
54
62
|
return result;
|
|
55
63
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Logger context and source formatting helpers.
|
|
3
3
|
*/
|
|
4
|
+
import { escapeLogText } from "../../loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.js";
|
|
4
5
|
/**
|
|
5
6
|
* Formats logger context.
|
|
6
7
|
*/
|
|
@@ -13,7 +14,16 @@ export function formatContext(entry) {
|
|
|
13
14
|
if (value === undefined || value === null) {
|
|
14
15
|
continue;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
if (typeof value === "object") {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
// Context identifiers are also flattened into metadata; skip the ones
|
|
21
|
+
// the metadata block already prints so a line never repeats itself.
|
|
22
|
+
if (Object.hasOwn(entry.metadata, key) &&
|
|
23
|
+
entry.metadata[key] === value) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
values.push(`${escapeLogText(key)}=${escapeLogText(String(value))}`);
|
|
17
27
|
}
|
|
18
28
|
return values.length > 0 ? `[${values.join(" ")}]` : "";
|
|
19
29
|
}
|
|
@@ -27,12 +37,14 @@ export function formatSource(entry) {
|
|
|
27
37
|
}
|
|
28
38
|
const location = [];
|
|
29
39
|
if (source.file) {
|
|
30
|
-
location.push(source.file);
|
|
40
|
+
location.push(escapeLogText(source.file));
|
|
31
41
|
}
|
|
32
42
|
if (source.line !== undefined) {
|
|
33
43
|
location.push(String(source.line));
|
|
34
44
|
}
|
|
35
|
-
const functionName = source.function
|
|
45
|
+
const functionName = source.function
|
|
46
|
+
? ` ${escapeLogText(source.function)}`
|
|
47
|
+
: "";
|
|
36
48
|
return location.length > 0 ? `[${location.join(":")}${functionName}]` : "";
|
|
37
49
|
}
|
|
38
50
|
//# sourceMappingURL=loggerFormatterFormatters.context.js.map
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { serializeLoggerEntry } from "../../loggerEntry/loggerEntrySerialize.js";
|
|
5
5
|
import { createLoggerFormatter } from "../loggerFormatter.core.js";
|
|
6
|
+
import { escapeLogText } from "../../loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.js";
|
|
6
7
|
import { createJsonLoggerFormatter } from "./loggerFormatterFormatters.json.js";
|
|
7
8
|
import { createTextLoggerFormatter } from "./loggerFormatterFormatters.text.js";
|
|
8
9
|
/**
|
|
@@ -11,8 +12,8 @@ import { createTextLoggerFormatter } from "./loggerFormatterFormatters.text.js";
|
|
|
11
12
|
export function createCompactLoggerFormatter(options = {}) {
|
|
12
13
|
return createLoggerFormatter((entry) => {
|
|
13
14
|
const level = entry.levelName.toUpperCase();
|
|
14
|
-
const logger = entry.logger ? ` ${entry.logger}:` : "";
|
|
15
|
-
return `${level}${logger} ${entry.message}`;
|
|
15
|
+
const logger = entry.logger ? ` ${escapeLogText(entry.logger)}:` : "";
|
|
16
|
+
return `${level}${logger} ${escapeLogText(entry.message)}`;
|
|
16
17
|
}, {
|
|
17
18
|
name: options.name ?? "compact",
|
|
18
19
|
});
|
|
@@ -6,17 +6,33 @@ import { createLoggerFormatter } from "../loggerFormatter.core.js";
|
|
|
6
6
|
/**
|
|
7
7
|
* Removes undefined values recursively.
|
|
8
8
|
*/
|
|
9
|
-
function removeUndefinedValues(value) {
|
|
9
|
+
function removeUndefinedValues(value, seen = new WeakSet()) {
|
|
10
10
|
if (Array.isArray(value)) {
|
|
11
|
-
|
|
11
|
+
if (seen.has(value)) {
|
|
12
|
+
return "[Circular]";
|
|
13
|
+
}
|
|
14
|
+
seen.add(value);
|
|
15
|
+
return value.map((item) => removeUndefinedValues(item, seen));
|
|
12
16
|
}
|
|
13
17
|
if (value && typeof value === "object" && !(value instanceof Date)) {
|
|
18
|
+
// Without a cycle guard this walk recursed until the stack blew,
|
|
19
|
+
// and the resulting RangeError was swallowed by dispatch — losing
|
|
20
|
+
// the log line rather than reporting the offending value.
|
|
21
|
+
if (seen.has(value)) {
|
|
22
|
+
return "[Circular]";
|
|
23
|
+
}
|
|
24
|
+
seen.add(value);
|
|
14
25
|
const result = {};
|
|
15
26
|
for (const [key, item] of Object.entries(value)) {
|
|
16
27
|
if (item === undefined) {
|
|
17
28
|
continue;
|
|
18
29
|
}
|
|
19
|
-
result
|
|
30
|
+
Object.defineProperty(result, key, {
|
|
31
|
+
value: removeUndefinedValues(item, seen),
|
|
32
|
+
enumerable: true,
|
|
33
|
+
writable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
});
|
|
20
36
|
}
|
|
21
37
|
return result;
|
|
22
38
|
}
|
package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.js
CHANGED
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
* Logger metadata and error formatting helpers.
|
|
3
3
|
*/
|
|
4
4
|
import { serializeLoggerError, serializeLoggerValue, } from "../../loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.js";
|
|
5
|
+
import { escapeLogText } from "../../loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.js";
|
|
5
6
|
/**
|
|
6
7
|
* Formats metadata as key=value pairs.
|
|
7
8
|
*/
|
|
8
9
|
export function formatMetadata(metadata, separator) {
|
|
9
|
-
return Object.entries(metadata)
|
|
10
|
+
return (Object.entries(metadata)
|
|
10
11
|
.filter(([, value]) => value !== undefined)
|
|
11
|
-
|
|
12
|
-
.
|
|
12
|
+
// Metadata KEYS are as attacker-influenceable as values (a header
|
|
13
|
+
// name, a form field) and were previously interpolated raw.
|
|
14
|
+
.map(([key, value]) => `${escapeLogText(key)}=${formatValue(value)}`)
|
|
15
|
+
.join(separator));
|
|
13
16
|
}
|
|
14
17
|
/**
|
|
15
18
|
* Formats an arbitrary metadata value.
|
|
@@ -22,19 +25,24 @@ export function formatValue(value) {
|
|
|
22
25
|
if (/\s/.test(value)) {
|
|
23
26
|
return JSON.stringify(value);
|
|
24
27
|
}
|
|
25
|
-
|
|
28
|
+
// A value with no whitespace can still carry ANSI escapes or other
|
|
29
|
+
// C0 controls, which used to reach the sink verbatim.
|
|
30
|
+
return escapeLogText(value);
|
|
26
31
|
}
|
|
27
32
|
if (typeof value === "object") {
|
|
28
33
|
return JSON.stringify(serializeLoggerValue(value));
|
|
29
34
|
}
|
|
30
|
-
return String(value);
|
|
35
|
+
return escapeLogText(String(value));
|
|
31
36
|
}
|
|
32
37
|
/**
|
|
33
38
|
* Formats an Error.
|
|
34
39
|
*/
|
|
35
40
|
export function formatError(error, includeStackTrace) {
|
|
36
41
|
if (includeStackTrace && error.stack) {
|
|
37
|
-
|
|
42
|
+
// A stack trace is intentionally multi-line, but everything in it
|
|
43
|
+
// that came from user input (the message) must not be able to
|
|
44
|
+
// introduce a further record boundary of its own.
|
|
45
|
+
return `\n${error.stack.split("\n").map(escapeLogText).join("\n")}`;
|
|
38
46
|
}
|
|
39
47
|
const serialized = serializeLoggerError(error);
|
|
40
48
|
return `error=${JSON.stringify(serialized)}`;
|
|
@@ -2,8 +2,26 @@
|
|
|
2
2
|
* Text logger formatter.
|
|
3
3
|
*/
|
|
4
4
|
import { createLoggerFormatter } from "../loggerFormatter.core.js";
|
|
5
|
+
import { escapeLogText } from "../../loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.js";
|
|
5
6
|
import { formatContext, formatSource, } from "./loggerFormatterFormatters.context.js";
|
|
6
7
|
import { formatMetadata, formatError, } from "./loggerFormatterFormatters.metadata.js";
|
|
8
|
+
/** ANSI colour per severity, used only when the caller opts in. */
|
|
9
|
+
const LEVEL_COLORS = Object.freeze({
|
|
10
|
+
fatal: "35",
|
|
11
|
+
error: "31",
|
|
12
|
+
warn: "33",
|
|
13
|
+
info: "36",
|
|
14
|
+
debug: "32",
|
|
15
|
+
trace: "90",
|
|
16
|
+
});
|
|
17
|
+
/** Wraps a level tag in an ANSI colour sequence. */
|
|
18
|
+
function colorizeLevel(levelName, tag) {
|
|
19
|
+
const color = LEVEL_COLORS[levelName];
|
|
20
|
+
if (color === undefined) {
|
|
21
|
+
return tag;
|
|
22
|
+
}
|
|
23
|
+
return `\u001b[${color}m${tag}\u001b[0m`;
|
|
24
|
+
}
|
|
7
25
|
/**
|
|
8
26
|
* Creates a human-readable text formatter.
|
|
9
27
|
*/
|
|
@@ -15,16 +33,25 @@ export function createTextLoggerFormatter(options = {}) {
|
|
|
15
33
|
const includeSource = options.includeSource ?? false;
|
|
16
34
|
const includeStackTrace = options.includeStackTrace ?? true;
|
|
17
35
|
const metadataSeparator = options.metadataSeparator ?? " ";
|
|
18
|
-
return createLoggerFormatter((entry) => {
|
|
36
|
+
return createLoggerFormatter((entry, context) => {
|
|
19
37
|
const parts = [];
|
|
20
38
|
if (includeTimestamp) {
|
|
21
39
|
parts.push(entry.timestamp.toISOString());
|
|
22
40
|
}
|
|
23
|
-
|
|
41
|
+
// LoggerFormatterContext.colors was declared from the first
|
|
42
|
+
// release and read by nothing, so `colors: true` produced plain
|
|
43
|
+
// output. Colour codes are emitted only on explicit opt-in, and
|
|
44
|
+
// only around the fixed level name — never around user text,
|
|
45
|
+
// which stays escaped.
|
|
46
|
+
const levelTag = `[${entry.levelName.toUpperCase()}]`;
|
|
47
|
+
parts.push(context.colors ? colorizeLevel(entry.levelName, levelTag) : levelTag);
|
|
24
48
|
if (includeLogger && entry.logger) {
|
|
25
|
-
parts.push(`[${entry.logger}]`);
|
|
49
|
+
parts.push(`[${escapeLogText(entry.logger)}]`);
|
|
26
50
|
}
|
|
27
|
-
|
|
51
|
+
// The message is the single most attacker-influenceable field on
|
|
52
|
+
// an entry. Emitted verbatim, a newline inside it forged a whole
|
|
53
|
+
// extra log record and an ESC byte drove the operator's terminal.
|
|
54
|
+
parts.push(escapeLogText(entry.message));
|
|
28
55
|
if (includeContext && entry.context) {
|
|
29
56
|
const context = formatContext(entry);
|
|
30
57
|
if (context) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { LoggerLevel } 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";
|
|
5
|
+
import type { LoggerRedactionOptions } from "../loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.js";
|
|
5
6
|
/** Options used to configure a Zudojs logger. */
|
|
6
7
|
export interface LoggerOptions {
|
|
7
8
|
readonly name?: string;
|
|
@@ -16,6 +17,15 @@ export interface LoggerOptions {
|
|
|
16
17
|
readonly transportTimeout?: number;
|
|
17
18
|
readonly inheritContext?: boolean;
|
|
18
19
|
readonly mutable?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Secret redaction for metadata and context.
|
|
22
|
+
*
|
|
23
|
+
* Redaction is ON by default: fields whose NAME looks like a secret
|
|
24
|
+
* (password, token, api key, credential, authorization, cookie) are
|
|
25
|
+
* replaced with "[REDACTED]" before an entry reaches a formatter.
|
|
26
|
+
* Pass `{ enabled: false }` to opt out.
|
|
27
|
+
*/
|
|
28
|
+
readonly redact?: LoggerRedactionOptions;
|
|
19
29
|
}
|
|
20
30
|
/** Options used when creating a child logger. */
|
|
21
31
|
export interface ChildLoggerOptions {
|
|
@@ -53,6 +63,7 @@ export interface LoggerConfiguration {
|
|
|
53
63
|
readonly transportTimeout: number;
|
|
54
64
|
readonly inheritContext: boolean;
|
|
55
65
|
readonly mutable: boolean;
|
|
66
|
+
readonly redact: LoggerRedactionOptions;
|
|
56
67
|
}
|
|
57
68
|
/** Default logger configuration values. */
|
|
58
69
|
export declare const DEFAULT_LOGGER_OPTIONS: Required<Pick<LoggerOptions, "enabled" | "throwTransportErrors" | "asynchronous" | "transportTimeout" | "inheritContext" | "mutable">>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LoggerLevel } from "../loggerLevel/loggerLevel.type.js";
|
|
1
2
|
/** Default logger configuration values. */
|
|
2
3
|
export const DEFAULT_LOGGER_OPTIONS = {
|
|
3
4
|
enabled: true,
|
|
@@ -28,7 +29,7 @@ export function resolveLoggerOptions(options = {}) {
|
|
|
28
29
|
validateLoggerOptions(options);
|
|
29
30
|
return Object.freeze({
|
|
30
31
|
name: options.name ?? "zudojs",
|
|
31
|
-
level: options.level ??
|
|
32
|
+
level: options.level ?? LoggerLevel.INFO,
|
|
32
33
|
environment: options.environment,
|
|
33
34
|
metadata: Object.freeze({ ...(options.metadata ?? {}) }),
|
|
34
35
|
formatter: options.formatter ?? "text",
|
|
@@ -40,6 +41,7 @@ export function resolveLoggerOptions(options = {}) {
|
|
|
40
41
|
transportTimeout: options.transportTimeout ?? DEFAULT_LOGGER_OPTIONS.transportTimeout,
|
|
41
42
|
inheritContext: options.inheritContext ?? DEFAULT_LOGGER_OPTIONS.inheritContext,
|
|
42
43
|
mutable: options.mutable ?? DEFAULT_LOGGER_OPTIONS.mutable,
|
|
44
|
+
redact: Object.freeze({ ...(options.redact ?? {}) }),
|
|
43
45
|
});
|
|
44
46
|
}
|
|
45
47
|
/** Merges two logger option objects. Values from `override` take precedence. */
|
|
@@ -66,6 +68,7 @@ export function createChildLoggerOptions(parent, options = {}) {
|
|
|
66
68
|
transportTimeout: parent.transportTimeout,
|
|
67
69
|
inheritContext: parent.inheritContext,
|
|
68
70
|
mutable: parent.mutable,
|
|
71
|
+
redact: parent.redact,
|
|
69
72
|
};
|
|
70
73
|
}
|
|
71
74
|
//# sourceMappingURL=loggerOptions.type.js.map
|
|
@@ -34,6 +34,10 @@ export function createBufferedLoggerTransport(transport, options = {}) {
|
|
|
34
34
|
/* deliberate no-op */
|
|
35
35
|
}
|
|
36
36
|
}, flushInterval);
|
|
37
|
+
// A pending flush is housekeeping, not work: left referenced it kept a
|
|
38
|
+
// finished process alive for a full `flushInterval`. close() flushes
|
|
39
|
+
// whatever is buffered, so nothing is lost by letting the loop exit.
|
|
40
|
+
timer.unref?.();
|
|
37
41
|
};
|
|
38
42
|
const buffered = {
|
|
39
43
|
name: options.name ?? "buffered",
|