loggily 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -221
- package/dist/context.d.mts +2 -2
- package/dist/context.d.mts.map +1 -1
- package/dist/context.mjs +3 -3
- package/dist/context.mjs.map +1 -1
- package/dist/{core-B3pox577.mjs → core-Byd3DY71.mjs} +297 -47
- package/dist/core-Byd3DY71.mjs.map +1 -0
- package/dist/{core-Dm2PQUoS.d.mts → core-DHB4KaG1.d.mts} +74 -5
- package/dist/core-DHB4KaG1.d.mts.map +1 -0
- package/dist/{file-writer-DtaY8Njt.d.mts → file-writer-BhJzFNKE.d.mts} +10 -3
- package/dist/file-writer-BhJzFNKE.d.mts.map +1 -0
- package/dist/index.browser.d.mts +4 -4
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.mjs +1 -1
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/metrics.d.mts +1 -1
- package/dist/metrics.mjs.map +1 -1
- package/dist/otel.d.mts +1 -1
- package/dist/{pipeline-Cl9-wCmt.d.mts → pipeline-D0omS7eF.d.mts} +14 -2
- package/dist/pipeline-D0omS7eF.d.mts.map +1 -0
- package/dist/worker.d.mts +2 -2
- package/dist/worker.d.mts.map +1 -1
- package/dist/worker.mjs +1 -1
- package/dist/worker.mjs.map +1 -1
- package/package.json +5 -2
- package/dist/core-B3pox577.mjs.map +0 -1
- package/dist/core-Dm2PQUoS.d.mts.map +0 -1
- package/dist/file-writer-DtaY8Njt.d.mts.map +0 -1
- package/dist/pipeline-Cl9-wCmt.d.mts.map +0 -1
|
@@ -49,15 +49,21 @@ const colors = {
|
|
|
49
49
|
function createFileWriter(filePath, options = {}) {
|
|
50
50
|
const bufferSize = options.bufferSize ?? 4096;
|
|
51
51
|
const flushInterval = options.flushInterval ?? 100;
|
|
52
|
+
const fs = options.__fs ?? {
|
|
53
|
+
openSync,
|
|
54
|
+
writeSync,
|
|
55
|
+
closeSync
|
|
56
|
+
};
|
|
52
57
|
let buffer = "";
|
|
53
58
|
let fd = null;
|
|
54
59
|
let timer = null;
|
|
55
60
|
let closed = false;
|
|
56
|
-
fd = openSync(filePath, "a");
|
|
61
|
+
fd = fs.openSync(filePath, "a");
|
|
57
62
|
/** Flush buffer contents to disk synchronously */
|
|
58
63
|
function flush() {
|
|
59
64
|
if (buffer.length === 0 || fd === null) return;
|
|
60
|
-
|
|
65
|
+
const data = buffer;
|
|
66
|
+
fs.writeSync(fd, data);
|
|
61
67
|
buffer = "";
|
|
62
68
|
}
|
|
63
69
|
timer = setInterval(flush, flushInterval);
|
|
@@ -82,7 +88,7 @@ function createFileWriter(filePath, options = {}) {
|
|
|
82
88
|
flush();
|
|
83
89
|
} catch {} finally {
|
|
84
90
|
if (fd !== null) {
|
|
85
|
-
closeSync(fd);
|
|
91
|
+
fs.closeSync(fd);
|
|
86
92
|
fd = null;
|
|
87
93
|
}
|
|
88
94
|
process.removeListener("exit", exitHandler);
|
|
@@ -149,7 +155,8 @@ function resetIdCounters() {
|
|
|
149
155
|
*
|
|
150
156
|
* @example
|
|
151
157
|
* ```typescript
|
|
152
|
-
* const span = log.span("http-request")
|
|
158
|
+
* const span = log.span?.("http-request")
|
|
159
|
+
* if (!span) return
|
|
153
160
|
* const header = traceparent(span.spanData)
|
|
154
161
|
* // → "00-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6-1a2b3c4d5e6f7a8b-01"
|
|
155
162
|
* fetch(url, { headers: { traceparent: header } })
|
|
@@ -195,6 +202,211 @@ function shouldSample() {
|
|
|
195
202
|
return Math.random() < sampleRate;
|
|
196
203
|
}
|
|
197
204
|
//#endregion
|
|
205
|
+
//#region src/console-sinks.ts
|
|
206
|
+
/**
|
|
207
|
+
* Console sinks — runtime-aware structured output to console.
|
|
208
|
+
*
|
|
209
|
+
* Two sinks, one contract: `(event: Event) => void`. They do NOT pre-format
|
|
210
|
+
* events into a single ANSI string. Instead they spread structured arguments
|
|
211
|
+
* to `console.*` so the platform can render rich output:
|
|
212
|
+
*
|
|
213
|
+
* Terminal (Node / Bun):
|
|
214
|
+
* console.info(ansiPrefix, message, ...userArgs)
|
|
215
|
+
* — util.format keeps objects inspectable in devtools
|
|
216
|
+
*
|
|
217
|
+
* Browser (Chrome / Firefox / Safari DevTools):
|
|
218
|
+
* console.info("%c<level> %c<namespace>", levelCss, nsCss, message, ...userArgs)
|
|
219
|
+
* — DevTools renders colored prefix and keeps every user arg as an
|
|
220
|
+
* expandable, clickable object.
|
|
221
|
+
*
|
|
222
|
+
* Source-location preservation:
|
|
223
|
+
* We call `console.<level>(...)` from arrow-function sinks. DevTools attribute
|
|
224
|
+
* the log line to the caller's frame, not this file, as long as no wrapper
|
|
225
|
+
* closes over a bound console reference. `Function.prototype.bind.call(console.info, ...)`
|
|
226
|
+
* works too but defeats `vi.spyOn(console, 'info')` because bind captures
|
|
227
|
+
* the function at bind time. Plain arrow functions re-read `console.info`
|
|
228
|
+
* on each call — mockable AND location-preserving.
|
|
229
|
+
*
|
|
230
|
+
* The sinks consume `event.userArgs` (raw user-supplied data/errors) when
|
|
231
|
+
* present, falling back to `event.props` so they still work with code paths
|
|
232
|
+
* that have not yet been migrated.
|
|
233
|
+
*/
|
|
234
|
+
/**
|
|
235
|
+
* True when running inside a browser-like environment. We check for the
|
|
236
|
+
* presence of a `window` with `document` — the Node DOM test env (jsdom)
|
|
237
|
+
* also matches, but that is the correct behaviour for DevTools-style output.
|
|
238
|
+
*/
|
|
239
|
+
function isBrowserRuntime() {
|
|
240
|
+
return typeof globalThis?.window !== "undefined" && typeof globalThis.document !== "undefined";
|
|
241
|
+
}
|
|
242
|
+
function timeStr(time) {
|
|
243
|
+
return new Date(time).toISOString().split("T")[1]?.split(".")[0] ?? "";
|
|
244
|
+
}
|
|
245
|
+
function levelLabel(level) {
|
|
246
|
+
switch (level) {
|
|
247
|
+
case "trace": return "TRACE";
|
|
248
|
+
case "debug": return "DEBUG";
|
|
249
|
+
case "info": return "INFO";
|
|
250
|
+
case "warn": return "WARN";
|
|
251
|
+
case "error": return "ERROR";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Return the raw user-supplied data attached to the event, in call order.
|
|
256
|
+
* Prefers the explicit `userArgs` field (new path). Falls back to `props`
|
|
257
|
+
* (coerced to a single trailing object) for events emitted by older code or
|
|
258
|
+
* by `writeSpan`. Filters out `undefined` entries.
|
|
259
|
+
*/
|
|
260
|
+
function userArgsOf(event) {
|
|
261
|
+
if ("userArgs" in event && Array.isArray(event.userArgs)) return event.userArgs.filter((v) => v !== void 0);
|
|
262
|
+
if (event.props && Object.keys(event.props).length > 0) return [event.props];
|
|
263
|
+
return [];
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Terminal (ANSI) sink. Emits `[ansiPrefix, message, ...userArgs]` so that:
|
|
267
|
+
* - stdout gets a colored prefix
|
|
268
|
+
* - util.format leaves objects inspectable
|
|
269
|
+
* - vi.spyOn(console, 'info') intercepts calls (arrows re-read console)
|
|
270
|
+
*
|
|
271
|
+
* Spans and JSON format still go through the pre-formatted single-arg path —
|
|
272
|
+
* their consumers are log aggregators, not humans.
|
|
273
|
+
*/
|
|
274
|
+
function createTerminalConsoleSink(format = "console") {
|
|
275
|
+
if (format === "json") return (event) => routeSingle(event, formatJSONEvent(event));
|
|
276
|
+
return (event) => {
|
|
277
|
+
if (event.kind === "span") {
|
|
278
|
+
writeStderrLine(formatConsoleEvent(event));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const prefix = `${colors.dim(timeStr(event.time))} ${levelAnsi(event.level)} ${colors.cyan(event.namespace)}`;
|
|
282
|
+
const args = userArgsOf(event);
|
|
283
|
+
invokeForLevel(event.level, prefix, event.message, ...args);
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/** Emit one line to process.stderr when available (no-op in browser). */
|
|
287
|
+
function writeStderrLine(text) {
|
|
288
|
+
const p = typeof process !== "undefined" ? process : void 0;
|
|
289
|
+
if (p?.stderr && typeof p.stderr.write === "function") {
|
|
290
|
+
p.stderr.write(text + "\n");
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
console.info(text);
|
|
294
|
+
}
|
|
295
|
+
function levelAnsi(level) {
|
|
296
|
+
switch (level) {
|
|
297
|
+
case "trace": return colors.dim("TRACE");
|
|
298
|
+
case "debug": return colors.dim("DEBUG");
|
|
299
|
+
case "info": return colors.blue("INFO");
|
|
300
|
+
case "warn": return colors.yellow("WARN");
|
|
301
|
+
case "error": return colors.red("ERROR");
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Browser (DevTools) sink. Uses `%c` CSS format specifiers so DevTools
|
|
306
|
+
* renders a colored level + namespace prefix, then spreads user args raw so
|
|
307
|
+
* DevTools keeps them as expandable object references (clickable source
|
|
308
|
+
* locations for Error, drill-in for plain objects).
|
|
309
|
+
*
|
|
310
|
+
* For JSON format we still emit a single string — consumers that explicitly
|
|
311
|
+
* asked for JSON want machine-readable output, not DevTools theatrics.
|
|
312
|
+
*/
|
|
313
|
+
function createBrowserConsoleSink(format = "console") {
|
|
314
|
+
if (format === "json") return (event) => routeSingle(event, formatJSONEvent(event));
|
|
315
|
+
return (event) => {
|
|
316
|
+
if (event.kind === "span") {
|
|
317
|
+
const spanTemplate = `%c%s %cSPAN %c%s %c(%sms)`;
|
|
318
|
+
const args = userArgsOf(event);
|
|
319
|
+
const spanPropsString = args.length > 0 ? ` ${safeStringify(Object.assign({}, ...args.filter(isPlainRecord)))}` : "";
|
|
320
|
+
const { durationLabel } = { durationLabel: String(event.duration) };
|
|
321
|
+
invokeForLevel("info", spanTemplate + (spanPropsString ? "%s" : ""), cssDim(), timeStr(event.time), cssSpan(), cssNamespace(), event.namespace, cssDim(), durationLabel, ...spanPropsString ? [cssDim(), spanPropsString] : []);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const template = `%c%s %c%s %c%s`;
|
|
325
|
+
const args = userArgsOf(event);
|
|
326
|
+
invokeForLevel(event.level, template, cssDim(), timeStr(event.time), cssLevel(event.level), levelLabel(event.level), cssNamespace(), event.namespace, event.message, ...args);
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function isPlainRecord(v) {
|
|
330
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
331
|
+
}
|
|
332
|
+
function cssDim() {
|
|
333
|
+
return "color: #888";
|
|
334
|
+
}
|
|
335
|
+
function cssNamespace() {
|
|
336
|
+
return "color: #0aa; font-weight: bold";
|
|
337
|
+
}
|
|
338
|
+
function cssSpan() {
|
|
339
|
+
return "color: #a0a; font-weight: bold";
|
|
340
|
+
}
|
|
341
|
+
function cssLevel(level) {
|
|
342
|
+
switch (level) {
|
|
343
|
+
case "trace":
|
|
344
|
+
case "debug": return "color: #888; font-weight: bold";
|
|
345
|
+
case "info": return "color: #36f; font-weight: bold";
|
|
346
|
+
case "warn": return "color: #b80; font-weight: bold";
|
|
347
|
+
case "error": return "color: #c33; font-weight: bold";
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Dispatch to the right console method for the event's level.
|
|
352
|
+
* We intentionally use arrow-style invocation rather than
|
|
353
|
+
* `Function.prototype.bind.call(console.info, console, ...)` so that:
|
|
354
|
+
* 1. Tests can `vi.spyOn(console, 'info')` AFTER the sink is created.
|
|
355
|
+
* 2. DevTools attribute the log line to the caller's source location
|
|
356
|
+
* (arrows don't appear in the stack between the call and `console.*`).
|
|
357
|
+
*/
|
|
358
|
+
function invokeForLevel(level, ...args) {
|
|
359
|
+
switch (level) {
|
|
360
|
+
case "trace":
|
|
361
|
+
case "debug":
|
|
362
|
+
console.debug(...args);
|
|
363
|
+
return;
|
|
364
|
+
case "info":
|
|
365
|
+
console.info(...args);
|
|
366
|
+
return;
|
|
367
|
+
case "warn":
|
|
368
|
+
console.warn(...args);
|
|
369
|
+
return;
|
|
370
|
+
case "error":
|
|
371
|
+
console.error(...args);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Route an already-formatted single string to the correct console level.
|
|
377
|
+
* Used for JSON format and for span events where we preserve the pre-formatted
|
|
378
|
+
* shape.
|
|
379
|
+
*/
|
|
380
|
+
function routeSingle(event, text) {
|
|
381
|
+
if (event.kind === "span") {
|
|
382
|
+
console.info(text);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
switch (event.level) {
|
|
386
|
+
case "trace":
|
|
387
|
+
case "debug":
|
|
388
|
+
console.debug(text);
|
|
389
|
+
return;
|
|
390
|
+
case "info":
|
|
391
|
+
console.info(text);
|
|
392
|
+
return;
|
|
393
|
+
case "warn":
|
|
394
|
+
console.warn(text);
|
|
395
|
+
return;
|
|
396
|
+
case "error":
|
|
397
|
+
console.error(text);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Pick the right sink for the current runtime. Browsers get `%c` CSS, Node
|
|
403
|
+
* gets ANSI. Both emit multi-arg spreads so the platform can render objects
|
|
404
|
+
* as expandable references.
|
|
405
|
+
*/
|
|
406
|
+
function createConsoleSink$1(format = "console") {
|
|
407
|
+
return isBrowserRuntime() ? createBrowserConsoleSink(format) : createTerminalConsoleSink(format);
|
|
408
|
+
}
|
|
409
|
+
//#endregion
|
|
198
410
|
//#region src/pipeline.ts
|
|
199
411
|
const LOG_LEVEL_PRIORITY = {
|
|
200
412
|
trace: 0,
|
|
@@ -208,10 +420,6 @@ const _process = typeof process !== "undefined" ? process : void 0;
|
|
|
208
420
|
function getEnv(key) {
|
|
209
421
|
return _process?.env?.[key];
|
|
210
422
|
}
|
|
211
|
-
function writeStderr(text) {
|
|
212
|
-
if (_process?.stderr?.write) _process.stderr.write(text + "\n");
|
|
213
|
-
else console.error(text);
|
|
214
|
-
}
|
|
215
423
|
/** Serialize Error.cause chains up to a max depth */
|
|
216
424
|
function serializeCause(cause, maxDepth = 3) {
|
|
217
425
|
if (maxDepth <= 0 || cause === void 0 || cause === null) return void 0;
|
|
@@ -324,38 +532,12 @@ function parseNsFilter(ns) {
|
|
|
324
532
|
};
|
|
325
533
|
}
|
|
326
534
|
/**
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
* browser DevTools. When you click a log line in DevTools, it shows where
|
|
331
|
-
* YOUR code called log.info?.(), not where pipeline.ts called console.info().
|
|
332
|
-
* DO NOT replace bind() with direct console.info(text) calls — it breaks
|
|
333
|
-
* source location tracking in browsers.
|
|
535
|
+
* Console sink used inside the pipeline builder. Delegates to the structured
|
|
536
|
+
* console sink (browser %c or terminal multi-arg) so the pipeline preserves
|
|
537
|
+
* expandable user args end-to-end.
|
|
334
538
|
*/
|
|
335
|
-
function writeToConsole(text, event) {
|
|
336
|
-
if (event.kind === "span") {
|
|
337
|
-
writeStderr(text);
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
switch (event.level) {
|
|
341
|
-
case "trace":
|
|
342
|
-
case "debug":
|
|
343
|
-
Function.prototype.bind.call(console.debug, console, text)();
|
|
344
|
-
break;
|
|
345
|
-
case "info":
|
|
346
|
-
Function.prototype.bind.call(console.info, console, text)();
|
|
347
|
-
break;
|
|
348
|
-
case "warn":
|
|
349
|
-
Function.prototype.bind.call(console.warn, console, text)();
|
|
350
|
-
break;
|
|
351
|
-
case "error":
|
|
352
|
-
Function.prototype.bind.call(console.error, console, text)();
|
|
353
|
-
break;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
539
|
function createConsoleSink(format) {
|
|
357
|
-
|
|
358
|
-
return (event) => writeToConsole(formatter(event), event);
|
|
540
|
+
return createConsoleSink$1(format);
|
|
359
541
|
}
|
|
360
542
|
function createFileSink(path, format) {
|
|
361
543
|
const writer = createFileWriter(path);
|
|
@@ -493,8 +675,15 @@ function buildPipeline(elements, parentConfig) {
|
|
|
493
675
|
}
|
|
494
676
|
for (const branch of branches) branch.dispatch(e);
|
|
495
677
|
};
|
|
678
|
+
const spanEnabledForNamespace = (namespace) => {
|
|
679
|
+
if (!spansEnabled) return false;
|
|
680
|
+
if (outputs.some((output) => !output.nsFilter || output.nsFilter(namespace))) return true;
|
|
681
|
+
if (branches.some((branch) => branch.spanEnabled(namespace))) return true;
|
|
682
|
+
return stages.length > 0;
|
|
683
|
+
};
|
|
496
684
|
return {
|
|
497
685
|
dispatch,
|
|
686
|
+
spanEnabled: spanEnabledForNamespace,
|
|
498
687
|
level: config.level,
|
|
499
688
|
dispose: () => {
|
|
500
689
|
for (const d of disposables) d();
|
|
@@ -573,6 +762,12 @@ function readEnvTrace() {
|
|
|
573
762
|
* ])
|
|
574
763
|
* log.info?.('server started', { port: 3000 })
|
|
575
764
|
*/
|
|
765
|
+
const SPAN_ENABLED = Symbol("loggily.spanEnabled");
|
|
766
|
+
function spanIsEnabled(logger, namespace) {
|
|
767
|
+
if (collectSpans) return true;
|
|
768
|
+
const checker = logger[SPAN_ENABLED];
|
|
769
|
+
return checker ? checker(namespace) : true;
|
|
770
|
+
}
|
|
576
771
|
function resetIds() {
|
|
577
772
|
resetIdCounters();
|
|
578
773
|
}
|
|
@@ -638,6 +833,7 @@ function createLoggerImpl(name, props, pipeline) {
|
|
|
638
833
|
const emitLog = (level, msgOrError, dataOrMsg, extraData) => {
|
|
639
834
|
let message;
|
|
640
835
|
let data;
|
|
836
|
+
const userArgs = [];
|
|
641
837
|
if (msgOrError instanceof Error) {
|
|
642
838
|
const err = msgOrError;
|
|
643
839
|
const contextTags = _getContextTags?.() ?? {};
|
|
@@ -665,6 +861,8 @@ function createLoggerImpl(name, props, pipeline) {
|
|
|
665
861
|
error_cause: err.cause !== void 0 ? serializeCause(err.cause) : void 0
|
|
666
862
|
};
|
|
667
863
|
}
|
|
864
|
+
userArgs.push(err);
|
|
865
|
+
if (data && Object.keys(data).length > 0) userArgs.push(data);
|
|
668
866
|
} else {
|
|
669
867
|
message = resolveMessage(msgOrError);
|
|
670
868
|
const contextTags = _getContextTags?.();
|
|
@@ -676,6 +874,7 @@ function createLoggerImpl(name, props, pipeline) {
|
|
|
676
874
|
...props,
|
|
677
875
|
...dataOrMsg
|
|
678
876
|
} : void 0;
|
|
877
|
+
if (data && Object.keys(data).length > 0) userArgs.push(data);
|
|
679
878
|
}
|
|
680
879
|
const event = {
|
|
681
880
|
kind: "log",
|
|
@@ -683,7 +882,8 @@ function createLoggerImpl(name, props, pipeline) {
|
|
|
683
882
|
namespace: name,
|
|
684
883
|
level,
|
|
685
884
|
message,
|
|
686
|
-
props: data
|
|
885
|
+
props: data,
|
|
886
|
+
userArgs
|
|
687
887
|
};
|
|
688
888
|
pipeline.dispatch(event);
|
|
689
889
|
};
|
|
@@ -693,6 +893,9 @@ function createLoggerImpl(name, props, pipeline) {
|
|
|
693
893
|
get level() {
|
|
694
894
|
return pipeline.level;
|
|
695
895
|
},
|
|
896
|
+
[SPAN_ENABLED](namespace) {
|
|
897
|
+
return pipeline.spanEnabled(namespace);
|
|
898
|
+
},
|
|
696
899
|
dispatch(event) {
|
|
697
900
|
pipeline.dispatch(event);
|
|
698
901
|
},
|
|
@@ -757,8 +960,9 @@ function augmentWithSpans(logger, parentSpanId, traceId, traceSampled) {
|
|
|
757
960
|
traceId,
|
|
758
961
|
traceSampled
|
|
759
962
|
};
|
|
963
|
+
const spanMethod = spanIsEnabled(logger, logger.name) ? createSpanMethod(logger, spanState) : void 0;
|
|
760
964
|
return new Proxy(logger, { get(target, prop) {
|
|
761
|
-
if (prop === "span") return
|
|
965
|
+
if (prop === "span") return spanMethod;
|
|
762
966
|
if (prop === "child") return function child(namespaceOrContext, childProps) {
|
|
763
967
|
return augmentWithSpans(target.child(namespaceOrContext, childProps), spanState.parentSpanId, spanState.traceId, spanState.traceSampled);
|
|
764
968
|
};
|
|
@@ -796,7 +1000,8 @@ function createSpanMethod(logger, spanState) {
|
|
|
796
1000
|
startTime: Date.now(),
|
|
797
1001
|
endTime: null,
|
|
798
1002
|
duration: null,
|
|
799
|
-
attrs: {}
|
|
1003
|
+
attrs: {},
|
|
1004
|
+
laps: []
|
|
800
1005
|
};
|
|
801
1006
|
const spanAugmented = augmentWithSpans(logger.child(namespace ?? "", resolvedChildProps), newSpanId, finalTraceId, sampled);
|
|
802
1007
|
_enterContext?.(newSpanId, finalTraceId, resolvedParentId);
|
|
@@ -814,6 +1019,7 @@ function createSpanMethod(logger, spanState) {
|
|
|
814
1019
|
}), { ...newSpanData.attrs }));
|
|
815
1020
|
_exitContext?.(newSpanId);
|
|
816
1021
|
if (sampled) {
|
|
1022
|
+
const lapsProp = newSpanData.laps.length > 0 ? Object.fromEntries(newSpanData.laps.map((l) => [l.name, l.deltaMs])) : void 0;
|
|
817
1023
|
const spanEvent = {
|
|
818
1024
|
kind: "span",
|
|
819
1025
|
time: newSpanData.endTime,
|
|
@@ -822,7 +1028,8 @@ function createSpanMethod(logger, spanState) {
|
|
|
822
1028
|
duration: newSpanData.duration,
|
|
823
1029
|
props: {
|
|
824
1030
|
...mergedProps,
|
|
825
|
-
...newSpanData.attrs
|
|
1031
|
+
...newSpanData.attrs,
|
|
1032
|
+
...lapsProp ? { laps: lapsProp } : {}
|
|
826
1033
|
},
|
|
827
1034
|
spanId: newSpanData.id,
|
|
828
1035
|
traceId: newSpanData.traceId,
|
|
@@ -831,6 +1038,16 @@ function createSpanMethod(logger, spanState) {
|
|
|
831
1038
|
logger.dispatch(spanEvent);
|
|
832
1039
|
}
|
|
833
1040
|
};
|
|
1041
|
+
const lapImpl = (name) => {
|
|
1042
|
+
const elapsedMs = Date.now() - newSpanData.startTime;
|
|
1043
|
+
const lastLap = newSpanData.laps[newSpanData.laps.length - 1];
|
|
1044
|
+
const deltaMs = lastLap ? elapsedMs - lastLap.elapsedMs : elapsedMs;
|
|
1045
|
+
newSpanData.laps.push({
|
|
1046
|
+
name,
|
|
1047
|
+
elapsedMs,
|
|
1048
|
+
deltaMs
|
|
1049
|
+
});
|
|
1050
|
+
};
|
|
834
1051
|
const spanDataProxy = createSpanDataProxy(() => ({
|
|
835
1052
|
id: newSpanData.id,
|
|
836
1053
|
traceId: newSpanData.traceId,
|
|
@@ -847,6 +1064,7 @@ function createSpanMethod(logger, spanState) {
|
|
|
847
1064
|
if (prop === "end") return () => {
|
|
848
1065
|
if (newSpanData.endTime === null) currentDispose();
|
|
849
1066
|
};
|
|
1067
|
+
if (prop === "lap") return lapImpl;
|
|
850
1068
|
if (prop === "name") return childName;
|
|
851
1069
|
if (prop === "props") return Object.freeze({ ...mergedProps });
|
|
852
1070
|
return target[prop];
|
|
@@ -938,6 +1156,15 @@ function withEnvDefaults() {
|
|
|
938
1156
|
*/
|
|
939
1157
|
function applyNamespaceGating(logger) {
|
|
940
1158
|
return new Proxy(logger, { get(target, prop) {
|
|
1159
|
+
if (prop === SPAN_ENABLED) return (namespace) => {
|
|
1160
|
+
if (collectSpans) return true;
|
|
1161
|
+
const trace = currentTrace();
|
|
1162
|
+
if (!trace.enabled) return false;
|
|
1163
|
+
if (trace.filter && !trace.filter(namespace)) return false;
|
|
1164
|
+
const ns = currentNs();
|
|
1165
|
+
if (ns && !ns(namespace)) return false;
|
|
1166
|
+
return true;
|
|
1167
|
+
};
|
|
941
1168
|
if (typeof prop === "string" && prop in LOG_LEVEL_PRIORITY && prop !== "silent") {
|
|
942
1169
|
const nsLevel = readEnvLevelForNamespace(target.name);
|
|
943
1170
|
if (LOG_LEVEL_PRIORITY[prop] < LOG_LEVEL_PRIORITY[nsLevel]) return;
|
|
@@ -966,14 +1193,23 @@ function createEnvPipeline() {
|
|
|
966
1193
|
}
|
|
967
1194
|
const ns = currentNs();
|
|
968
1195
|
if (ns && !ns(event.namespace)) return;
|
|
969
|
-
const
|
|
1196
|
+
const format = currentFormat();
|
|
1197
|
+
const text = (format === "json" ? formatJSONEvent : formatConsoleEvent)(event);
|
|
970
1198
|
const lvl = event.kind === "log" ? event.level : "span";
|
|
971
|
-
for (const w of _writers) w(text, lvl);
|
|
972
|
-
if (!_suppressConsole)
|
|
1199
|
+
for (const w of _writers) w(text, lvl, event.namespace, event);
|
|
1200
|
+
if (!_suppressConsole) createConsoleSink$1(format)(event);
|
|
973
1201
|
fileSink?.(event);
|
|
974
1202
|
};
|
|
975
1203
|
return {
|
|
976
1204
|
dispatch,
|
|
1205
|
+
spanEnabled(namespace) {
|
|
1206
|
+
const trace = currentTrace();
|
|
1207
|
+
if (!trace.enabled) return false;
|
|
1208
|
+
if (trace.filter && !trace.filter(namespace)) return false;
|
|
1209
|
+
const ns = currentNs();
|
|
1210
|
+
if (ns && !ns(namespace)) return false;
|
|
1211
|
+
return true;
|
|
1212
|
+
},
|
|
977
1213
|
get level() {
|
|
978
1214
|
return currentLevel();
|
|
979
1215
|
},
|
|
@@ -1048,7 +1284,21 @@ function setOutputMode(_mode) {
|
|
|
1048
1284
|
function getOutputMode() {
|
|
1049
1285
|
return "console";
|
|
1050
1286
|
}
|
|
1051
|
-
function addWriter(
|
|
1287
|
+
function addWriter(arg1, arg2) {
|
|
1288
|
+
if (typeof arg1 === "function") return _addRawWriter(arg1);
|
|
1289
|
+
if (!arg2) throw new Error("addWriter: writer fn required when first argument is a config object");
|
|
1290
|
+
const config = arg1;
|
|
1291
|
+
const matches = config.ns ? parseNsFilter(config.ns) : null;
|
|
1292
|
+
const minPriority = config.level ? LOG_LEVEL_PRIORITY[config.level] : null;
|
|
1293
|
+
return _addRawWriter((formatted, level, namespace, event) => {
|
|
1294
|
+
if (matches && !matches(namespace)) return;
|
|
1295
|
+
if (minPriority !== null) {
|
|
1296
|
+
if ((LOG_LEVEL_PRIORITY[level] ?? LOG_LEVEL_PRIORITY.info) < minPriority) return;
|
|
1297
|
+
}
|
|
1298
|
+
arg2(formatted, level, namespace, event);
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
function _addRawWriter(writer) {
|
|
1052
1302
|
_writers.push(writer);
|
|
1053
1303
|
return () => {
|
|
1054
1304
|
const i = _writers.indexOf(writer);
|
|
@@ -1071,4 +1321,4 @@ function writeSpan(namespace, duration, attrs) {
|
|
|
1071
1321
|
//#endregion
|
|
1072
1322
|
export { withEnvDefaults as A, setSampleRate as B, setOutputMode as C, startCollecting as D, spansAreEnabled as E, safeStringify as F, createFileWriter as H, serializeCause as I, getIdFormat as L, writeSpan as M, LOG_LEVEL_PRIORITY as N, stopCollecting as O, buildPipeline as P, getSampleRate as R, setLogLevel as S, setTraceFilter as T, traceparent as V, getTraceFilter as _, baseCreateLogger as a, setDebugFilter as b, createSpanDataProxy as c, enableSpans as d, getCollectedSpans as f, getOutputMode as g, getLogLevel as h, addWriter as i, withSpans as j, withConfigMetrics as k, createTestLogger as l, getLogFormat as m, _setContextHooks as n, clearCollectedSpans as o, getDebugFilter as p, _setLogFileWriterFactory as r, createLogger as s, _clearContextHooks as t, disableSpans as u, pipe as v, setSuppressConsole as w, setLogFormat as x, resetIds as y, setIdFormat as z };
|
|
1073
1323
|
|
|
1074
|
-
//# sourceMappingURL=core-
|
|
1324
|
+
//# sourceMappingURL=core-Byd3DY71.mjs.map
|