@sonisoft/now-sdk-ext-core 5.3.0 → 6.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 -21
- package/README.md +86 -3
- package/dist/comm/http/HTTPRequest.d.ts +12 -0
- package/dist/comm/http/RequestHandler.d.ts +13 -0
- package/dist/comm/http/RequestHandler.js +47 -0
- package/dist/comm/http/RequestHandler.js.map +1 -1
- package/dist/comm/http/ServiceNowProcessorRequest.d.ts +9 -2
- package/dist/comm/http/ServiceNowProcessorRequest.js +17 -5
- package/dist/comm/http/ServiceNowProcessorRequest.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/policy/Policy.d.ts +40 -0
- package/dist/policy/Policy.js +161 -0
- package/dist/policy/Policy.js.map +1 -0
- package/dist/policy/PolicyEnv.d.ts +46 -0
- package/dist/policy/PolicyEnv.js +92 -0
- package/dist/policy/PolicyEnv.js.map +1 -0
- package/dist/policy/PolicyRefusal.d.ts +17 -0
- package/dist/policy/PolicyRefusal.js +69 -0
- package/dist/policy/PolicyRefusal.js.map +1 -0
- package/dist/policy/PolicyTypes.d.ts +65 -0
- package/dist/policy/PolicyTypes.js +15 -0
- package/dist/policy/PolicyTypes.js.map +1 -0
- package/dist/policy/ScanScript.d.ts +22 -0
- package/dist/policy/ScanScript.js +171 -0
- package/dist/policy/ScanScript.js.map +1 -0
- package/dist/policy/internal/Classify.d.ts +16 -0
- package/dist/policy/internal/Classify.js +121 -0
- package/dist/policy/internal/Classify.js.map +1 -0
- package/dist/sn/Application.js +18 -8
- package/dist/sn/Application.js.map +1 -1
- package/dist/sn/BackgroundScriptExecutor.d.ts +12 -0
- package/dist/sn/BackgroundScriptExecutor.js +60 -1
- package/dist/sn/BackgroundScriptExecutor.js.map +1 -1
- package/dist/sn/amb/AMBClient.js +24 -11
- package/dist/sn/amb/AMBClient.js.map +1 -1
- package/dist/sn/amb/SubscriptionCommandSender.js +19 -2
- package/dist/sn/amb/SubscriptionCommandSender.js.map +1 -1
- package/dist/sn/amb/XMLHttpRequest.d.ts +1 -0
- package/dist/sn/amb/XMLHttpRequest.js +5 -1
- package/dist/sn/amb/XMLHttpRequest.js.map +1 -1
- package/dist/sn/atf/ATFTestExecutor.js +3 -1
- package/dist/sn/atf/ATFTestExecutor.js.map +1 -1
- package/dist/sn/scripttracer/ScriptTracer.js +6 -2
- package/dist/sn/scripttracer/ScriptTracer.js.map +1 -1
- package/dist/sn/syslog/SyslogReader.js +6 -1
- package/dist/sn/syslog/SyslogReader.js.map +1 -1
- package/dist/util/LogConfig.d.ts +83 -0
- package/dist/util/LogConfig.js +387 -0
- package/dist/util/LogConfig.js.map +1 -0
- package/dist/util/Logger.d.ts +40 -18
- package/dist/util/Logger.js +78 -84
- package/dist/util/Logger.js.map +1 -1
- package/dist/util/redact.d.ts +12 -0
- package/dist/util/redact.js +76 -0
- package/dist/util/redact.js.map +1 -1
- package/package.json +10 -9
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where logging goes, and whether it happens at all.
|
|
3
|
+
*
|
|
4
|
+
* The bug this exists for (NEX-3): `Logger` built four Winston File transports at
|
|
5
|
+
* hard-coded RELATIVE paths, with no console transport and no injectable destination.
|
|
6
|
+
* Winston's File transport mkdirs in its own constructor, so merely constructing a
|
|
7
|
+
* Logger created `./logs/` — in whatever directory the process happened to start in.
|
|
8
|
+
* For a published library that is the consumer's project directory; for the MCP server
|
|
9
|
+
* it is whatever cwd its client chose. There was no way to turn it off.
|
|
10
|
+
*
|
|
11
|
+
* Configuration is process-global rather than constructor-injected because there are
|
|
12
|
+
* ~43 field initializers of the form `private _logger = new Logger("FlowManager")`,
|
|
13
|
+
* none of which receive arguments. Threading options through them would mean changing
|
|
14
|
+
* every manager constructor. The consuming application configures once at boot; the
|
|
15
|
+
* library reads its own environment so that a Logger used BEFORE that call still
|
|
16
|
+
* behaves — which makes boot order an optimization rather than a correctness
|
|
17
|
+
* requirement, and is what lets this work under Jest.
|
|
18
|
+
*/
|
|
19
|
+
import * as winston from "winston";
|
|
20
|
+
import { homedir, tmpdir } from "os";
|
|
21
|
+
import { join } from "path";
|
|
22
|
+
import { redactValue, isSecretKey, redactMessage, REDACTED } from "./redact.js";
|
|
23
|
+
const { combine, timestamp, json, metadata, printf } = winston.format;
|
|
24
|
+
/** Directory name used under whichever per-user state root applies. */
|
|
25
|
+
const APP_DIR = "now-sdk-ext";
|
|
26
|
+
/** Winston's npm levels, which are the only levels the transports understand. */
|
|
27
|
+
const VALID_LEVELS = Object.keys(winston.config.npm.levels);
|
|
28
|
+
/**
|
|
29
|
+
* `trace` is not a winston level, but the CLI has always offered it. Left unmapped it
|
|
30
|
+
* does not merely fail validation: a transport with no explicit level compares against
|
|
31
|
+
* an undefined threshold and drops EVERY record, while level-pinned transports keep
|
|
32
|
+
* working. Partial and invisible, which is worse than rejecting it.
|
|
33
|
+
*/
|
|
34
|
+
const LEVEL_ALIASES = {
|
|
35
|
+
trace: "silly",
|
|
36
|
+
verbose: "verbose",
|
|
37
|
+
warning: "warn",
|
|
38
|
+
err: "error",
|
|
39
|
+
};
|
|
40
|
+
let explicit = {};
|
|
41
|
+
let resolved;
|
|
42
|
+
let root;
|
|
43
|
+
let epochCounter = 0;
|
|
44
|
+
const warnedOnce = new Set();
|
|
45
|
+
/** Resolves when `event` fires, and never rejects. */
|
|
46
|
+
function once(emitter, event) {
|
|
47
|
+
return new Promise((resolveOnce) => emitter.once(event, () => resolveOnce()));
|
|
48
|
+
}
|
|
49
|
+
function delay(ms) {
|
|
50
|
+
return new Promise((resolveDelay) => {
|
|
51
|
+
const timer = setTimeout(resolveDelay, ms);
|
|
52
|
+
// Must not hold the process open just because a flush is pending.
|
|
53
|
+
timer.unref?.();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Yields until the logger stream has no records left queued, bounded.
|
|
58
|
+
*
|
|
59
|
+
* A single `setImmediate` moves exactly one record through the Transform, so a burst
|
|
60
|
+
* logged in one tick needs one turn each.
|
|
61
|
+
*/
|
|
62
|
+
async function settle(turns) {
|
|
63
|
+
for (let i = 0; i < turns; i++) {
|
|
64
|
+
await new Promise((resolveTick) => setImmediate(resolveTick));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** True while a File transport still has bytes it has not handed to the OS. */
|
|
68
|
+
function fileTransportBusy(transport) {
|
|
69
|
+
const t = transport;
|
|
70
|
+
return Boolean(t._opening) || Boolean(t._drain) || (t._pendingSize ?? 0) > 0;
|
|
71
|
+
}
|
|
72
|
+
/** Complains to stderr at most once per distinct problem. */
|
|
73
|
+
function warnOnce(key, message) {
|
|
74
|
+
if (warnedOnce.has(key)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
warnedOnce.add(key);
|
|
78
|
+
process.stderr.write(`[now-sdk-ext] ${message}\n`);
|
|
79
|
+
}
|
|
80
|
+
/** Matches sn-credstore's `envFlag` exactly, so the two packages agree on truthiness. */
|
|
81
|
+
function envFlag(name) {
|
|
82
|
+
const value = process.env[name];
|
|
83
|
+
if (value === undefined) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return value !== "" && value !== "0" && value.toLowerCase() !== "false";
|
|
87
|
+
}
|
|
88
|
+
function normalizeLevel(level, source) {
|
|
89
|
+
if (!level) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
const lowered = level.trim().toLowerCase();
|
|
93
|
+
const mapped = LEVEL_ALIASES[lowered] ?? lowered;
|
|
94
|
+
if (!VALID_LEVELS.includes(mapped)) {
|
|
95
|
+
warnOnce(`level:${mapped}`, `ignoring unknown log level "${level}" from ${source}`);
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
return mapped;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The user's home directory, or undefined if there isn't a usable one.
|
|
102
|
+
*
|
|
103
|
+
* Reads the environment before falling back to `os.homedir()`, which is what homedir()
|
|
104
|
+
* itself does on both POSIX and Windows — so this is the same answer, reachable from a
|
|
105
|
+
* test. A daemon with no HOME gets "/" back, and `join("/", ".local", …)` is an EACCES
|
|
106
|
+
* waiting to happen on the first write.
|
|
107
|
+
*/
|
|
108
|
+
function resolveHome() {
|
|
109
|
+
let raw;
|
|
110
|
+
try {
|
|
111
|
+
raw = (process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME) ?? homedir();
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const trimmed = raw?.trim();
|
|
117
|
+
if (!trimmed || trimmed === "/" || trimmed === ".") {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return trimmed;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Per-user state directory for logs.
|
|
124
|
+
*
|
|
125
|
+
* XDG_STATE_HOME is honoured on every platform, not just Linux. That is deliberate: it
|
|
126
|
+
* makes the whole thing testable with one environment variable and no mocking, and it
|
|
127
|
+
* matches how sn-credstore resolves its own state.
|
|
128
|
+
*/
|
|
129
|
+
export function defaultLogDir() {
|
|
130
|
+
const xdg = process.env.XDG_STATE_HOME?.trim();
|
|
131
|
+
if (xdg) {
|
|
132
|
+
return join(xdg, APP_DIR, "logs");
|
|
133
|
+
}
|
|
134
|
+
const home = resolveHome();
|
|
135
|
+
if (!home) {
|
|
136
|
+
return join(tmpdir(), APP_DIR, "logs");
|
|
137
|
+
}
|
|
138
|
+
if (process.platform === "win32") {
|
|
139
|
+
const localAppData = process.env.LOCALAPPDATA?.trim() || join(home, "AppData", "Local");
|
|
140
|
+
return join(localAppData, APP_DIR, "Logs");
|
|
141
|
+
}
|
|
142
|
+
if (process.platform === "darwin") {
|
|
143
|
+
return join(home, "Library", "Logs", APP_DIR);
|
|
144
|
+
}
|
|
145
|
+
return join(home, ".local", "state", APP_DIR, "logs");
|
|
146
|
+
}
|
|
147
|
+
function resolve() {
|
|
148
|
+
if (resolved) {
|
|
149
|
+
return resolved;
|
|
150
|
+
}
|
|
151
|
+
const envDir = process.env.NEX_LOG_DIR?.trim() || undefined;
|
|
152
|
+
const envFile = envFlag("NEX_LOG_FILE");
|
|
153
|
+
const envLevel = normalizeLevel(process.env.NEX_LOG_LEVEL, "NEX_LOG_LEVEL");
|
|
154
|
+
const dir = explicit.dir ?? envDir ?? defaultLogDir();
|
|
155
|
+
// A directory alone implies enable. Without that, `--log-dir ./logs` produces
|
|
156
|
+
// nothing and looks like a bug in the flag rather than a missing second flag.
|
|
157
|
+
const impliedByDir = explicit.dir !== undefined || envDir !== undefined;
|
|
158
|
+
const file = explicit.file ?? envFile ?? (impliedByDir ? true : false);
|
|
159
|
+
const level = normalizeLevel(explicit.level, "configureLogging") ?? envLevel ?? "info";
|
|
160
|
+
const consoleLevel = normalizeLevel(explicit.consoleLevel, "configureLogging") ?? "warn";
|
|
161
|
+
resolved = Object.freeze({
|
|
162
|
+
file,
|
|
163
|
+
dir,
|
|
164
|
+
level,
|
|
165
|
+
console: explicit.console ?? true,
|
|
166
|
+
consoleLevel,
|
|
167
|
+
maxSizeBytes: explicit.maxSizeBytes ?? 10 * 1024 * 1024,
|
|
168
|
+
maxFiles: explicit.maxFiles ?? 5,
|
|
169
|
+
});
|
|
170
|
+
return resolved;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Strips credential material from every record.
|
|
174
|
+
*
|
|
175
|
+
* Applied as a format rather than fixed at each call site on purpose. There are ~40
|
|
176
|
+
* logging calls across src/, several of which pass whole request configs and session
|
|
177
|
+
* objects, and the set grows. Auditing call sites catches today's leaks and none of
|
|
178
|
+
* tomorrow's; a format in the pipeline catches both.
|
|
179
|
+
*
|
|
180
|
+
* The specific leak that motivated it: RequestHandler built `{auth: this._session}` and
|
|
181
|
+
* logged it at debug on every single request, writing live cookies and tokens to disk.
|
|
182
|
+
*/
|
|
183
|
+
const redactSecrets = winston.format((info) => {
|
|
184
|
+
if (typeof info.message === "string") {
|
|
185
|
+
info.message = redactMessage(info.message);
|
|
186
|
+
}
|
|
187
|
+
for (const key of Object.keys(info)) {
|
|
188
|
+
if (key === "level" || key === "message" || key === "timestamp" || key === "label") {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (isSecretKey(key)) {
|
|
192
|
+
info[key] = REDACTED;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
info[key] = redactValue(info[key]);
|
|
196
|
+
}
|
|
197
|
+
return info;
|
|
198
|
+
});
|
|
199
|
+
/** Human-shaped single line for stderr. */
|
|
200
|
+
const consoleLine = printf((info) => {
|
|
201
|
+
const meta = info.metadata;
|
|
202
|
+
const label = typeof info.label === "string" ? info.label : "-";
|
|
203
|
+
let tail = "";
|
|
204
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
205
|
+
try {
|
|
206
|
+
tail = ` ${JSON.stringify(meta)}`;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
tail = " [unserializable]";
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Both are `unknown` on the info object; stringify defensively rather than trusting
|
|
213
|
+
// a shape, because a caller can log anything.
|
|
214
|
+
const stamp = typeof info.timestamp === "string" ? info.timestamp : "";
|
|
215
|
+
const text = typeof info.message === "string" ? info.message : JSON.stringify(info.message);
|
|
216
|
+
return `${stamp} [${label}] ${info.level}: ${text}${tail}`;
|
|
217
|
+
});
|
|
218
|
+
function buildFileTransport(cfg) {
|
|
219
|
+
try {
|
|
220
|
+
return new winston.transports.File({
|
|
221
|
+
filename: join(cfg.dir, "nex.log"),
|
|
222
|
+
maxsize: cfg.maxSizeBytes,
|
|
223
|
+
maxFiles: cfg.maxFiles,
|
|
224
|
+
// Keep the newest data in nex.log, which is what `tail -f` users expect.
|
|
225
|
+
tailable: true,
|
|
226
|
+
format: combine(timestamp(), json()),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
catch (e) {
|
|
230
|
+
// mkdirSync runs inside the File transport constructor and precedes its own
|
|
231
|
+
// `lazy` handling, so EACCES/EROFS/ENOSPC lands here. Degrade to console rather
|
|
232
|
+
// than throwing out of whatever business call happened to log first.
|
|
233
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
234
|
+
warnOnce("filetransport", `file logging disabled: ${reason}`);
|
|
235
|
+
return undefined;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* The one winston logger for the process.
|
|
240
|
+
*
|
|
241
|
+
* Shared rather than per-`Logger` because rotation requires it: each File transport
|
|
242
|
+
* tracks its own size and rotates independently, so N transports on one path interleave
|
|
243
|
+
* renames and lose lines. It also fixes an fd leak — `ServiceNowRequest` is constructed
|
|
244
|
+
* per HTTP call, and each one used to open four more append streams that were never
|
|
245
|
+
* closed. That is where the 120 MB came from.
|
|
246
|
+
*/
|
|
247
|
+
export function getRootLogger() {
|
|
248
|
+
if (root) {
|
|
249
|
+
return root;
|
|
250
|
+
}
|
|
251
|
+
const cfg = resolve();
|
|
252
|
+
const transports = [];
|
|
253
|
+
if (cfg.file) {
|
|
254
|
+
const fileTransport = buildFileTransport(cfg);
|
|
255
|
+
if (fileTransport) {
|
|
256
|
+
transports.push(fileTransport);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Stream, not Console. transports.Console routes by a stderrLevels MAP and falls
|
|
260
|
+
// through to stdout for any level absent from it, so it is a denylist by omission —
|
|
261
|
+
// one added level and MCP's JSON-RPC framing on fd 1 is corrupted. Stream writes
|
|
262
|
+
// where it is told.
|
|
263
|
+
transports.push(new winston.transports.Stream({
|
|
264
|
+
stream: process.stderr,
|
|
265
|
+
level: cfg.consoleLevel,
|
|
266
|
+
silent: !cfg.console,
|
|
267
|
+
format: consoleLine,
|
|
268
|
+
}));
|
|
269
|
+
root = winston.createLogger({
|
|
270
|
+
level: cfg.level,
|
|
271
|
+
format: combine(
|
|
272
|
+
// First in the chain: redact before anything reshapes, nests, or serializes
|
|
273
|
+
// the entry, so no later format can capture a raw value.
|
|
274
|
+
redactSecrets(), timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), metadata({ fillExcept: ["message", "level", "timestamp", "label"] })),
|
|
275
|
+
// Never an empty transport array: winston console.error's the RAW info object
|
|
276
|
+
// when a logger has no transports, and it does so BEFORE the format chain runs,
|
|
277
|
+
// so redaction never happens. "Off" is a silent transport.
|
|
278
|
+
transports,
|
|
279
|
+
exitOnError: false,
|
|
280
|
+
});
|
|
281
|
+
return root;
|
|
282
|
+
}
|
|
283
|
+
/** Bumped whenever configuration changes, so live `Logger` facades pick up the new root. */
|
|
284
|
+
export function logEpoch() {
|
|
285
|
+
return epochCounter;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Sets logging options for the process. Call once, early, from the application that
|
|
289
|
+
* owns the entry point — not from a library.
|
|
290
|
+
*
|
|
291
|
+
* Unset fields keep whatever the environment or the defaults provide, so a consumer can
|
|
292
|
+
* set only what it knows about.
|
|
293
|
+
*/
|
|
294
|
+
export function configureLogging(options = {}) {
|
|
295
|
+
explicit = { ...explicit, ...options };
|
|
296
|
+
resolved = undefined;
|
|
297
|
+
const previous = root;
|
|
298
|
+
root = undefined;
|
|
299
|
+
epochCounter++;
|
|
300
|
+
if (previous) {
|
|
301
|
+
// Close rather than drop, or every reconfigure leaks a file stream.
|
|
302
|
+
try {
|
|
303
|
+
previous.close();
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// Closing is best-effort; a failure here must not break configuration.
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
export function getLogConfig() {
|
|
311
|
+
return resolve();
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Waits for buffered records to reach disk.
|
|
315
|
+
*
|
|
316
|
+
* Winston's File transport buffers, and `process.exit()` drops whatever is pending. A
|
|
317
|
+
* library cannot register `process.on('exit')` for this because that handler cannot be
|
|
318
|
+
* async, so the application calls this before exiting.
|
|
319
|
+
*/
|
|
320
|
+
export async function flushLogs() {
|
|
321
|
+
if (!root) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const current = root;
|
|
325
|
+
// Let the pipeline settle first, and do not remove this. A winston Logger is a
|
|
326
|
+
// Transform stream, and records written in the current tick have not reached the
|
|
327
|
+
// transports yet — calling end() straight after a .info() truncates the pipeline and
|
|
328
|
+
// those records are lost. The documented `logger.on('finish'); logger.end()` idiom
|
|
329
|
+
// silently drops the very last lines without this, which are exactly the lines
|
|
330
|
+
// anyone flushing before exit most wants. One turn moves roughly one record, so give
|
|
331
|
+
// the pipeline several before looking at what the transports still owe.
|
|
332
|
+
await settle(8);
|
|
333
|
+
// A File transport opens its file asynchronously and buffers writes until it does.
|
|
334
|
+
// When the transport was built lazily by the very call being flushed — the common
|
|
335
|
+
// case for a short CLI command — ending here would discard that buffer, so wait for
|
|
336
|
+
// the file to actually be open first.
|
|
337
|
+
const fileTransports = current.transports.filter((t) => t instanceof winston.transports.File);
|
|
338
|
+
// Then wait for what the transports still owe. `_pendingSize` is winston's own count
|
|
339
|
+
// of bytes written but not yet acknowledged, `_opening` means writes are queued
|
|
340
|
+
// behind the file open, `_drain` means the OS buffer is full (file.js:86-90,
|
|
341
|
+
// 129-135, 213-220). Probing for `_stream` instead does not work — it is assigned
|
|
342
|
+
// synchronously inside open(), so it is already set while writes are still queued.
|
|
343
|
+
const deadline = Date.now() + 1500;
|
|
344
|
+
while (Date.now() < deadline && fileTransports.some(fileTransportBusy)) {
|
|
345
|
+
await delay(10);
|
|
346
|
+
}
|
|
347
|
+
await settle(2);
|
|
348
|
+
// The logger's own `finish` is not enough. It fires when the logger stream ends,
|
|
349
|
+
// which is before each File transport has drained to disk — so a flush that waits
|
|
350
|
+
// only on the logger returns with the file still empty.
|
|
351
|
+
const waiters = [
|
|
352
|
+
once(current, "finish"),
|
|
353
|
+
...fileTransports.map((t) => once(t, "finish")),
|
|
354
|
+
];
|
|
355
|
+
current.end();
|
|
356
|
+
// Bounded: a transport with nothing buffered may never emit, and a flush that can
|
|
357
|
+
// hang is worse than one that returns early.
|
|
358
|
+
await Promise.race([Promise.all(waiters), delay(2000)]);
|
|
359
|
+
if (root === current) {
|
|
360
|
+
root = undefined;
|
|
361
|
+
// Bump the epoch as well, exactly as configureLogging and resetLoggingForTests
|
|
362
|
+
// do. Dropping `root` alone is not enough: a Logger that already cached this
|
|
363
|
+
// instance sees an unchanged epoch, keeps the reference, and its next call is a
|
|
364
|
+
// write to an ended stream — which THROWS ("write after end"), losing the whole
|
|
365
|
+
// call rather than just the line. flushLogs is public API meant to be callable
|
|
366
|
+
// mid-process, not only on the way out.
|
|
367
|
+
epochCounter++;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/** Drops all configuration and the built logger. Test seam. */
|
|
371
|
+
export function resetLoggingForTests() {
|
|
372
|
+
explicit = {};
|
|
373
|
+
resolved = undefined;
|
|
374
|
+
const previous = root;
|
|
375
|
+
root = undefined;
|
|
376
|
+
epochCounter++;
|
|
377
|
+
warnedOnce.clear();
|
|
378
|
+
if (previous) {
|
|
379
|
+
try {
|
|
380
|
+
previous.close();
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
// best effort
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=LogConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LogConfig.js","sourceRoot":"","sources":["../../src/util/LogConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE7E,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;AAEtE,uEAAuE;AACvE,MAAM,OAAO,GAAG,aAAa,CAAC;AAE9B,iFAAiF;AACjF,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,aAAa,GAAqC;IACpD,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,MAAM;IACf,GAAG,EAAE,OAAO;CACf,CAAC;AA6BF,IAAI,QAAQ,GAAe,EAAE,CAAC;AAC9B,IAAI,QAAuC,CAAC;AAC5C,IAAI,IAAgC,CAAC;AACrC,IAAI,YAAY,GAAG,CAAC,CAAC;AACrB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;AAErC,sDAAsD;AACtD,SAAS,IAAI,CAAC,OAAyD,EAAE,KAAa;IAClF,OAAO,IAAI,OAAO,CAAO,CAAC,WAAW,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACrB,OAAO,IAAI,OAAO,CAAO,CAAC,YAAY,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAC3C,kEAAkE;QAClE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,MAAM,CAAC,KAAa;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,OAAO,CAAO,CAAC,WAAW,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;IACxE,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,SAAS,iBAAiB,CAAC,SAAkB;IACzC,MAAM,CAAC,GAAG,SAA4E,CAAC;IACvF,OAAO,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AACjF,CAAC;AAED,6DAA6D;AAC7D,SAAS,QAAQ,CAAC,GAAW,EAAE,OAAe;IAC1C,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO;IACX,CAAC;IACD,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,IAAI,CAAC,CAAC;AACvD,CAAC;AAED,yFAAyF;AACzF,SAAS,OAAO,CAAC,IAAY;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,OAAO,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC;AAC5E,CAAC;AAED,SAAS,cAAc,CAAC,KAAyB,EAAE,MAAc;IAC7D,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC;IACjD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,QAAQ,CAAC,SAAS,MAAM,EAAE,EAAE,+BAA+B,KAAK,UAAU,MAAM,EAAE,CAAC,CAAC;QACpF,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,WAAW;IAChB,IAAI,GAAuB,CAAC;IAC5B,IAAI,CAAC;QACD,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;IACnG,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;QACjD,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa;IACzB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAI,GAAG,EAAE,CAAC;QACN,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QACxF,OAAO,IAAI,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,OAAO;IACZ,IAAI,QAAQ,EAAE,CAAC;QACX,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IAC5D,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;IAE5E,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,IAAI,MAAM,IAAI,aAAa,EAAE,CAAC;IAEtD,8EAA8E;IAC9E,8EAA8E;IAC9E,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,CAAC;IACxE,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAEvE,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC,IAAI,QAAQ,IAAI,MAAM,CAAC;IACvF,MAAM,YAAY,GACd,cAAc,CAAC,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC,IAAI,MAAM,CAAC;IAExE,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QACrB,IAAI;QACJ,GAAG;QACH,KAAK;QACL,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,IAAI;QACjC,YAAY;QACZ,YAAY,EAAE,QAAQ,CAAC,YAAY,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI;QACvD,QAAQ,EAAE,QAAQ,CAAC,QAAQ,IAAI,CAAC;KACnC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;IAC1C,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YACjF,SAAS;QACb,CAAC;QACD,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,IAAgC,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;YAClD,SAAS;QACb,CAAC;QACA,IAAgC,CAAC,GAAG,CAAC,GAAG,WAAW,CAC/C,IAAgC,CAAC,GAAG,CAAC,CACzC,CAAC;IACN,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC,CAAC,CAAC;AAEH,2CAA2C;AAC3C,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;IAChC,MAAM,IAAI,GAAG,IAAI,CAAC,QAA+C,CAAC;IAClE,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IAChE,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC;YACD,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACL,IAAI,GAAG,mBAAmB,CAAC;QAC/B,CAAC;IACL,CAAC;IACD,oFAAoF;IACpF,8CAA8C;IAC9C,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5F,OAAO,GAAG,KAAK,KAAK,KAAK,KAAK,IAAI,CAAC,KAAK,KAAK,IAAI,GAAG,IAAI,EAAE,CAAC;AAC/D,CAAC,CAAC,CAAC;AAEH,SAAS,kBAAkB,CAAC,GAAsB;IAC9C,IAAI,CAAC;QACD,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YAC/B,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC;YAClC,OAAO,EAAE,GAAG,CAAC,YAAY;YACzB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,yEAAyE;YACzE,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC;SACvC,CAAC,CAAC;IACP,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,4EAA4E;QAC5E,gFAAgF;QAChF,qEAAqE;QACrE,MAAM,MAAM,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1D,QAAQ,CAAC,eAAe,EAAE,0BAA0B,MAAM,EAAE,CAAC,CAAC;QAC9D,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa;IACzB,IAAI,IAAI,EAAE,CAAC;QACP,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,MAAM,UAAU,GAAwB,EAAE,CAAC;IAE3C,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,aAAa,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,aAAa,EAAE,CAAC;YAChB,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;IACL,CAAC;IAED,iFAAiF;IACjF,oFAAoF;IACpF,iFAAiF;IACjF,oBAAoB;IACpB,UAAU,CAAC,IAAI,CACX,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,GAAG,CAAC,YAAY;QACvB,MAAM,EAAE,CAAC,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,WAAW;KACtB,CAAC,CACL,CAAC;IAEF,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;QACxB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,MAAM,EAAE,OAAO;QACX,4EAA4E;QAC5E,yDAAyD;QACzD,aAAa,EAAE,EACf,SAAS,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,EAC5C,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,CACvE;QACD,8EAA8E;QAC9E,gFAAgF;QAChF,2DAA2D;QAC3D,UAAU;QACV,WAAW,EAAE,KAAK;KACrB,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,QAAQ;IACpB,OAAO,YAAY,CAAC;AACxB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAsB,EAAE;IACrD,QAAQ,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;IACvC,QAAQ,GAAG,SAAS,CAAC;IACrB,MAAM,QAAQ,GAAG,IAAI,CAAC;IACtB,IAAI,GAAG,SAAS,CAAC;IACjB,YAAY,EAAE,CAAC;IACf,IAAI,QAAQ,EAAE,CAAC;QACX,oEAAoE;QACpE,IAAI,CAAC;YACD,QAAQ,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACL,uEAAuE;QAC3E,CAAC;IACL,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY;IACxB,OAAO,OAAO,EAAE,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO;IACX,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC;IAErB,+EAA+E;IAC/E,iFAAiF;IACjF,qFAAqF;IACrF,mFAAmF;IACnF,+EAA+E;IAC/E,qFAAqF;IACrF,wEAAwE;IACxE,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC;IAEhB,mFAAmF;IACnF,kFAAkF;IAClF,oFAAoF;IACpF,sCAAsC;IACtC,MAAM,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAC5C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,OAAO,CAAC,UAAU,CAAC,IAAI,CAC9C,CAAC;IACF,qFAAqF;IACrF,gFAAgF;IAChF,6EAA6E;IAC7E,kFAAkF;IAClF,mFAAmF;IACnF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACnC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,IAAI,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACrE,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;IACD,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC;IAEhB,iFAAiF;IACjF,kFAAkF;IAClF,wDAAwD;IACxD,MAAM,OAAO,GAAoB;QAC7B,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC;QACvB,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;KAClD,CAAC;IAEF,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,kFAAkF;IAClF,6CAA6C;IAC7C,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAExD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACnB,IAAI,GAAG,SAAS,CAAC;QACjB,+EAA+E;QAC/E,6EAA6E;QAC7E,gFAAgF;QAChF,gFAAgF;QAChF,+EAA+E;QAC/E,wCAAwC;QACxC,YAAY,EAAE,CAAC;IACnB,CAAC;AACL,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB;IAChC,QAAQ,GAAG,EAAE,CAAC;IACd,QAAQ,GAAG,SAAS,CAAC;IACrB,MAAM,QAAQ,GAAG,IAAI,CAAC;IACtB,IAAI,GAAG,SAAS,CAAC;IACjB,YAAY,EAAE,CAAC;IACf,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,IAAI,QAAQ,EAAE,CAAC;QACX,IAAI,CAAC;YACD,QAAQ,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACL,cAAc;QAClB,CAAC;IACL,CAAC;AACL,CAAC"}
|
package/dist/util/Logger.d.ts
CHANGED
|
@@ -1,33 +1,55 @@
|
|
|
1
1
|
import * as winston from "winston";
|
|
2
|
+
/**
|
|
3
|
+
* A named handle onto the process-wide logger.
|
|
4
|
+
*
|
|
5
|
+
* This used to build its own winston logger with four File transports per instance. It
|
|
6
|
+
* no longer builds anything: there are ~43 of these across the codebase, and
|
|
7
|
+
* `ServiceNowRequest` is constructed per HTTP call, so each request was opening four
|
|
8
|
+
* more never-closed append streams. That is where the 120 MB of logs came from, and it
|
|
9
|
+
* also made rotation impossible — File transports track size independently, so several
|
|
10
|
+
* on one path interleave renames and lose lines.
|
|
11
|
+
*
|
|
12
|
+
* Destination, level, and rotation now live in LogConfig and are set once by the
|
|
13
|
+
* application. See `configureLogging`.
|
|
14
|
+
*/
|
|
2
15
|
export declare class Logger {
|
|
16
|
+
_labelName: string;
|
|
17
|
+
/** Set only by `setLogger`. Overrides the shared root for this instance. */
|
|
18
|
+
private _override?;
|
|
19
|
+
private _cached?;
|
|
20
|
+
private _epochSeen;
|
|
3
21
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* ~40 logging calls across src/, several of which pass whole request configs and
|
|
8
|
-
* session objects, and the set grows. Auditing call sites catches today's leaks
|
|
9
|
-
* and none of tomorrow's; a format in the pipeline catches both.
|
|
10
|
-
*
|
|
11
|
-
* The specific leak that motivated it: RequestHandler built `{auth: this._session}`
|
|
12
|
-
* and logged it at debug on every single request, writing live cookies and tokens
|
|
13
|
-
* to logs/app-debug.log.
|
|
22
|
+
* @param labelName Appears as `label` on every record from this instance.
|
|
23
|
+
* @param level Ignored. Kept so existing call sites still compile.
|
|
24
|
+
* @deprecated Pass the level to `configureLogging` instead — it applies process-wide.
|
|
14
25
|
*/
|
|
15
|
-
static redactSecrets: winston.Logform.FormatWrap;
|
|
16
|
-
static errorFilter: winston.Logform.FormatWrap;
|
|
17
|
-
static infoFilter: winston.Logform.FormatWrap;
|
|
18
|
-
static debugFilter: winston.Logform.FormatWrap;
|
|
19
|
-
_labelName: string;
|
|
20
|
-
_localLogger: winston.Logger;
|
|
21
|
-
_logLevel: string;
|
|
22
26
|
constructor(labelName: string, level?: string);
|
|
27
|
+
/** Replaces the underlying winston logger for this instance only. Test seam. */
|
|
23
28
|
setLogger(logger: winston.Logger): void;
|
|
24
29
|
getLabel(): string;
|
|
25
|
-
|
|
30
|
+
/**
|
|
31
|
+
* @deprecated The `level` argument the constructor accepts is ignored; use
|
|
32
|
+
* `configureLogging({level})`.
|
|
33
|
+
*/
|
|
26
34
|
static createLogger(labelName: string): Logger;
|
|
35
|
+
/** Resolves the shared root, rebuilding the cached reference if config changed. */
|
|
36
|
+
private root;
|
|
37
|
+
/**
|
|
38
|
+
* Attaches this instance's label to the record.
|
|
39
|
+
*
|
|
40
|
+
* The label used to be a winston format bound to a per-instance logger. With one
|
|
41
|
+
* shared root it has to travel with the call. Callers pass all sorts of things as
|
|
42
|
+
* `metadata`, so a non-object is nested rather than spread — spreading a string
|
|
43
|
+
* would scatter it across numeric keys.
|
|
44
|
+
*/
|
|
45
|
+
private meta;
|
|
27
46
|
debug(message: string, metadata?: unknown): void;
|
|
28
47
|
info(message: string, metadata?: unknown): void;
|
|
29
48
|
error(message: string, metadata?: unknown): void;
|
|
30
49
|
warn(message: string, metadata?: unknown): void;
|
|
50
|
+
verbose(message: string, metadata?: unknown): void;
|
|
51
|
+
http(message: string, metadata?: unknown): void;
|
|
52
|
+
silly(message: string, metadata?: unknown): void;
|
|
31
53
|
addInfoMessage(message: string, metadata?: unknown): void;
|
|
32
54
|
addErrorMessage(message: string, metadata?: unknown): void;
|
|
33
55
|
addWarnMessage(message: string, metadata?: unknown): void;
|
package/dist/util/Logger.js
CHANGED
|
@@ -1,115 +1,109 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { getRootLogger, logEpoch } from "./LogConfig.js";
|
|
2
|
+
/**
|
|
3
|
+
* A named handle onto the process-wide logger.
|
|
4
|
+
*
|
|
5
|
+
* This used to build its own winston logger with four File transports per instance. It
|
|
6
|
+
* no longer builds anything: there are ~43 of these across the codebase, and
|
|
7
|
+
* `ServiceNowRequest` is constructed per HTTP call, so each request was opening four
|
|
8
|
+
* more never-closed append streams. That is where the 120 MB of logs came from, and it
|
|
9
|
+
* also made rotation impossible — File transports track size independently, so several
|
|
10
|
+
* on one path interleave renames and lose lines.
|
|
11
|
+
*
|
|
12
|
+
* Destination, level, and rotation now live in LogConfig and are set once by the
|
|
13
|
+
* application. See `configureLogging`.
|
|
14
|
+
*/
|
|
5
15
|
export class Logger {
|
|
16
|
+
_labelName;
|
|
17
|
+
/** Set only by `setLogger`. Overrides the shared root for this instance. */
|
|
18
|
+
_override;
|
|
19
|
+
_cached;
|
|
20
|
+
_epochSeen = -1;
|
|
6
21
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* ~40 logging calls across src/, several of which pass whole request configs and
|
|
11
|
-
* session objects, and the set grows. Auditing call sites catches today's leaks
|
|
12
|
-
* and none of tomorrow's; a format in the pipeline catches both.
|
|
13
|
-
*
|
|
14
|
-
* The specific leak that motivated it: RequestHandler built `{auth: this._session}`
|
|
15
|
-
* and logged it at debug on every single request, writing live cookies and tokens
|
|
16
|
-
* to logs/app-debug.log.
|
|
22
|
+
* @param labelName Appears as `label` on every record from this instance.
|
|
23
|
+
* @param level Ignored. Kept so existing call sites still compile.
|
|
24
|
+
* @deprecated Pass the level to `configureLogging` instead — it applies process-wide.
|
|
17
25
|
*/
|
|
18
|
-
|
|
19
|
-
for (const key of Object.keys(info)) {
|
|
20
|
-
if (key === "level" || key === "message" || key === "timestamp" || key === "label") {
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
if (isSecretKey(key)) {
|
|
24
|
-
info[key] = REDACTED;
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
info[key] = redactValue(info[key]);
|
|
28
|
-
}
|
|
29
|
-
return info;
|
|
30
|
-
});
|
|
31
|
-
static errorFilter = winston.format((info) => {
|
|
32
|
-
return info.level === "error" ? info : false;
|
|
33
|
-
});
|
|
34
|
-
static infoFilter = winston.format((info) => {
|
|
35
|
-
return info.level === "info" ? info : false;
|
|
36
|
-
});
|
|
37
|
-
static debugFilter = winston.format((info) => {
|
|
38
|
-
return info.level === "debug" ? info : false;
|
|
39
|
-
});
|
|
40
|
-
_labelName;
|
|
41
|
-
_localLogger;
|
|
42
|
-
_logLevel;
|
|
43
|
-
constructor(labelName, level = "info") {
|
|
26
|
+
constructor(labelName, level) {
|
|
44
27
|
this._labelName = labelName;
|
|
45
|
-
|
|
46
|
-
this.initLogger();
|
|
28
|
+
void level;
|
|
47
29
|
}
|
|
30
|
+
/** Replaces the underlying winston logger for this instance only. Test seam. */
|
|
48
31
|
setLogger(logger) {
|
|
49
|
-
this.
|
|
32
|
+
this._override = logger;
|
|
50
33
|
}
|
|
51
34
|
getLabel() {
|
|
52
35
|
return this._labelName;
|
|
53
36
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// First in the chain: redact before anything reshapes, nests, or
|
|
59
|
-
// serializes the entry, so no later format can capture a raw value.
|
|
60
|
-
Logger.redactSecrets(), label({ label: this._labelName }), timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
|
61
|
-
// Format the metadata object
|
|
62
|
-
metadata({ fillExcept: ["message", "level", "timestamp", "label"] })),
|
|
63
|
-
transports: [
|
|
64
|
-
new transports.File({
|
|
65
|
-
filename: "logs/combined.log",
|
|
66
|
-
format: format.combine(timestamp(), format.json())
|
|
67
|
-
}),
|
|
68
|
-
new transports.File({
|
|
69
|
-
filename: "logs/app-error.log",
|
|
70
|
-
level: "error",
|
|
71
|
-
format: combine(Logger.errorFilter(), timestamp(), json()),
|
|
72
|
-
}),
|
|
73
|
-
new transports.File({
|
|
74
|
-
filename: "logs/app-info.log",
|
|
75
|
-
level: "info",
|
|
76
|
-
format: combine(Logger.infoFilter(), timestamp(), json()),
|
|
77
|
-
}),
|
|
78
|
-
new transports.File({
|
|
79
|
-
filename: "logs/app-debug.log",
|
|
80
|
-
level: "debug",
|
|
81
|
-
format: combine(Logger.debugFilter(), timestamp(), json()),
|
|
82
|
-
}),
|
|
83
|
-
],
|
|
84
|
-
exitOnError: false
|
|
85
|
-
});
|
|
86
|
-
}
|
|
37
|
+
/**
|
|
38
|
+
* @deprecated The `level` argument the constructor accepts is ignored; use
|
|
39
|
+
* `configureLogging({level})`.
|
|
40
|
+
*/
|
|
87
41
|
static createLogger(labelName) {
|
|
88
42
|
return new Logger(labelName);
|
|
89
43
|
}
|
|
44
|
+
/** Resolves the shared root, rebuilding the cached reference if config changed. */
|
|
45
|
+
root() {
|
|
46
|
+
if (this._override) {
|
|
47
|
+
return this._override;
|
|
48
|
+
}
|
|
49
|
+
if (this._epochSeen !== logEpoch()) {
|
|
50
|
+
this._cached = getRootLogger();
|
|
51
|
+
this._epochSeen = logEpoch();
|
|
52
|
+
}
|
|
53
|
+
return this._cached;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Attaches this instance's label to the record.
|
|
57
|
+
*
|
|
58
|
+
* The label used to be a winston format bound to a per-instance logger. With one
|
|
59
|
+
* shared root it has to travel with the call. Callers pass all sorts of things as
|
|
60
|
+
* `metadata`, so a non-object is nested rather than spread — spreading a string
|
|
61
|
+
* would scatter it across numeric keys.
|
|
62
|
+
*/
|
|
63
|
+
meta(metadata) {
|
|
64
|
+
if (metadata === undefined || metadata === null) {
|
|
65
|
+
return { label: this._labelName };
|
|
66
|
+
}
|
|
67
|
+
if (typeof metadata === "object" && !Array.isArray(metadata)) {
|
|
68
|
+
// Label last, deliberately. Metadata objects here are assembled ad hoc and
|
|
69
|
+
// grow over time; a caller key named `label` would otherwise misattribute
|
|
70
|
+
// the record to a component that never emitted it.
|
|
71
|
+
return { ...metadata, label: this._labelName };
|
|
72
|
+
}
|
|
73
|
+
return { label: this._labelName, meta: metadata };
|
|
74
|
+
}
|
|
90
75
|
debug(message, metadata) {
|
|
91
|
-
this.
|
|
76
|
+
this.root().debug(message, this.meta(metadata));
|
|
92
77
|
}
|
|
93
78
|
info(message, metadata) {
|
|
94
|
-
this.
|
|
79
|
+
this.root().info(message, this.meta(metadata));
|
|
95
80
|
}
|
|
96
81
|
error(message, metadata) {
|
|
97
|
-
this.
|
|
82
|
+
this.root().error(message, this.meta(metadata));
|
|
98
83
|
}
|
|
99
84
|
warn(message, metadata) {
|
|
100
|
-
this.
|
|
85
|
+
this.root().warn(message, this.meta(metadata));
|
|
86
|
+
}
|
|
87
|
+
verbose(message, metadata) {
|
|
88
|
+
this.root().verbose(message, this.meta(metadata));
|
|
89
|
+
}
|
|
90
|
+
http(message, metadata) {
|
|
91
|
+
this.root().http(message, this.meta(metadata));
|
|
92
|
+
}
|
|
93
|
+
silly(message, metadata) {
|
|
94
|
+
this.root().silly(message, this.meta(metadata));
|
|
101
95
|
}
|
|
102
96
|
addInfoMessage(message, metadata) {
|
|
103
|
-
this.
|
|
97
|
+
this.info(message, metadata);
|
|
104
98
|
}
|
|
105
99
|
addErrorMessage(message, metadata) {
|
|
106
|
-
this.
|
|
100
|
+
this.error(message, metadata);
|
|
107
101
|
}
|
|
108
102
|
addWarnMessage(message, metadata) {
|
|
109
|
-
this.
|
|
103
|
+
this.warn(message, metadata);
|
|
110
104
|
}
|
|
111
105
|
successful(message, metadata) {
|
|
112
|
-
this.
|
|
106
|
+
this.info(message, metadata);
|
|
113
107
|
}
|
|
114
108
|
}
|
|
115
109
|
//# sourceMappingURL=Logger.js.map
|