loggily 0.7.0 → 0.8.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.
@@ -1,3 +1,4 @@
1
+ import { createMetricsCollector, withMetrics } from "./metrics.mjs";
1
2
  import { closeSync, openSync, writeSync } from "node:fs";
2
3
  //#region src/colors.ts
3
4
  /**
@@ -90,6 +91,110 @@ function createFileWriter(filePath, options = {}) {
90
91
  };
91
92
  }
92
93
  //#endregion
94
+ //#region src/tracing.ts
95
+ let currentIdFormat = "simple";
96
+ /**
97
+ * Set the ID format for new spans and traces.
98
+ * - "simple": sp_1, sp_2, tr_1, tr_2 (default, lightweight)
99
+ * - "w3c": 32-char hex trace ID, 16-char hex span ID (W3C Trace Context compatible)
100
+ *
101
+ * @deprecated Use the `TRACE_ID_FORMAT` env var or `{ idFormat: "w3c" }` in the config array instead.
102
+ */
103
+ function setIdFormat(format) {
104
+ currentIdFormat = format;
105
+ }
106
+ /**
107
+ * Get the current ID format.
108
+ *
109
+ * @deprecated Use the `TRACE_ID_FORMAT` env var or `{ idFormat: "w3c" }` in the config array instead.
110
+ */
111
+ function getIdFormat() {
112
+ return currentIdFormat;
113
+ }
114
+ let simpleSpanCounter = 0;
115
+ let simpleTraceCounter = 0;
116
+ /** Generate a hex string of the given byte length using crypto.randomUUID */
117
+ function randomHex(bytes) {
118
+ return crypto.randomUUID().replace(/-/g, "").slice(0, bytes * 2);
119
+ }
120
+ /** Generate a span ID according to the current format */
121
+ function generateSpanId() {
122
+ if (currentIdFormat === "w3c") return randomHex(8);
123
+ return `sp_${(++simpleSpanCounter).toString(36)}`;
124
+ }
125
+ /** Generate a trace ID according to the current format */
126
+ function generateTraceId() {
127
+ if (currentIdFormat === "w3c") return randomHex(16);
128
+ return `tr_${(++simpleTraceCounter).toString(36)}`;
129
+ }
130
+ /** Reset ID counters (for testing) */
131
+ function resetIdCounters() {
132
+ simpleSpanCounter = 0;
133
+ simpleTraceCounter = 0;
134
+ }
135
+ /**
136
+ * Format a W3C traceparent header from span data.
137
+ *
138
+ * Format: `{version}-{trace-id}-{span-id}-{trace-flags}`
139
+ * - version: "00" (current W3C spec version)
140
+ * - trace-id: 32 hex chars (128 bits)
141
+ * - span-id: 16 hex chars (64 bits)
142
+ * - trace-flags: "01" (sampled) or "00" (not sampled)
143
+ *
144
+ * Works with both simple and W3C ID formats. Simple IDs are zero-padded to spec length.
145
+ *
146
+ * @param spanData - Span data with id and traceId
147
+ * @param options - Optional settings (sampled flag). Defaults to sampled=true.
148
+ * @returns W3C traceparent header string
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * const span = log.span("http-request")
153
+ * const header = traceparent(span.spanData)
154
+ * // → "00-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6-1a2b3c4d5e6f7a8b-01"
155
+ * fetch(url, { headers: { traceparent: header } })
156
+ * ```
157
+ */
158
+ function traceparent(spanData, options) {
159
+ return `00-${padHex(spanData.traceId, 32)}-${padHex(spanData.id, 16)}-${options?.sampled ?? true ? "01" : "00"}`;
160
+ }
161
+ /** Pad or hash an ID to the specified hex length */
162
+ function padHex(id, length) {
163
+ if (id.length === length && /^[0-9a-f]+$/.test(id)) return id;
164
+ let hex = "";
165
+ for (let i = 0; i < id.length; i++) hex += id.charCodeAt(i).toString(16).padStart(2, "0");
166
+ return hex.padStart(length, "0").slice(-length);
167
+ }
168
+ let sampleRate = 1;
169
+ /**
170
+ * Set the head-based sampling rate for new traces.
171
+ * Applied at trace creation — all spans within a sampled trace are kept.
172
+ *
173
+ * @deprecated Use the `TRACE_SAMPLE_RATE` env var or `{ sampleRate: 0.1 }` in the config array instead.
174
+ * @param rate - Sampling rate from 0.0 (sample nothing) to 1.0 (sample everything, default)
175
+ */
176
+ function setSampleRate(rate) {
177
+ if (rate < 0 || rate > 1) throw new Error(`Sample rate must be between 0.0 and 1.0, got ${rate}`);
178
+ sampleRate = rate;
179
+ }
180
+ /**
181
+ * Get the current sampling rate.
182
+ *
183
+ * @deprecated Use the `TRACE_SAMPLE_RATE` env var or `{ sampleRate: 0.1 }` in the config array instead.
184
+ */
185
+ function getSampleRate() {
186
+ return sampleRate;
187
+ }
188
+ /**
189
+ * Determine whether a new trace should be sampled.
190
+ * Called at trace creation time (head-based sampling).
191
+ */
192
+ function shouldSample() {
193
+ if (sampleRate >= 1) return true;
194
+ if (sampleRate <= 0) return false;
195
+ return Math.random() < sampleRate;
196
+ }
197
+ //#endregion
93
198
  //#region src/pipeline.ts
94
199
  const LOG_LEVEL_PRIORITY = {
95
200
  trace: 0,
@@ -107,16 +212,36 @@ function writeStderr(text) {
107
212
  if (_process?.stderr?.write) _process.stderr.write(text + "\n");
108
213
  else console.error(text);
109
214
  }
215
+ /** Serialize Error.cause chains up to a max depth */
216
+ function serializeCause(cause, maxDepth = 3) {
217
+ if (maxDepth <= 0 || cause === void 0 || cause === null) return void 0;
218
+ if (cause instanceof Error) {
219
+ const result = {
220
+ name: cause.name,
221
+ message: cause.message,
222
+ stack: cause.stack
223
+ };
224
+ if (cause.code) result.code = cause.code;
225
+ if (cause.cause !== void 0) result.cause = serializeCause(cause.cause, maxDepth - 1);
226
+ return result;
227
+ }
228
+ return cause;
229
+ }
110
230
  function safeStringify(value) {
111
231
  const seen = /* @__PURE__ */ new WeakSet();
112
232
  return JSON.stringify(value, (_key, val) => {
113
233
  if (typeof val === "bigint") return val.toString();
114
234
  if (typeof val === "symbol") return val.toString();
115
- if (val instanceof Error) return {
116
- message: val.message,
117
- stack: val.stack,
118
- name: val.name
119
- };
235
+ if (val instanceof Error) {
236
+ const result = {
237
+ message: val.message,
238
+ stack: val.stack,
239
+ name: val.name
240
+ };
241
+ if (val.code) result.code = val.code;
242
+ if (val.cause !== void 0) result.cause = serializeCause(val.cause);
243
+ return result;
244
+ }
120
245
  if (typeof val === "object" && val !== null) {
121
246
  if (seen.has(val)) return "[Circular]";
122
247
  seen.add(val);
@@ -177,6 +302,10 @@ function formatJSONEvent(event) {
177
302
  }
178
303
  function matchesPattern(namespace, pattern) {
179
304
  if (pattern === "*") return true;
305
+ if (pattern.endsWith(":*")) {
306
+ const prefix = pattern.slice(0, -2);
307
+ return namespace === prefix || namespace.startsWith(prefix + ":");
308
+ }
180
309
  return namespace === pattern || namespace.startsWith(pattern + ":");
181
310
  }
182
311
  function parseNsFilter(ns) {
@@ -194,30 +323,39 @@ function parseNsFilter(ns) {
194
323
  return true;
195
324
  };
196
325
  }
326
+ /**
327
+ * Write formatted text to console using the appropriate log level.
328
+ *
329
+ * IMPORTANT: We use Function.bind() to preserve caller source locations in
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.
334
+ */
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
+ }
197
356
  function createConsoleSink(format) {
198
357
  const formatter = format === "json" ? formatJSONEvent : formatConsoleEvent;
199
- return (event) => {
200
- const text = formatter(event);
201
- if (event.kind === "span") {
202
- writeStderr(text);
203
- return;
204
- }
205
- switch (event.level) {
206
- case "trace":
207
- case "debug":
208
- console.debug(text);
209
- break;
210
- case "info":
211
- console.info(text);
212
- break;
213
- case "warn":
214
- console.warn(text);
215
- break;
216
- case "error":
217
- console.error(text);
218
- break;
219
- }
220
- };
358
+ return (event) => writeToConsole(formatter(event), event);
221
359
  }
222
360
  function createFileSink(path, format) {
223
361
  const writer = createFileWriter(path);
@@ -227,14 +365,24 @@ function createFileSink(path, format) {
227
365
  dispose: () => writer.close()
228
366
  };
229
367
  }
368
+ function isNodeStream(obj) {
369
+ return typeof obj === "object" && obj !== null && ("_write" in obj || "writable" in obj || "fd" in obj);
370
+ }
230
371
  function createWritableSink(writable, format) {
231
- const formatter = format === "json" ? formatJSONEvent : formatConsoleEvent;
232
- return (event) => writable.write(formatter(event) + "\n");
372
+ if (!(writable.objectMode ?? !isNodeStream(writable))) {
373
+ const formatter = format === "json" ? formatJSONEvent : formatConsoleEvent;
374
+ return (event) => writable.write(formatter(event) + "\n");
375
+ }
376
+ return (event) => writable.write(event);
233
377
  }
234
378
  const VALID_CONFIG_KEYS = new Set([
235
379
  "level",
236
380
  "ns",
237
- "format"
381
+ "format",
382
+ "spans",
383
+ "metrics",
384
+ "idFormat",
385
+ "sampleRate"
238
386
  ]);
239
387
  const SINK_KEYS = new Set(["file", "otel"]);
240
388
  function isPojo(obj) {
@@ -243,7 +391,7 @@ function isPojo(obj) {
243
391
  return proto === Object.prototype || proto === null;
244
392
  }
245
393
  function isWritable(obj) {
246
- return typeof obj === "object" && obj !== null && "write" in obj && typeof obj.write === "function" && !isPojo(obj);
394
+ return typeof obj === "object" && obj !== null && "write" in obj && typeof obj.write === "function";
247
395
  }
248
396
  function isValidLogLevel(val) {
249
397
  return typeof val === "string" && val in LOG_LEVEL_PRIORITY;
@@ -254,6 +402,7 @@ function buildPipeline(elements, parentConfig) {
254
402
  ns: parentConfig?.ns ?? readEnvNs(),
255
403
  format: parentConfig?.format ?? readEnvFormat()
256
404
  };
405
+ let spansEnabled = true;
257
406
  const stages = [];
258
407
  const outputs = [];
259
408
  const branches = [];
@@ -265,11 +414,7 @@ function buildPipeline(elements, parentConfig) {
265
414
  disposables.push(() => branch.dispose());
266
415
  continue;
267
416
  }
268
- if (typeof element === "function" && element !== console) {
269
- stages.push(element);
270
- continue;
271
- }
272
- if (element === console) {
417
+ if (element === console || element === "console") {
273
418
  outputs.push({
274
419
  levelPriority: LOG_LEVEL_PRIORITY[config.level],
275
420
  nsFilter: config.ns,
@@ -277,6 +422,10 @@ function buildPipeline(elements, parentConfig) {
277
422
  });
278
423
  continue;
279
424
  }
425
+ if (typeof element === "function") {
426
+ stages.push(element);
427
+ continue;
428
+ }
280
429
  if (isWritable(element)) {
281
430
  outputs.push({
282
431
  levelPriority: LOG_LEVEL_PRIORITY[config.level],
@@ -307,16 +456,30 @@ function buildPipeline(elements, parentConfig) {
307
456
  dispose: sink.dispose
308
457
  });
309
458
  }
459
+ if (obj.otel !== void 0) throw new Error("loggily: OTEL sink is not yet implemented. See loggily/otel for the planned bridge.");
310
460
  continue;
311
461
  }
312
462
  if (isValidLogLevel(obj.level)) config.level = obj.level;
313
463
  if (obj.ns !== void 0) config.ns = parseNsFilter(obj.ns);
314
464
  if (obj.format === "console" || obj.format === "json") config.format = obj.format;
465
+ if (obj.spans === true) spansEnabled = true;
466
+ if (obj.spans === false) spansEnabled = false;
467
+ if (obj.idFormat === "simple" || obj.idFormat === "w3c") setIdFormat(obj.idFormat);
468
+ if (typeof obj.sampleRate === "number") setSampleRate(obj.sampleRate);
469
+ continue;
470
+ }
471
+ if (element === "stderr" && typeof process !== "undefined") {
472
+ outputs.push({
473
+ levelPriority: LOG_LEVEL_PRIORITY[config.level],
474
+ nsFilter: config.ns,
475
+ write: createWritableSink(process.stderr, config.format)
476
+ });
315
477
  continue;
316
478
  }
317
- throw new Error(`loggily: unsupported config element of type "${typeof element}". Config arrays accept: objects (config), arrays (branches), functions (stages), console, or writables ({ write }).`);
479
+ throw new Error(`loggily: unsupported config element of type "${typeof element}". Config arrays accept: objects (config), arrays (branches), functions (stages), console, "console", or writables ({ write }).`);
318
480
  }
319
481
  const dispatch = (event) => {
482
+ if (event.kind === "span" && !spansEnabled) return;
320
483
  let e = event;
321
484
  for (const stage of stages) {
322
485
  const result = stage(e);
@@ -338,76 +501,27 @@ function buildPipeline(elements, parentConfig) {
338
501
  }
339
502
  };
340
503
  }
341
- const runtimeState = {
342
- suppressConsole: false,
343
- writers: []
344
- };
345
- function defaultPipeline() {
346
- const rt = runtimeState;
347
- const disposables = [];
348
- let fileSink = null;
349
- const logFile = getEnv("LOG_FILE");
350
- if (logFile) {
351
- const sink = createFileSink(logFile, "json");
352
- fileSink = sink.write;
353
- disposables.push(sink.dispose);
354
- }
355
- const dispatch = (event) => {
356
- const currentLevel = readEnvLevel();
357
- if (event.kind === "log") {
358
- if (LOG_LEVEL_PRIORITY[event.level] < LOG_LEVEL_PRIORITY[currentLevel]) return;
359
- } else if (event.kind === "span") {
360
- const trace = readEnvTrace();
361
- if (!trace.enabled) return;
362
- if (trace.filter && !trace.filter(event.namespace)) return;
363
- }
364
- const currentNs = readEnvNs();
365
- if (currentNs && !currentNs(event.namespace)) return;
366
- const formatter = readEnvFormat() === "json" || getEnv("NODE_ENV") === "production" || getEnv("TRACE_FORMAT") === "json" ? formatJSONEvent : formatConsoleEvent;
367
- if (rt.writers.length > 0) {
368
- const formatted = formatter(event);
369
- const lvl = event.kind === "log" ? event.level : "span";
370
- for (const w of rt.writers) w(formatted, lvl);
371
- }
372
- if (rt.suppressConsole) {
373
- fileSink?.(event);
374
- return;
375
- }
376
- const text = formatter(event);
377
- if (event.kind === "span") writeStderr(text);
378
- else switch (event.level) {
379
- case "trace":
380
- case "debug":
381
- console.debug(text);
382
- break;
383
- case "info":
384
- console.info(text);
385
- break;
386
- case "warn":
387
- console.warn(text);
388
- break;
389
- case "error":
390
- console.error(text);
391
- break;
392
- }
393
- fileSink?.(event);
394
- };
395
- return {
396
- dispatch,
397
- get level() {
398
- return readEnvLevel();
399
- },
400
- dispose: () => {
401
- for (const d of disposables) d();
402
- }
403
- };
404
- }
405
504
  function readEnvLevel() {
406
505
  const env = getEnv("LOG_LEVEL")?.toLowerCase();
407
506
  let level = env === "trace" || env === "debug" || env === "info" || env === "warn" || env === "error" || env === "silent" ? env : "info";
408
507
  if (getEnv("DEBUG") && LOG_LEVEL_PRIORITY[level] > LOG_LEVEL_PRIORITY.debug) level = "debug";
409
508
  return level;
410
509
  }
510
+ /**
511
+ * Namespace-aware level: only bumps to debug if the namespace matches the DEBUG filter.
512
+ * This enables zero-overhead conditional gating — `log.debug?.()` returns undefined
513
+ * for namespaces outside the DEBUG filter, skipping argument evaluation entirely.
514
+ */
515
+ function readEnvLevelForNamespace(namespace) {
516
+ const env = getEnv("LOG_LEVEL")?.toLowerCase();
517
+ const baseLevel = env === "trace" || env === "debug" || env === "info" || env === "warn" || env === "error" || env === "silent" ? env : "info";
518
+ if (getEnv("DEBUG") && LOG_LEVEL_PRIORITY[baseLevel] > LOG_LEVEL_PRIORITY.debug) {
519
+ const nsFilter = readEnvNs();
520
+ if (nsFilter && nsFilter(namespace)) return "debug";
521
+ return baseLevel;
522
+ }
523
+ return baseLevel;
524
+ }
411
525
  function readEnvNs() {
412
526
  const debugEnv = getEnv("DEBUG");
413
527
  if (!debugEnv) return null;
@@ -441,99 +555,6 @@ function readEnvTrace() {
441
555
  };
442
556
  }
443
557
  //#endregion
444
- //#region src/tracing.ts
445
- let currentIdFormat = "simple";
446
- /**
447
- * Set the ID format for new spans and traces.
448
- * - "simple": sp_1, sp_2, tr_1, tr_2 (default, lightweight)
449
- * - "w3c": 32-char hex trace ID, 16-char hex span ID (W3C Trace Context compatible)
450
- */
451
- function setIdFormat(format) {
452
- currentIdFormat = format;
453
- }
454
- /** Get the current ID format */
455
- function getIdFormat() {
456
- return currentIdFormat;
457
- }
458
- let simpleSpanCounter = 0;
459
- let simpleTraceCounter = 0;
460
- /** Generate a hex string of the given byte length using crypto.randomUUID */
461
- function randomHex(bytes) {
462
- return crypto.randomUUID().replace(/-/g, "").slice(0, bytes * 2);
463
- }
464
- /** Generate a span ID according to the current format */
465
- function generateSpanId() {
466
- if (currentIdFormat === "w3c") return randomHex(8);
467
- return `sp_${(++simpleSpanCounter).toString(36)}`;
468
- }
469
- /** Generate a trace ID according to the current format */
470
- function generateTraceId() {
471
- if (currentIdFormat === "w3c") return randomHex(16);
472
- return `tr_${(++simpleTraceCounter).toString(36)}`;
473
- }
474
- /** Reset ID counters (for testing) */
475
- function resetIdCounters() {
476
- simpleSpanCounter = 0;
477
- simpleTraceCounter = 0;
478
- }
479
- /**
480
- * Format a W3C traceparent header from span data.
481
- *
482
- * Format: `{version}-{trace-id}-{span-id}-{trace-flags}`
483
- * - version: "00" (current W3C spec version)
484
- * - trace-id: 32 hex chars (128 bits)
485
- * - span-id: 16 hex chars (64 bits)
486
- * - trace-flags: "01" (sampled) or "00" (not sampled)
487
- *
488
- * Works with both simple and W3C ID formats. Simple IDs are zero-padded to spec length.
489
- *
490
- * @param spanData - Span data with id and traceId
491
- * @param options - Optional settings (sampled flag). Defaults to sampled=true.
492
- * @returns W3C traceparent header string
493
- *
494
- * @example
495
- * ```typescript
496
- * const span = log.span("http-request")
497
- * const header = traceparent(span.spanData)
498
- * // → "00-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6-1a2b3c4d5e6f7a8b-01"
499
- * fetch(url, { headers: { traceparent: header } })
500
- * ```
501
- */
502
- function traceparent(spanData, options) {
503
- return `00-${padHex(spanData.traceId, 32)}-${padHex(spanData.id, 16)}-${options?.sampled ?? true ? "01" : "00"}`;
504
- }
505
- /** Pad or hash an ID to the specified hex length */
506
- function padHex(id, length) {
507
- if (id.length === length && /^[0-9a-f]+$/.test(id)) return id;
508
- let hex = "";
509
- for (let i = 0; i < id.length; i++) hex += id.charCodeAt(i).toString(16).padStart(2, "0");
510
- return hex.padStart(length, "0").slice(-length);
511
- }
512
- let sampleRate = 1;
513
- /**
514
- * Set the head-based sampling rate for new traces.
515
- * Applied at trace creation — all spans within a sampled trace are kept.
516
- *
517
- * @param rate - Sampling rate from 0.0 (sample nothing) to 1.0 (sample everything, default)
518
- */
519
- function setSampleRate(rate) {
520
- if (rate < 0 || rate > 1) throw new Error(`Sample rate must be between 0.0 and 1.0, got ${rate}`);
521
- sampleRate = rate;
522
- }
523
- /** Get the current sampling rate */
524
- function getSampleRate() {
525
- return sampleRate;
526
- }
527
- /**
528
- * Determine whether a new trace should be sampled.
529
- * Called at trace creation time (head-based sampling).
530
- */
531
- function shouldSample() {
532
- if (sampleRate >= 1) return true;
533
- if (sampleRate <= 0) return false;
534
- return Math.random() < sampleRate;
535
- }
536
- //#endregion
537
558
  //#region src/core.ts
538
559
  /**
539
560
  * loggily v2 — Structured logging with spans
@@ -552,11 +573,6 @@ function shouldSample() {
552
573
  * ])
553
574
  * log.info?.('server started', { port: 3000 })
554
575
  */
555
- /** @internal */
556
- let _ambientRecorder = null;
557
- function _setAmbientRecorder(recorder) {
558
- _ambientRecorder = recorder;
559
- }
560
576
  function resetIds() {
561
577
  resetIdCounters();
562
578
  }
@@ -618,30 +634,35 @@ function clearCollectedSpans() {
618
634
  function resolveMessage(msg) {
619
635
  return typeof msg === "function" ? msg() : msg;
620
636
  }
621
- function createLoggerImpl(name, props, pipeline, spanMeta, parentSpanId, traceId, traceSampled = true) {
637
+ function createLoggerImpl(name, props, pipeline) {
622
638
  const emitLog = (level, msgOrError, dataOrMsg, extraData) => {
623
639
  let message;
624
640
  let data;
625
641
  if (msgOrError instanceof Error) {
626
642
  const err = msgOrError;
643
+ const contextTags = _getContextTags?.() ?? {};
627
644
  if (typeof dataOrMsg === "string") {
628
645
  message = dataOrMsg;
629
646
  data = {
647
+ ...contextTags,
630
648
  ...props,
631
649
  ...extraData,
632
650
  error_type: err.name,
633
651
  error_message: err.message,
634
652
  error_stack: err.stack,
635
- error_code: err.code
653
+ error_code: err.code,
654
+ error_cause: err.cause !== void 0 ? serializeCause(err.cause) : void 0
636
655
  };
637
656
  } else {
638
657
  message = err.message;
639
658
  data = {
659
+ ...contextTags,
640
660
  ...props,
641
661
  ...dataOrMsg,
642
662
  error_type: err.name,
643
663
  error_stack: err.stack,
644
- error_code: err.code
664
+ error_code: err.code,
665
+ error_cause: err.cause !== void 0 ? serializeCause(err.cause) : void 0
645
666
  };
646
667
  }
647
668
  } else {
@@ -669,16 +690,14 @@ function createLoggerImpl(name, props, pipeline, spanMeta, parentSpanId, traceId
669
690
  return {
670
691
  name,
671
692
  props: Object.freeze({ ...props }),
672
- get spanData() {
673
- if (!spanMeta) return null;
674
- return createSpanDataProxy(() => ({
675
- id: spanMeta.id,
676
- traceId: spanMeta.traceId,
677
- parentId: spanMeta.parentId,
678
- startTime: spanMeta.startTime,
679
- endTime: spanMeta.endTime,
680
- duration: spanMeta.endTime !== null ? spanMeta.endTime - spanMeta.startTime : Date.now() - spanMeta.startTime
681
- }), spanMeta.attrs);
693
+ get level() {
694
+ return pipeline.level;
695
+ },
696
+ dispatch(event) {
697
+ pipeline.dispatch(event);
698
+ },
699
+ [Symbol.dispose]() {
700
+ pipeline.dispose();
682
701
  },
683
702
  trace: (msg, data) => emitLog("trace", msg, data),
684
703
  debug: (msg, data) => emitLog("debug", msg, data),
@@ -686,202 +705,358 @@ function createLoggerImpl(name, props, pipeline, spanMeta, parentSpanId, traceId
686
705
  warn: (msg, data) => emitLog("warn", msg, data),
687
706
  error: (msgOrError, dataOrMsg, extraData) => emitLog("error", msgOrError, dataOrMsg, extraData),
688
707
  logger(namespace, childProps) {
689
- return wrapConditional(createLoggerImpl(namespace ? `${name}:${namespace}` : name, {
690
- ...props,
691
- ...childProps
692
- }, pipeline, null, parentSpanId, traceId, traceSampled), () => pipeline.level);
708
+ return this.child(namespace ?? "", childProps);
693
709
  },
694
- span(namespace, childProps) {
695
- const childName = namespace ? `${name}:${namespace}` : name;
696
- const resolvedChildProps = typeof childProps === "function" ? childProps() : childProps;
697
- const mergedProps = {
698
- ...props,
699
- ...resolvedChildProps
700
- };
701
- const newSpanId = generateSpanId();
702
- let resolvedParentId = parentSpanId;
703
- let resolvedTraceId = traceId;
704
- if (!resolvedParentId && _getContextParent) {
705
- const ctxParent = _getContextParent();
706
- if (ctxParent) {
707
- resolvedParentId = ctxParent.spanId;
708
- resolvedTraceId = resolvedTraceId || ctxParent.traceId;
709
- }
710
- }
711
- const isNewTrace = !resolvedTraceId;
712
- const finalTraceId = resolvedTraceId || generateTraceId();
713
- const sampled = isNewTrace ? shouldSample() : traceSampled;
714
- const newSpanData = {
715
- id: newSpanId,
716
- traceId: finalTraceId,
717
- parentId: resolvedParentId,
718
- startTime: Date.now(),
719
- endTime: null,
720
- duration: null,
721
- attrs: {}
722
- };
723
- const spanLogger = createLoggerImpl(childName, mergedProps, pipeline, newSpanData, newSpanId, finalTraceId, sampled);
724
- _enterContext?.(newSpanId, finalTraceId, resolvedParentId);
725
- spanLogger[Symbol.dispose] = () => {
726
- if (newSpanData.endTime !== null) return;
727
- newSpanData.endTime = Date.now();
728
- newSpanData.duration = newSpanData.endTime - newSpanData.startTime;
729
- if (collectSpans) collectedSpans.push(createSpanDataProxy(() => ({
730
- id: newSpanData.id,
731
- traceId: newSpanData.traceId,
732
- parentId: newSpanData.parentId,
733
- startTime: newSpanData.startTime,
734
- endTime: newSpanData.endTime,
735
- duration: newSpanData.duration
736
- }), { ...newSpanData.attrs }));
737
- _exitContext?.(newSpanId);
738
- _ambientRecorder?.recordSpan({
739
- name: childName,
740
- durationMs: newSpanData.duration
741
- });
742
- if (sampled) {
743
- const spanEvent = {
744
- kind: "span",
745
- time: newSpanData.endTime,
746
- namespace: childName,
747
- name: childName,
748
- duration: newSpanData.duration,
749
- props: {
750
- ...mergedProps,
751
- ...newSpanData.attrs
752
- },
753
- spanId: newSpanData.id,
754
- traceId: newSpanData.traceId,
755
- parentId: newSpanData.parentId
756
- };
757
- pipeline.dispatch(spanEvent);
758
- }
759
- };
760
- return spanLogger;
710
+ span(_namespace, _childProps) {
711
+ throw new Error("loggily: span() requires the withSpans() plugin. Use pipe(baseCreateLogger, withSpans()) or the default createLogger.");
761
712
  },
762
- child(context) {
763
- if (typeof context === "string") return this.logger(context);
713
+ child(namespaceOrContext, childProps) {
714
+ if (typeof namespaceOrContext === "string") return wrapConditional(createLoggerImpl(namespaceOrContext ? `${name}:${namespaceOrContext}` : name, {
715
+ ...props,
716
+ ...childProps
717
+ }, pipeline), () => pipeline.level);
764
718
  return wrapConditional(createLoggerImpl(name, {
765
719
  ...props,
766
- ...context
767
- }, pipeline, null, parentSpanId, traceId, traceSampled), () => pipeline.level);
720
+ ...namespaceOrContext
721
+ }, pipeline), () => pipeline.level);
768
722
  },
769
- end() {
770
- if (spanMeta?.endTime === null) this[Symbol.dispose]?.();
771
- }
723
+ end() {}
772
724
  };
773
725
  }
774
726
  function wrapConditional(logger, getLevel) {
775
727
  return new Proxy(logger, { get(target, prop) {
776
- if (prop in LOG_LEVEL_PRIORITY && prop !== "silent") {
728
+ if (typeof prop === "string" && prop in LOG_LEVEL_PRIORITY && prop !== "silent") {
777
729
  if (LOG_LEVEL_PRIORITY[prop] < LOG_LEVEL_PRIORITY[getLevel()]) return;
778
730
  }
731
+ if (prop === "span") {
732
+ const val = target[prop];
733
+ if (val === baseSpanStub) return void 0;
734
+ return val;
735
+ }
779
736
  return target[prop];
780
737
  } });
781
738
  }
739
+ const baseSpanStub = function baseSpanStub(_namespace, _childProps) {
740
+ throw new Error("loggily: span() requires the withSpans() plugin. Use pipe(baseCreateLogger, withSpans()) or the default createLogger.");
741
+ };
782
742
  /**
783
- * Create a logger.
784
- *
785
- * @param name - Logger namespace (e.g., 'myapp', 'myapp:db')
786
- * @param config - Optional config array. Objects configure, arrays branch, values write.
787
- *
788
- * @example
789
- * // Zero config (reads LOG_LEVEL, DEBUG, LOG_FORMAT from env)
790
- * const log = createLogger('myapp')
791
- *
792
- * @example
793
- * // Configured pipeline
794
- * const log = createLogger('myapp', [
795
- * { level: 'debug', ns: '-sql' },
796
- * console,
797
- * { file: '/tmp/app.log', level: 'info', format: 'json' },
798
- * ])
743
+ * Plugin: adds span creation capability to loggers.
744
+ * Without this plugin, `.span` is undefined on ConditionalLogger.
745
+ * Included by default in `createLogger`.
799
746
  */
800
- function createLogger(name, config) {
801
- const pipeline = config ? buildPipeline(config) : defaultPipeline();
802
- return wrapConditional(createLoggerImpl(name, {}, pipeline, null, null, null), () => pipeline.level);
747
+ function withSpans() {
748
+ return (factory, _ctx) => {
749
+ return (name, configOrProps) => {
750
+ return augmentWithSpans(factory(name, configOrProps), null, null, true);
751
+ };
752
+ };
753
+ }
754
+ function augmentWithSpans(logger, parentSpanId, traceId, traceSampled) {
755
+ const spanState = {
756
+ parentSpanId,
757
+ traceId,
758
+ traceSampled
759
+ };
760
+ return new Proxy(logger, { get(target, prop) {
761
+ if (prop === "span") return createSpanMethod(target, spanState);
762
+ if (prop === "child") return function child(namespaceOrContext, childProps) {
763
+ return augmentWithSpans(target.child(namespaceOrContext, childProps), spanState.parentSpanId, spanState.traceId, spanState.traceSampled);
764
+ };
765
+ if (prop === "logger") return function logger(namespace, childProps) {
766
+ return augmentWithSpans(target.logger(namespace, childProps), spanState.parentSpanId, spanState.traceId, spanState.traceSampled);
767
+ };
768
+ return target[prop];
769
+ } });
770
+ }
771
+ function createSpanMethod(logger, spanState) {
772
+ return (namespace, childProps) => {
773
+ const childName = namespace ? `${logger.name}:${namespace}` : logger.name;
774
+ const resolvedChildProps = typeof childProps === "function" ? childProps() : childProps;
775
+ const mergedProps = {
776
+ ...logger.props,
777
+ ...resolvedChildProps
778
+ };
779
+ const newSpanId = generateSpanId();
780
+ let resolvedParentId = spanState.parentSpanId;
781
+ let resolvedTraceId = spanState.traceId;
782
+ if (!resolvedParentId && _getContextParent) {
783
+ const ctxParent = _getContextParent();
784
+ if (ctxParent) {
785
+ resolvedParentId = ctxParent.spanId;
786
+ resolvedTraceId = resolvedTraceId || ctxParent.traceId;
787
+ }
788
+ }
789
+ const isNewTrace = !resolvedTraceId;
790
+ const finalTraceId = resolvedTraceId || generateTraceId();
791
+ const sampled = isNewTrace ? shouldSample() : spanState.traceSampled;
792
+ const newSpanData = {
793
+ id: newSpanId,
794
+ traceId: finalTraceId,
795
+ parentId: resolvedParentId,
796
+ startTime: Date.now(),
797
+ endTime: null,
798
+ duration: null,
799
+ attrs: {}
800
+ };
801
+ const spanAugmented = augmentWithSpans(logger.child(namespace ?? "", resolvedChildProps), newSpanId, finalTraceId, sampled);
802
+ _enterContext?.(newSpanId, finalTraceId, resolvedParentId);
803
+ const disposeSpan = () => {
804
+ if (newSpanData.endTime !== null) return;
805
+ newSpanData.endTime = Date.now();
806
+ newSpanData.duration = newSpanData.endTime - newSpanData.startTime;
807
+ if (collectSpans) collectedSpans.push(createSpanDataProxy(() => ({
808
+ id: newSpanData.id,
809
+ traceId: newSpanData.traceId,
810
+ parentId: newSpanData.parentId,
811
+ startTime: newSpanData.startTime,
812
+ endTime: newSpanData.endTime,
813
+ duration: newSpanData.duration
814
+ }), { ...newSpanData.attrs }));
815
+ _exitContext?.(newSpanId);
816
+ if (sampled) {
817
+ const spanEvent = {
818
+ kind: "span",
819
+ time: newSpanData.endTime,
820
+ namespace: childName,
821
+ name: childName,
822
+ duration: newSpanData.duration,
823
+ props: {
824
+ ...mergedProps,
825
+ ...newSpanData.attrs
826
+ },
827
+ spanId: newSpanData.id,
828
+ traceId: newSpanData.traceId,
829
+ parentId: newSpanData.parentId
830
+ };
831
+ logger.dispatch(spanEvent);
832
+ }
833
+ };
834
+ const spanDataProxy = createSpanDataProxy(() => ({
835
+ id: newSpanData.id,
836
+ traceId: newSpanData.traceId,
837
+ parentId: newSpanData.parentId,
838
+ startTime: newSpanData.startTime,
839
+ endTime: newSpanData.endTime,
840
+ duration: newSpanData.endTime !== null ? newSpanData.endTime - newSpanData.startTime : Date.now() - newSpanData.startTime
841
+ }), newSpanData.attrs);
842
+ let currentDispose = disposeSpan;
843
+ return new Proxy(spanAugmented, {
844
+ get(target, prop) {
845
+ if (prop === "spanData") return spanDataProxy;
846
+ if (prop === Symbol.dispose) return currentDispose;
847
+ if (prop === "end") return () => {
848
+ if (newSpanData.endTime === null) currentDispose();
849
+ };
850
+ if (prop === "name") return childName;
851
+ if (prop === "props") return Object.freeze({ ...mergedProps });
852
+ return target[prop];
853
+ },
854
+ set(_target, prop, value) {
855
+ if (prop === Symbol.dispose) {
856
+ currentDispose = value;
857
+ return true;
858
+ }
859
+ return false;
860
+ }
861
+ });
862
+ };
803
863
  }
804
864
  /**
805
- * Compose a custom createLogger with plugins.
865
+ * Base createLogger requires a config array.
866
+ * Use the default `createLogger` export (with `withEnvDefaults`) for zero-config.
806
867
  *
807
- * @example
808
- * import { createLogger as base, compose } from "loggily"
809
- * import withSentry from "@sentry/loggily"
810
- *
811
- * const createLogger = compose(base, withSentry({ dsn: "..." }))
812
- * const log = createLogger("myapp")
868
+ * Note: loggers from baseCreateLogger do NOT have `.span()` capability.
869
+ * Use `pipe(baseCreateLogger, withSpans())` or the default `createLogger` for spans.
813
870
  */
814
- function compose(base, ...plugins) {
815
- return plugins.reduce((factory, plugin) => plugin(factory), base);
871
+ function baseCreateLogger(name, configOrProps) {
872
+ let pipeline;
873
+ let props = {};
874
+ if (Array.isArray(configOrProps)) pipeline = buildPipeline(configOrProps);
875
+ else if (configOrProps && typeof configOrProps === "object") {
876
+ props = configOrProps;
877
+ pipeline = buildPipeline(["console"]);
878
+ } else pipeline = buildPipeline(["console"]);
879
+ const logger = createLoggerImpl(name, props, pipeline);
880
+ logger.span = baseSpanStub;
881
+ return wrapConditional(logger, () => pipeline.level);
882
+ }
883
+ function pipe(base, ...plugins) {
884
+ const ctx = {};
885
+ return plugins.reduce((factory, plugin) => plugin(factory, ctx), base);
816
886
  }
817
887
  const _env = (typeof process !== "undefined" ? process : void 0)?.env ?? {};
818
- /** @deprecated Use createLogger config array: createLogger("x", [{ level }, console]) */
888
+ function currentLevel() {
889
+ return readEnvLevel();
890
+ }
891
+ function currentNs() {
892
+ return readEnvNs();
893
+ }
894
+ function currentFormat() {
895
+ return readEnvFormat();
896
+ }
897
+ function currentTrace() {
898
+ return readEnvTrace();
899
+ }
900
+ const _writers = [];
901
+ let _suppressConsole = false;
902
+ let _logFileWriterFactory = null;
903
+ /** @internal */
904
+ function _setLogFileWriterFactory(factory) {
905
+ _logFileWriterFactory = factory;
906
+ }
907
+ /**
908
+ * Plugin: read defaults from environment variables (LOG_LEVEL, DEBUG, LOG_FORMAT, TRACE, LOG_FILE).
909
+ * Included by default. Omit to disable env-var behavior entirely.
910
+ *
911
+ * When no config array is given, provides console output + env-var-based config.
912
+ * When a config array IS given, env vars are already used as defaults by buildPipeline.
913
+ * Legacy setters (setLogLevel, addWriter, etc.) affect loggers created without explicit config.
914
+ */
915
+ function withEnvDefaults() {
916
+ return (factory, _ctx) => (name, configOrProps) => {
917
+ const envIdFormat = _env.TRACE_ID_FORMAT?.toLowerCase();
918
+ if (envIdFormat === "simple" || envIdFormat === "w3c") setIdFormat(envIdFormat);
919
+ const envSampleRate = _env.TRACE_SAMPLE_RATE;
920
+ if (envSampleRate !== void 0) {
921
+ const rate = Number.parseFloat(envSampleRate);
922
+ if (!Number.isNaN(rate) && rate >= 0 && rate <= 1) setSampleRate(rate);
923
+ }
924
+ if (Array.isArray(configOrProps)) return factory(name, configOrProps);
925
+ const envPipeline = createEnvPipeline();
926
+ const envStage = (event) => {
927
+ envPipeline.dispatch(event);
928
+ return null;
929
+ };
930
+ if (configOrProps && typeof configOrProps === "object") return applyNamespaceGating(factory(name, [{ level: "trace" }, envStage]).child(configOrProps));
931
+ return applyNamespaceGating(factory(name, [{ level: "trace" }, envStage]));
932
+ };
933
+ }
934
+ /**
935
+ * Wrap a logger so that conditional method gating is namespace-aware.
936
+ * When DEBUG=myapp:db, only loggers whose namespace matches get debug enabled.
937
+ * Without this, all loggers get debug because readEnvLevel() bumps globally.
938
+ */
939
+ function applyNamespaceGating(logger) {
940
+ return new Proxy(logger, { get(target, prop) {
941
+ if (typeof prop === "string" && prop in LOG_LEVEL_PRIORITY && prop !== "silent") {
942
+ const nsLevel = readEnvLevelForNamespace(target.name);
943
+ if (LOG_LEVEL_PRIORITY[prop] < LOG_LEVEL_PRIORITY[nsLevel]) return;
944
+ }
945
+ return target[prop];
946
+ } });
947
+ }
948
+ function createEnvPipeline() {
949
+ const disposables = [];
950
+ const logFile = _env.LOG_FILE;
951
+ let fileSink = null;
952
+ if (logFile && _logFileWriterFactory) {
953
+ const writer = _logFileWriterFactory(logFile);
954
+ fileSink = (event) => {
955
+ const fmt = currentFormat() === "json" ? formatJSONEvent : formatConsoleEvent;
956
+ writer.write(fmt(event));
957
+ };
958
+ disposables.push(() => writer.close());
959
+ }
960
+ const dispatch = (event) => {
961
+ if (event.kind === "log" && LOG_LEVEL_PRIORITY[event.level] < LOG_LEVEL_PRIORITY[currentLevel()]) return;
962
+ if (event.kind === "span") {
963
+ const trace = currentTrace();
964
+ if (!trace.enabled) return;
965
+ if (trace.filter && !trace.filter(event.namespace)) return;
966
+ }
967
+ const ns = currentNs();
968
+ if (ns && !ns(event.namespace)) return;
969
+ const text = (currentFormat() === "json" ? formatJSONEvent : formatConsoleEvent)(event);
970
+ const lvl = event.kind === "log" ? event.level : "span";
971
+ for (const w of _writers) w(text, lvl);
972
+ if (!_suppressConsole) writeToConsole(text, event);
973
+ fileSink?.(event);
974
+ };
975
+ return {
976
+ dispatch,
977
+ get level() {
978
+ return currentLevel();
979
+ },
980
+ dispose: () => {
981
+ for (const d of disposables) d();
982
+ }
983
+ };
984
+ }
985
+ /**
986
+ * Plugin: when `{ metrics: true }` appears in the config array, automatically
987
+ * creates a MetricsCollector and applies withMetrics to the logger.
988
+ * The collector is accessible via `logger.metrics`.
989
+ */
990
+ function withConfigMetrics() {
991
+ return (factory, _ctx) => {
992
+ return (name, configOrProps) => {
993
+ const logger = factory(name, configOrProps);
994
+ if (!Array.isArray(configOrProps)) return logger;
995
+ if (!configOrProps.some((el) => typeof el === "object" && el !== null && !Array.isArray(el) && "metrics" in el && el.metrics === true)) return logger;
996
+ return withMetrics(createMetricsCollector())(logger);
997
+ };
998
+ };
999
+ }
1000
+ /** Default createLogger — includes withEnvDefaults + withSpans + withConfigMetrics. */
1001
+ const createLogger = pipe(baseCreateLogger, withEnvDefaults(), withSpans(), withConfigMetrics());
1002
+ /** Test helper — all levels, console output. */
1003
+ function createTestLogger(name) {
1004
+ return pipe(baseCreateLogger, withSpans())(name, [{ level: "trace" }, "console"]);
1005
+ }
1006
+ /** @deprecated Use config array */
819
1007
  function setLogLevel(level) {
820
1008
  _env.LOG_LEVEL = level;
821
1009
  }
822
- /** @deprecated Level is per-logger in v2 */
823
1010
  function getLogLevel() {
824
- return _env.LOG_LEVEL ?? "info";
1011
+ return currentLevel();
825
1012
  }
826
- /** @deprecated Use TRACE=1 env var */
827
1013
  function enableSpans() {
828
1014
  _env.TRACE = "1";
829
1015
  }
830
- /** @deprecated */
831
1016
  function disableSpans() {
832
1017
  delete _env.TRACE;
833
1018
  }
834
- /** @deprecated */
835
1019
  function spansAreEnabled() {
836
1020
  return !!_env.TRACE;
837
1021
  }
838
- /** @deprecated Use TRACE=namespace env var */
839
1022
  function setTraceFilter(namespaces) {
840
1023
  if (!namespaces || namespaces.length === 0) delete _env.TRACE;
841
1024
  else _env.TRACE = namespaces.join(",");
842
1025
  }
843
- /** @deprecated */
844
1026
  function getTraceFilter() {
845
1027
  return _env.TRACE ? _env.TRACE.split(",") : null;
846
1028
  }
847
- /** @deprecated Use DEBUG=namespace env var or { ns } in config array */
848
1029
  function setDebugFilter(namespaces) {
849
1030
  if (!namespaces || namespaces.length === 0) delete _env.DEBUG;
850
1031
  else _env.DEBUG = namespaces.join(",");
851
1032
  }
852
- /** @deprecated */
853
1033
  function getDebugFilter() {
854
1034
  return _env.DEBUG ? _env.DEBUG.split(",") : null;
855
1035
  }
856
- /** @deprecated Use { format } in config array */
857
1036
  function setLogFormat(format) {
858
1037
  _env.LOG_FORMAT = format;
859
1038
  }
860
- /** @deprecated */
861
1039
  function getLogFormat() {
862
- return _env.LOG_FORMAT ?? "console";
1040
+ return currentFormat();
863
1041
  }
864
- /** @deprecated Omit console from config array instead */
865
1042
  function setSuppressConsole(value) {
866
- runtimeState.suppressConsole = value;
1043
+ _suppressConsole = value;
1044
+ }
1045
+ function setOutputMode(_mode) {
1046
+ throw new Error("loggily: setOutputMode() is removed in v2. Use config arrays: omit console from array for writers-only, use \"stderr\" for stderr mode.");
867
1047
  }
868
- /** @deprecated Use config array */
869
- function setOutputMode(_mode) {}
870
- /** @deprecated */
871
1048
  function getOutputMode() {
872
1049
  return "console";
873
1050
  }
874
- /** @deprecated Pass writers in config array instead */
875
1051
  function addWriter(writer) {
876
- runtimeState.writers.push(writer);
1052
+ _writers.push(writer);
877
1053
  return () => {
878
- const idx = runtimeState.writers.indexOf(writer);
879
- if (idx !== -1) runtimeState.writers.splice(idx, 1);
1054
+ const i = _writers.indexOf(writer);
1055
+ if (i !== -1) _writers.splice(i, 1);
880
1056
  };
881
1057
  }
882
- /** @deprecated Spans dispatch through the pipeline automatically */
883
1058
  function writeSpan(namespace, duration, attrs) {
884
- const event = {
1059
+ createEnvPipeline().dispatch({
885
1060
  kind: "span",
886
1061
  time: Date.now(),
887
1062
  namespace,
@@ -891,10 +1066,9 @@ function writeSpan(namespace, duration, attrs) {
891
1066
  spanId: attrs.span_id ?? "",
892
1067
  traceId: attrs.trace_id ?? "",
893
1068
  parentId: attrs.parent_id ?? null
894
- };
895
- defaultPipeline().dispatch(event);
1069
+ });
896
1070
  }
897
1071
  //#endregion
898
- export { getSampleRate as A, setSuppressConsole as C, stopCollecting as D, startCollecting as E, buildPipeline as F, defaultPipeline as I, safeStringify as L, setSampleRate as M, traceparent as N, writeSpan as O, LOG_LEVEL_PRIORITY as P, createFileWriter as R, setOutputMode as S, spansAreEnabled as T, getTraceFilter as _, addWriter as a, setLogFormat as b, createLogger as c, enableSpans as d, getCollectedSpans as f, getOutputMode as g, getLogLevel as h, _setContextHooks as i, setIdFormat as j, getIdFormat as k, createSpanDataProxy as l, getLogFormat as m, _clearContextHooks as n, clearCollectedSpans as o, getDebugFilter as p, _setAmbientRecorder as r, compose as s, _ambientRecorder as t, disableSpans as u, resetIds as v, setTraceFilter as w, setLogLevel as x, setDebugFilter as y };
1072
+ 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 };
899
1073
 
900
- //# sourceMappingURL=core-Du3sIje6.mjs.map
1074
+ //# sourceMappingURL=core-B3pox577.mjs.map