@ayepi/log 0.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 +216 -0
- package/dist/file.cjs +175 -0
- package/dist/file.d.cts +50 -0
- package/dist/file.d.ts +50 -0
- package/dist/file.js +174 -0
- package/dist/index.cjs +239 -0
- package/dist/index.d.cts +125 -0
- package/dist/index.d.ts +125 -0
- package/dist/index.js +218 -0
- package/dist/internal.cjs +546 -0
- package/dist/internal.d.cts +153 -0
- package/dist/internal.d.ts +153 -0
- package/dist/internal.js +415 -0
- package/dist/middleware.cjs +38 -0
- package/dist/middleware.d.cts +27 -0
- package/dist/middleware.d.ts +27 -0
- package/dist/middleware.js +37 -0
- package/dist/server.cjs +40 -0
- package/dist/server.d.cts +36 -0
- package/dist/server.d.ts +36 -0
- package/dist/server.js +39 -0
- package/package.json +100 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_internal = require("./internal.cjs");
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
/**
|
|
5
|
+
* # @ayepi/log
|
|
6
|
+
*
|
|
7
|
+
* Structured logging with **AsyncLocalStorage trace context**. Stack context with
|
|
8
|
+
* {@link logWith} and it flows through the whole async call tree (and onto thrown
|
|
9
|
+
* errors); {@link log} builds a record from mixed primitive/object/Error args;
|
|
10
|
+
* output goes to pluggable {@link Transport}s (console here, file via
|
|
11
|
+
* `@ayepi/log/file`); console.* can be intercepted (opt-in).
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { createLogger } from '@ayepi/log'
|
|
15
|
+
* const log = createLogger({ level: 'debug' })
|
|
16
|
+
*
|
|
17
|
+
* log.logWith({ reqId: 'abc' }, async () => {
|
|
18
|
+
* log.info('handling', { userId: 'u1' }) // → reqId + userId on the record
|
|
19
|
+
* await work() // a rejection here is tagged with { reqId, userId }
|
|
20
|
+
* })
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Bare `import` has **no side effects** — console interception is opt-in.
|
|
24
|
+
*
|
|
25
|
+
* @module
|
|
26
|
+
*/
|
|
27
|
+
const noopConsole = {
|
|
28
|
+
log() {},
|
|
29
|
+
info() {},
|
|
30
|
+
debug() {},
|
|
31
|
+
warn() {},
|
|
32
|
+
error() {}
|
|
33
|
+
};
|
|
34
|
+
const globalConsole = () => globalThis.console ?? noopConsole;
|
|
35
|
+
const defaultMethod = (level) => level === "error" ? "error" : level === "warn" ? "warn" : level === "debug" ? "debug" : "log";
|
|
36
|
+
/** A {@link Transport} that writes the formatted line to a console. */
|
|
37
|
+
function consoleTransport(opts = {}) {
|
|
38
|
+
const target = opts.console ?? globalConsole();
|
|
39
|
+
const pick = opts.method ?? defaultMethod;
|
|
40
|
+
return {
|
|
41
|
+
name: "console",
|
|
42
|
+
write(record, text) {
|
|
43
|
+
target[pick(record.level)](text);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Capture the current console methods (bound) so the transport + restore use the originals. */
|
|
48
|
+
function captureConsole(c) {
|
|
49
|
+
return {
|
|
50
|
+
log: c.log.bind(c),
|
|
51
|
+
info: c.info.bind(c),
|
|
52
|
+
debug: c.debug.bind(c),
|
|
53
|
+
warn: c.warn.bind(c),
|
|
54
|
+
error: c.error.bind(c)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Create a {@link Logger}.
|
|
59
|
+
*/
|
|
60
|
+
function createLogger(config = {}) {
|
|
61
|
+
let level = config.level ?? "info";
|
|
62
|
+
const structured = config.structured ?? false;
|
|
63
|
+
const timestamp = config.timestamp ?? "iso";
|
|
64
|
+
const now = config.now ?? (() => Date.now());
|
|
65
|
+
const errorCfg = config.error ?? {};
|
|
66
|
+
const consoleMap = config.consoleMap ?? require_internal.CONSOLE_LEVEL_MAP;
|
|
67
|
+
const targetConsole = config.console ?? globalConsole();
|
|
68
|
+
const originals = captureConsole(targetConsole);
|
|
69
|
+
let transports = config.transports ?? [consoleTransport({ console: originals })];
|
|
70
|
+
let intercepting = false;
|
|
71
|
+
let writing = false;
|
|
72
|
+
const report = (err) => {
|
|
73
|
+
try {
|
|
74
|
+
config.onError?.(err);
|
|
75
|
+
} catch {}
|
|
76
|
+
};
|
|
77
|
+
const sanitize = config.sanitize ? require_internal.createSanitizer(config.sanitize) : void 0;
|
|
78
|
+
const resolveOpts = {
|
|
79
|
+
onError: report,
|
|
80
|
+
serializers: config.serializers
|
|
81
|
+
};
|
|
82
|
+
/** Build → filter → sanitize → format → write a record from already-resolved args. */
|
|
83
|
+
const deliver = (lvl, args) => {
|
|
84
|
+
let record;
|
|
85
|
+
let text;
|
|
86
|
+
try {
|
|
87
|
+
record = require_internal.buildRecord(lvl, args, {
|
|
88
|
+
now,
|
|
89
|
+
timestamp,
|
|
90
|
+
error: errorCfg
|
|
91
|
+
});
|
|
92
|
+
if (config.filter) {
|
|
93
|
+
const filtered = config.filter(record);
|
|
94
|
+
if (!filtered) return;
|
|
95
|
+
record = filtered;
|
|
96
|
+
}
|
|
97
|
+
if (sanitize) {
|
|
98
|
+
const cleaned = sanitize(record);
|
|
99
|
+
if (!cleaned) return;
|
|
100
|
+
record = cleaned;
|
|
101
|
+
}
|
|
102
|
+
text = structured ? require_internal.formatJson(record) : require_internal.formatText(record);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
report(err);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
writing = true;
|
|
108
|
+
try {
|
|
109
|
+
for (const t of transports) try {
|
|
110
|
+
t.write(record, text);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
report(err);
|
|
113
|
+
}
|
|
114
|
+
} finally {
|
|
115
|
+
writing = false;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
/** Produce a {@link logMaybe}'s value for this level (only now that we know we'll log), or pass through. */
|
|
119
|
+
const seedArg = (raw, lvl) => {
|
|
120
|
+
if (!require_internal.isLazy(raw)) return raw;
|
|
121
|
+
try {
|
|
122
|
+
return raw[require_internal.LOG_MAYBE](lvl);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
report(err);
|
|
125
|
+
return require_internal.UNRESOLVED;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const emit = (lvl, args) => {
|
|
129
|
+
if (require_internal.LEVELS[lvl] < require_internal.LEVELS[level] || writing) return;
|
|
130
|
+
let resolved;
|
|
131
|
+
try {
|
|
132
|
+
resolved = args.map((raw) => require_internal.resolveLog(seedArg(raw, lvl), "", /* @__PURE__ */ new WeakSet(), resolveOpts));
|
|
133
|
+
} catch (err) {
|
|
134
|
+
report(err);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (resolved.some((v) => require_internal.containsThenable(v))) require_internal.settleDeep(resolved).then((settled) => deliver(lvl, settled)).catch(report);
|
|
138
|
+
else deliver(lvl, resolved);
|
|
139
|
+
};
|
|
140
|
+
let installed = [];
|
|
141
|
+
const restore = () => {
|
|
142
|
+
if (!intercepting) return;
|
|
143
|
+
intercepting = false;
|
|
144
|
+
const c = targetConsole;
|
|
145
|
+
for (const { method, original } of installed) c[method] = original;
|
|
146
|
+
installed = [];
|
|
147
|
+
};
|
|
148
|
+
const install = () => {
|
|
149
|
+
if (intercepting) return restore;
|
|
150
|
+
intercepting = true;
|
|
151
|
+
const c = targetConsole;
|
|
152
|
+
installed = [];
|
|
153
|
+
for (const method of Object.keys(consoleMap)) {
|
|
154
|
+
const lvl = consoleMap[method];
|
|
155
|
+
installed.push({
|
|
156
|
+
method,
|
|
157
|
+
original: c[method]
|
|
158
|
+
});
|
|
159
|
+
c[method] = (...args) => emit(lvl, args);
|
|
160
|
+
}
|
|
161
|
+
return restore;
|
|
162
|
+
};
|
|
163
|
+
/** Run `op` over every transport in parallel, awaiting all and reporting (never throwing) failures. */
|
|
164
|
+
const drain = (op) => Promise.all(transports.map(async (t) => {
|
|
165
|
+
try {
|
|
166
|
+
await op(t);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
report(err);
|
|
169
|
+
}
|
|
170
|
+
})).then(() => void 0);
|
|
171
|
+
const logger = {
|
|
172
|
+
log: (lvl, ...args) => emit(lvl, args),
|
|
173
|
+
debug: (...args) => emit("debug", args),
|
|
174
|
+
info: (...args) => emit("info", args),
|
|
175
|
+
warn: (...args) => emit("warn", args),
|
|
176
|
+
error: (...args) => emit("error", args),
|
|
177
|
+
logWith: (add, inner) => require_internal.runWith(add, inner),
|
|
178
|
+
context: () => Object.freeze({ ...require_internal.getContext() }),
|
|
179
|
+
setTransports: (t) => {
|
|
180
|
+
transports = t;
|
|
181
|
+
},
|
|
182
|
+
setLevel: (l) => {
|
|
183
|
+
level = l;
|
|
184
|
+
},
|
|
185
|
+
isLevelEnabled: (l) => require_internal.LEVELS[l] >= require_internal.LEVELS[level],
|
|
186
|
+
flush: () => drain((t) => t.flush?.()),
|
|
187
|
+
close: () => drain((t) => t.close?.()),
|
|
188
|
+
config: {
|
|
189
|
+
get level() {
|
|
190
|
+
return level;
|
|
191
|
+
},
|
|
192
|
+
structured,
|
|
193
|
+
timestamp
|
|
194
|
+
},
|
|
195
|
+
interceptConsole: install,
|
|
196
|
+
restoreConsole: restore
|
|
197
|
+
};
|
|
198
|
+
if (config.interceptConsole ?? false) install();
|
|
199
|
+
return logger;
|
|
200
|
+
}
|
|
201
|
+
const instance = createLogger();
|
|
202
|
+
/** Emit a record at `level` on the default logger. */
|
|
203
|
+
const log = (level, ...args) => instance.log(level, ...args);
|
|
204
|
+
const debug = (...args) => instance.debug(...args);
|
|
205
|
+
const info = (...args) => instance.info(...args);
|
|
206
|
+
const warn = (...args) => instance.warn(...args);
|
|
207
|
+
const error = (...args) => instance.error(...args);
|
|
208
|
+
/** Stack trace context on the default logger (and tag promise rejections). */
|
|
209
|
+
const logWith = (add, inner) => instance.logWith(add, inner);
|
|
210
|
+
/** The default logger's current trace context. */
|
|
211
|
+
const context = () => instance.context();
|
|
212
|
+
/** Intercept `console.*` through the default logger; returns a restore function. */
|
|
213
|
+
const interceptConsole = () => instance.interceptConsole();
|
|
214
|
+
/** Restore console interception installed by the default logger. */
|
|
215
|
+
const restoreConsole = () => instance.restoreConsole();
|
|
216
|
+
/** The default logger instance. */
|
|
217
|
+
const logger = instance;
|
|
218
|
+
//#endregion
|
|
219
|
+
exports.LOG_CONTEXT = require_internal.LOG_CONTEXT;
|
|
220
|
+
exports.consoleTransport = consoleTransport;
|
|
221
|
+
exports.context = context;
|
|
222
|
+
exports.createLogger = createLogger;
|
|
223
|
+
exports.createSanitizer = require_internal.createSanitizer;
|
|
224
|
+
exports.debug = debug;
|
|
225
|
+
exports.deepEqual = require_internal.deepEqual;
|
|
226
|
+
exports.error = error;
|
|
227
|
+
exports.getContext = require_internal.getContext;
|
|
228
|
+
exports.info = info;
|
|
229
|
+
exports.interceptConsole = interceptConsole;
|
|
230
|
+
exports.log = log;
|
|
231
|
+
exports.logMaybe = require_internal.logMaybe;
|
|
232
|
+
exports.logWith = logWith;
|
|
233
|
+
exports.logger = logger;
|
|
234
|
+
exports.merge = require_internal.merge;
|
|
235
|
+
exports.partialMask = require_internal.partialMask;
|
|
236
|
+
exports.resolveLogValue = require_internal.resolveLogValue;
|
|
237
|
+
exports.restoreConsole = restoreConsole;
|
|
238
|
+
exports.serializeError = require_internal.serializeError;
|
|
239
|
+
exports.warn = warn;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { _ as partialMask, a as Level, c as SanitizeOptions, d as Transport, f as createSanitizer, g as merge, h as logMaybe, i as LazyLogValue, l as SerializedError, m as getContext, n as ErrorConfig, o as LogRecord, p as deepEqual, r as LOG_CONTEXT, s as MaybePromise, t as ErrorCaptureConfig, u as Serializer, v as resolveLogValue, y as serializeError } from "./internal.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
|
|
5
|
+
/** The minimal `console` surface the logger reads/intercepts (the global one, or your own). */
|
|
6
|
+
interface ConsoleLike {
|
|
7
|
+
log(...args: unknown[]): void;
|
|
8
|
+
info(...args: unknown[]): void;
|
|
9
|
+
debug(...args: unknown[]): void;
|
|
10
|
+
warn(...args: unknown[]): void;
|
|
11
|
+
error(...args: unknown[]): void;
|
|
12
|
+
}
|
|
13
|
+
/** Options for {@link consoleTransport}. */
|
|
14
|
+
interface ConsoleTransportOptions {
|
|
15
|
+
/** The console to **write through** — should be the original (pre-interception) console to avoid recursion. */
|
|
16
|
+
readonly console?: ConsoleLike;
|
|
17
|
+
/** Map a record level to a console method (default: error→error, warn→warn, debug→debug, else→log). */
|
|
18
|
+
readonly method?: (level: Level) => keyof ConsoleLike;
|
|
19
|
+
}
|
|
20
|
+
/** A {@link Transport} that writes the formatted line to a console. */
|
|
21
|
+
declare function consoleTransport(opts?: ConsoleTransportOptions): Transport;
|
|
22
|
+
/** Configuration for {@link createLogger}. */
|
|
23
|
+
interface LoggerConfig {
|
|
24
|
+
/** Minimum level emitted (default `'info'`). Logs below this are dropped before a record is built. */
|
|
25
|
+
readonly level?: Level;
|
|
26
|
+
/** Structured JSON output vs `[tms] level msg key=value` text (default `false` = text). */
|
|
27
|
+
readonly structured?: boolean;
|
|
28
|
+
/** Timestamp format — ISO string (default) or numeric epoch ms. */
|
|
29
|
+
readonly timestamp?: 'iso' | 'epoch';
|
|
30
|
+
/** Transports to write to (default: a single {@link consoleTransport} bound to the captured original console). */
|
|
31
|
+
readonly transports?: readonly Transport[];
|
|
32
|
+
/** Intercept global `console.*` immediately (default `false` — opt-in). */
|
|
33
|
+
readonly interceptConsole?: boolean;
|
|
34
|
+
/** `console` method → level mapping for interception (default {@link CONSOLE_LEVEL_MAP}). */
|
|
35
|
+
readonly consoleMap?: Readonly<Record<string, Level>>;
|
|
36
|
+
/** The console to read originals from / intercept (default the global `console`). */
|
|
37
|
+
readonly console?: ConsoleLike;
|
|
38
|
+
/** Error serialization config, including per-level overrides. */
|
|
39
|
+
readonly error?: ErrorConfig;
|
|
40
|
+
/**
|
|
41
|
+
* Final hook over the built record before it is formatted. Return a (possibly
|
|
42
|
+
* modified) record to log it — e.g. redact or add fields — or `null`/`undefined`
|
|
43
|
+
* to drop the log entirely. Runs **before** {@link sanitize}.
|
|
44
|
+
*/
|
|
45
|
+
readonly filter?: (record: LogRecord) => LogRecord | null | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Declarative redaction/truncation applied to every record (after {@link filter}): drop via a
|
|
48
|
+
* `filter` predicate, mask `sensitiveKeys`/`sensitiveValues`, and cap `maxStringLength` /
|
|
49
|
+
* `maxArrayLength`. Applies to direct logger calls **and** intercepted `console.*`. (Equivalent
|
|
50
|
+
* to passing `createSanitizer(opts)` as `filter`, but it composes after your own `filter`.)
|
|
51
|
+
*/
|
|
52
|
+
readonly sanitize?: SanitizeOptions;
|
|
53
|
+
/**
|
|
54
|
+
* Observe an error from the logging pipeline itself — a throwing `filter`, an
|
|
55
|
+
* unserializable record, or a transport whose `write` throws. Logging is **best-effort**:
|
|
56
|
+
* such an error never propagates to the caller (the line is dropped); this hook just lets
|
|
57
|
+
* you notice (e.g. count a metric, write to `stderr`). Off by default. It must not throw;
|
|
58
|
+
* if it does, the throw is ignored.
|
|
59
|
+
*/
|
|
60
|
+
readonly onError?: (err: unknown) => void;
|
|
61
|
+
/**
|
|
62
|
+
* Custom {@link Serializer}s for values the logger doesn't own (a `Request`, `URL`, `Buffer`,
|
|
63
|
+
* a third-party class…) — the predicate-style counterpart to a `toLOG`/`toJSON` hook. Each is
|
|
64
|
+
* tried in order at every depth; the first non-`undefined` result wins (taking precedence over
|
|
65
|
+
* the value's own `toLOG`/`toJSON`). They apply to direct calls and intercepted `console.*`.
|
|
66
|
+
*/
|
|
67
|
+
readonly serializers?: readonly Serializer[];
|
|
68
|
+
/** Clock injection for tests (default `() => Date.now()`). */
|
|
69
|
+
readonly now?: () => number;
|
|
70
|
+
}
|
|
71
|
+
/** A logger instance. */
|
|
72
|
+
interface Logger {
|
|
73
|
+
/** Emit a record at `level` from mixed primitive/object/Error args. No-op below the threshold. */
|
|
74
|
+
log(level: Level, ...args: unknown[]): void;
|
|
75
|
+
debug(...args: unknown[]): void;
|
|
76
|
+
info(...args: unknown[]): void;
|
|
77
|
+
warn(...args: unknown[]): void;
|
|
78
|
+
error(...args: unknown[]): void;
|
|
79
|
+
/** Merge `add` into the current trace context, run `inner` within it, and tag promise rejections with the context. */
|
|
80
|
+
logWith<R>(add: object, inner: () => R): R;
|
|
81
|
+
/** Snapshot of the current merged trace context (empty outside any `logWith`). */
|
|
82
|
+
context(): Readonly<Record<string, unknown>>;
|
|
83
|
+
/** Replace the transports at runtime. */
|
|
84
|
+
setTransports(transports: readonly Transport[]): void;
|
|
85
|
+
/** Change the minimum emitted level at runtime (e.g. bump to `'debug'` on demand). */
|
|
86
|
+
setLevel(level: Level): void;
|
|
87
|
+
/** Whether a record at `level` would be emitted at the current threshold — guard expensive prep. */
|
|
88
|
+
isLevelEnabled(level: Level): boolean;
|
|
89
|
+
/** Drain every transport's buffered writes (e.g. the file transport) without closing them. */
|
|
90
|
+
flush(): Promise<void>;
|
|
91
|
+
/** Flush **and** close every transport (release timers/handles) — wire to a shutdown hook. */
|
|
92
|
+
close(): Promise<void>;
|
|
93
|
+
/** The effective level/format/timestamp (`level` reflects {@link setLevel}). */
|
|
94
|
+
readonly config: {
|
|
95
|
+
readonly level: Level;
|
|
96
|
+
readonly structured: boolean;
|
|
97
|
+
readonly timestamp: 'iso' | 'epoch';
|
|
98
|
+
};
|
|
99
|
+
/** Begin intercepting `console.*` (idempotent); returns a restore function. */
|
|
100
|
+
interceptConsole(): () => void;
|
|
101
|
+
/** Restore any console interception this logger installed (idempotent). */
|
|
102
|
+
restoreConsole(): void;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create a {@link Logger}.
|
|
106
|
+
*/
|
|
107
|
+
declare function createLogger(config?: LoggerConfig): Logger;
|
|
108
|
+
/** Emit a record at `level` on the default logger. */
|
|
109
|
+
declare const log: (level: Level, ...args: unknown[]) => void;
|
|
110
|
+
declare const debug: (...args: unknown[]) => void;
|
|
111
|
+
declare const info: (...args: unknown[]) => void;
|
|
112
|
+
declare const warn: (...args: unknown[]) => void;
|
|
113
|
+
declare const error: (...args: unknown[]) => void;
|
|
114
|
+
/** Stack trace context on the default logger (and tag promise rejections). */
|
|
115
|
+
declare const logWith: <R>(add: object, inner: () => R) => R;
|
|
116
|
+
/** The default logger's current trace context. */
|
|
117
|
+
declare const context: () => Readonly<Record<string, unknown>>;
|
|
118
|
+
/** Intercept `console.*` through the default logger; returns a restore function. */
|
|
119
|
+
declare const interceptConsole: () => (() => void);
|
|
120
|
+
/** Restore console interception installed by the default logger. */
|
|
121
|
+
declare const restoreConsole: () => void;
|
|
122
|
+
/** The default logger instance. */
|
|
123
|
+
declare const logger: Logger;
|
|
124
|
+
//#endregion
|
|
125
|
+
export { ConsoleLike, ConsoleTransportOptions, type ErrorCaptureConfig, type ErrorConfig, LOG_CONTEXT, type LazyLogValue, type Level, type LogRecord, Logger, LoggerConfig, type MaybePromise, type SanitizeOptions, type SerializedError, type Serializer, type Transport, consoleTransport, context, createLogger, createSanitizer, debug, deepEqual, error, getContext, info, interceptConsole, log, logMaybe, logWith, logger, merge, partialMask, resolveLogValue, restoreConsole, serializeError, warn };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { _ as partialMask, a as Level, c as SanitizeOptions, d as Transport, f as createSanitizer, g as merge, h as logMaybe, i as LazyLogValue, l as SerializedError, m as getContext, n as ErrorConfig, o as LogRecord, p as deepEqual, r as LOG_CONTEXT, s as MaybePromise, t as ErrorCaptureConfig, u as Serializer, v as resolveLogValue, y as serializeError } from "./internal.js";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
|
|
5
|
+
/** The minimal `console` surface the logger reads/intercepts (the global one, or your own). */
|
|
6
|
+
interface ConsoleLike {
|
|
7
|
+
log(...args: unknown[]): void;
|
|
8
|
+
info(...args: unknown[]): void;
|
|
9
|
+
debug(...args: unknown[]): void;
|
|
10
|
+
warn(...args: unknown[]): void;
|
|
11
|
+
error(...args: unknown[]): void;
|
|
12
|
+
}
|
|
13
|
+
/** Options for {@link consoleTransport}. */
|
|
14
|
+
interface ConsoleTransportOptions {
|
|
15
|
+
/** The console to **write through** — should be the original (pre-interception) console to avoid recursion. */
|
|
16
|
+
readonly console?: ConsoleLike;
|
|
17
|
+
/** Map a record level to a console method (default: error→error, warn→warn, debug→debug, else→log). */
|
|
18
|
+
readonly method?: (level: Level) => keyof ConsoleLike;
|
|
19
|
+
}
|
|
20
|
+
/** A {@link Transport} that writes the formatted line to a console. */
|
|
21
|
+
declare function consoleTransport(opts?: ConsoleTransportOptions): Transport;
|
|
22
|
+
/** Configuration for {@link createLogger}. */
|
|
23
|
+
interface LoggerConfig {
|
|
24
|
+
/** Minimum level emitted (default `'info'`). Logs below this are dropped before a record is built. */
|
|
25
|
+
readonly level?: Level;
|
|
26
|
+
/** Structured JSON output vs `[tms] level msg key=value` text (default `false` = text). */
|
|
27
|
+
readonly structured?: boolean;
|
|
28
|
+
/** Timestamp format — ISO string (default) or numeric epoch ms. */
|
|
29
|
+
readonly timestamp?: 'iso' | 'epoch';
|
|
30
|
+
/** Transports to write to (default: a single {@link consoleTransport} bound to the captured original console). */
|
|
31
|
+
readonly transports?: readonly Transport[];
|
|
32
|
+
/** Intercept global `console.*` immediately (default `false` — opt-in). */
|
|
33
|
+
readonly interceptConsole?: boolean;
|
|
34
|
+
/** `console` method → level mapping for interception (default {@link CONSOLE_LEVEL_MAP}). */
|
|
35
|
+
readonly consoleMap?: Readonly<Record<string, Level>>;
|
|
36
|
+
/** The console to read originals from / intercept (default the global `console`). */
|
|
37
|
+
readonly console?: ConsoleLike;
|
|
38
|
+
/** Error serialization config, including per-level overrides. */
|
|
39
|
+
readonly error?: ErrorConfig;
|
|
40
|
+
/**
|
|
41
|
+
* Final hook over the built record before it is formatted. Return a (possibly
|
|
42
|
+
* modified) record to log it — e.g. redact or add fields — or `null`/`undefined`
|
|
43
|
+
* to drop the log entirely. Runs **before** {@link sanitize}.
|
|
44
|
+
*/
|
|
45
|
+
readonly filter?: (record: LogRecord) => LogRecord | null | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Declarative redaction/truncation applied to every record (after {@link filter}): drop via a
|
|
48
|
+
* `filter` predicate, mask `sensitiveKeys`/`sensitiveValues`, and cap `maxStringLength` /
|
|
49
|
+
* `maxArrayLength`. Applies to direct logger calls **and** intercepted `console.*`. (Equivalent
|
|
50
|
+
* to passing `createSanitizer(opts)` as `filter`, but it composes after your own `filter`.)
|
|
51
|
+
*/
|
|
52
|
+
readonly sanitize?: SanitizeOptions;
|
|
53
|
+
/**
|
|
54
|
+
* Observe an error from the logging pipeline itself — a throwing `filter`, an
|
|
55
|
+
* unserializable record, or a transport whose `write` throws. Logging is **best-effort**:
|
|
56
|
+
* such an error never propagates to the caller (the line is dropped); this hook just lets
|
|
57
|
+
* you notice (e.g. count a metric, write to `stderr`). Off by default. It must not throw;
|
|
58
|
+
* if it does, the throw is ignored.
|
|
59
|
+
*/
|
|
60
|
+
readonly onError?: (err: unknown) => void;
|
|
61
|
+
/**
|
|
62
|
+
* Custom {@link Serializer}s for values the logger doesn't own (a `Request`, `URL`, `Buffer`,
|
|
63
|
+
* a third-party class…) — the predicate-style counterpart to a `toLOG`/`toJSON` hook. Each is
|
|
64
|
+
* tried in order at every depth; the first non-`undefined` result wins (taking precedence over
|
|
65
|
+
* the value's own `toLOG`/`toJSON`). They apply to direct calls and intercepted `console.*`.
|
|
66
|
+
*/
|
|
67
|
+
readonly serializers?: readonly Serializer[];
|
|
68
|
+
/** Clock injection for tests (default `() => Date.now()`). */
|
|
69
|
+
readonly now?: () => number;
|
|
70
|
+
}
|
|
71
|
+
/** A logger instance. */
|
|
72
|
+
interface Logger {
|
|
73
|
+
/** Emit a record at `level` from mixed primitive/object/Error args. No-op below the threshold. */
|
|
74
|
+
log(level: Level, ...args: unknown[]): void;
|
|
75
|
+
debug(...args: unknown[]): void;
|
|
76
|
+
info(...args: unknown[]): void;
|
|
77
|
+
warn(...args: unknown[]): void;
|
|
78
|
+
error(...args: unknown[]): void;
|
|
79
|
+
/** Merge `add` into the current trace context, run `inner` within it, and tag promise rejections with the context. */
|
|
80
|
+
logWith<R>(add: object, inner: () => R): R;
|
|
81
|
+
/** Snapshot of the current merged trace context (empty outside any `logWith`). */
|
|
82
|
+
context(): Readonly<Record<string, unknown>>;
|
|
83
|
+
/** Replace the transports at runtime. */
|
|
84
|
+
setTransports(transports: readonly Transport[]): void;
|
|
85
|
+
/** Change the minimum emitted level at runtime (e.g. bump to `'debug'` on demand). */
|
|
86
|
+
setLevel(level: Level): void;
|
|
87
|
+
/** Whether a record at `level` would be emitted at the current threshold — guard expensive prep. */
|
|
88
|
+
isLevelEnabled(level: Level): boolean;
|
|
89
|
+
/** Drain every transport's buffered writes (e.g. the file transport) without closing them. */
|
|
90
|
+
flush(): Promise<void>;
|
|
91
|
+
/** Flush **and** close every transport (release timers/handles) — wire to a shutdown hook. */
|
|
92
|
+
close(): Promise<void>;
|
|
93
|
+
/** The effective level/format/timestamp (`level` reflects {@link setLevel}). */
|
|
94
|
+
readonly config: {
|
|
95
|
+
readonly level: Level;
|
|
96
|
+
readonly structured: boolean;
|
|
97
|
+
readonly timestamp: 'iso' | 'epoch';
|
|
98
|
+
};
|
|
99
|
+
/** Begin intercepting `console.*` (idempotent); returns a restore function. */
|
|
100
|
+
interceptConsole(): () => void;
|
|
101
|
+
/** Restore any console interception this logger installed (idempotent). */
|
|
102
|
+
restoreConsole(): void;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create a {@link Logger}.
|
|
106
|
+
*/
|
|
107
|
+
declare function createLogger(config?: LoggerConfig): Logger;
|
|
108
|
+
/** Emit a record at `level` on the default logger. */
|
|
109
|
+
declare const log: (level: Level, ...args: unknown[]) => void;
|
|
110
|
+
declare const debug: (...args: unknown[]) => void;
|
|
111
|
+
declare const info: (...args: unknown[]) => void;
|
|
112
|
+
declare const warn: (...args: unknown[]) => void;
|
|
113
|
+
declare const error: (...args: unknown[]) => void;
|
|
114
|
+
/** Stack trace context on the default logger (and tag promise rejections). */
|
|
115
|
+
declare const logWith: <R>(add: object, inner: () => R) => R;
|
|
116
|
+
/** The default logger's current trace context. */
|
|
117
|
+
declare const context: () => Readonly<Record<string, unknown>>;
|
|
118
|
+
/** Intercept `console.*` through the default logger; returns a restore function. */
|
|
119
|
+
declare const interceptConsole: () => (() => void);
|
|
120
|
+
/** Restore console interception installed by the default logger. */
|
|
121
|
+
declare const restoreConsole: () => void;
|
|
122
|
+
/** The default logger instance. */
|
|
123
|
+
declare const logger: Logger;
|
|
124
|
+
//#endregion
|
|
125
|
+
export { ConsoleLike, ConsoleTransportOptions, type ErrorCaptureConfig, type ErrorConfig, LOG_CONTEXT, type LazyLogValue, type Level, type LogRecord, Logger, LoggerConfig, type MaybePromise, type SanitizeOptions, type SerializedError, type Serializer, type Transport, consoleTransport, context, createLogger, createSanitizer, debug, deepEqual, error, getContext, info, interceptConsole, log, logMaybe, logWith, logger, merge, partialMask, resolveLogValue, restoreConsole, serializeError, warn };
|