autotel-edge 3.16.0 → 3.16.2

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/dist/logger.js CHANGED
@@ -1,7 +1,258 @@
1
1
  import { createContextKey, context, trace } from '@opentelemetry/api';
2
2
 
3
+ // src/api/logger.ts
4
+
5
+ // src/api/redact.ts
6
+ var DEFAULT_CENSOR = "[Redacted]";
7
+ function parsePath(path) {
8
+ if (typeof path !== "string" || path.length === 0) {
9
+ throw new Error(
10
+ `redact path must be a non-empty string, got: ${JSON.stringify(path)}`
11
+ );
12
+ }
13
+ if (path.includes("..")) {
14
+ throw new Error(
15
+ `redact path contains empty segment: ${JSON.stringify(path)}`
16
+ );
17
+ }
18
+ const openBracket = path.indexOf("[");
19
+ const closeBracket = path.indexOf("]");
20
+ if (openBracket !== -1 && closeBracket === -1 || closeBracket !== -1 && openBracket === -1) {
21
+ throw new Error(
22
+ `redact path has unclosed bracket: ${JSON.stringify(path)}`
23
+ );
24
+ }
25
+ if (openBracket !== -1 && closeBracket < openBracket) {
26
+ throw new Error(
27
+ `redact path has bracket close before open: ${JSON.stringify(path)}`
28
+ );
29
+ }
30
+ if (/\[\s*\]$/.test(path)) {
31
+ throw new Error(
32
+ `redact path has unclosed bracket: ${JSON.stringify(path)}`
33
+ );
34
+ }
35
+ if (/\][^.[\]]/.test(path) && !/\]\[/.test(path)) {
36
+ const afterClose = path.match(/\]([^.[\]]+)/);
37
+ if (afterClose) {
38
+ throw new Error(
39
+ `redact path has invalid characters after ']': ${JSON.stringify(path)}`
40
+ );
41
+ }
42
+ }
43
+ const segments = [];
44
+ const rx = /[^.[\]]+|\[(\d+|\*)\]/g;
45
+ let match;
46
+ let lastIndex = 0;
47
+ while ((match = rx.exec(path)) !== null) {
48
+ segments.push(match[1] ?? match[0]);
49
+ lastIndex = rx.lastIndex;
50
+ }
51
+ if (lastIndex < path.length) {
52
+ throw new Error(
53
+ `redact path has unexpected trailing content: ${JSON.stringify(path)}`
54
+ );
55
+ }
56
+ if (segments.length === 0) {
57
+ throw new Error(
58
+ `redact path produced no segments: ${JSON.stringify(path)}`
59
+ );
60
+ }
61
+ return segments;
62
+ }
63
+ function isPlainObject(value) {
64
+ if (value === null || typeof value !== "object") return false;
65
+ const proto = Object.getPrototypeOf(value);
66
+ return proto === Object.prototype || proto === null;
67
+ }
68
+ function deepClone(value) {
69
+ if (value === null || typeof value !== "object") return value;
70
+ if (Array.isArray(value)) return value.map((v) => deepClone(v));
71
+ if (!isPlainObject(value)) return value;
72
+ const result = {};
73
+ for (const key of Object.keys(value)) {
74
+ result[key] = deepClone(value[key]);
75
+ }
76
+ return result;
77
+ }
78
+ function buildPathTree(paths) {
79
+ const root = {};
80
+ for (const segments of paths) {
81
+ let node = root;
82
+ for (let i = 0; i < segments.length; i++) {
83
+ const seg = segments[i];
84
+ const isLast = i === segments.length - 1;
85
+ if (!node.children) node.children = {};
86
+ if (!node.children[seg]) node.children[seg] = {};
87
+ if (isLast) {
88
+ node.children[seg].redact = true;
89
+ }
90
+ node = node.children[seg];
91
+ }
92
+ }
93
+ return root;
94
+ }
95
+ function redactWithTree(obj, node, censor, remove, path = []) {
96
+ if (!node.children) return;
97
+ const applyCensor = (target, k, currentPath) => {
98
+ if (remove) {
99
+ delete target[k];
100
+ } else {
101
+ target[k] = typeof censor === "function" ? censor(target[k], currentPath) : censor;
102
+ }
103
+ };
104
+ for (const [key, childNode] of Object.entries(node.children)) {
105
+ if (key === "*") {
106
+ for (const k of Object.keys(obj)) {
107
+ const wildcardPath = [...path, k];
108
+ if (childNode.redact && !childNode.children) {
109
+ applyCensor(obj, k, wildcardPath);
110
+ } else if (childNode.redact && childNode.children) {
111
+ const child = obj[k];
112
+ if (child != null && typeof child === "object" && !Array.isArray(child)) {
113
+ redactWithTree(child, childNode, censor, remove, wildcardPath);
114
+ } else {
115
+ applyCensor(obj, k, wildcardPath);
116
+ }
117
+ } else if (childNode.children) {
118
+ const child = obj[k];
119
+ if (child != null && typeof child === "object") {
120
+ redactWithTree(child, childNode, censor, remove, wildcardPath);
121
+ }
122
+ }
123
+ }
124
+ continue;
125
+ }
126
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
127
+ const val = obj[key];
128
+ const currentPath = [...path, key];
129
+ if (childNode.redact && !childNode.children) {
130
+ applyCensor(obj, key, currentPath);
131
+ } else if (childNode.redact && childNode.children) {
132
+ if (val != null && typeof val === "object") {
133
+ redactWithTree(val, childNode, censor, remove, currentPath);
134
+ }
135
+ } else if (childNode.children && val != null && typeof val === "object") {
136
+ redactWithTree(val, childNode, censor, remove, currentPath);
137
+ }
138
+ }
139
+ }
140
+ var SENSITIVE_KEY_PATHS = [
141
+ "password",
142
+ "passwd",
143
+ "pwd",
144
+ "secret",
145
+ "token",
146
+ "apiKey",
147
+ "api_key",
148
+ "auth",
149
+ "credential",
150
+ "privateKey",
151
+ "private_key",
152
+ "authorization"
153
+ ];
154
+ var SENSITIVE_HEADER_PATHS = [
155
+ "req.headers.authorization",
156
+ "req.headers.cookie",
157
+ "headers.authorization",
158
+ "headers.cookie",
159
+ "request.headers.authorization",
160
+ "request.headers.cookie"
161
+ ];
162
+ var REDACT_PRESETS = {
163
+ /**
164
+ * Default: covers the same sensitive-key names as the main autotel package's
165
+ * `sensitiveKey` pattern, plus common request header paths.
166
+ *
167
+ * Redacted keys: password, passwd, pwd, secret, token, apiKey, auth,
168
+ * credential, privateKey, authorization
169
+ * Redacted headers: req.headers.authorization, req.headers.cookie, etc.
170
+ */
171
+ default: {
172
+ paths: [...SENSITIVE_KEY_PATHS, ...SENSITIVE_HEADER_PATHS]
173
+ },
174
+ /**
175
+ * Strict: everything in default, plus nested paths for bearer tokens,
176
+ * JWT fields, and API key fields at common depths.
177
+ */
178
+ strict: {
179
+ paths: [
180
+ ...SENSITIVE_KEY_PATHS,
181
+ ...SENSITIVE_HEADER_PATHS,
182
+ // Common nested auth shapes
183
+ "bearer",
184
+ "jwt",
185
+ "apiSecret",
186
+ "api_secret",
187
+ "accessToken",
188
+ "access_token",
189
+ "refreshToken",
190
+ "refresh_token",
191
+ "clientSecret",
192
+ "client_secret"
193
+ ]
194
+ },
195
+ /**
196
+ * PCI-DSS: credit card and payment-related fields.
197
+ */
198
+ "pci-dss": {
199
+ paths: [
200
+ "card",
201
+ "cardNumber",
202
+ "card_number",
203
+ "ccn",
204
+ "pan",
205
+ "cvv",
206
+ "cvc",
207
+ "expirationDate",
208
+ "expiration_date",
209
+ "exp",
210
+ "payment.card",
211
+ "payment.cardNumber",
212
+ "payment.cvv"
213
+ ]
214
+ }
215
+ };
216
+ function resolveConfig(config) {
217
+ if (typeof config === "string") {
218
+ const preset = REDACT_PRESETS[config];
219
+ if (!preset) {
220
+ throw new Error(
221
+ `Unknown redactor preset: "${config}". Available: ${Object.keys(REDACT_PRESETS).join(", ")}`
222
+ );
223
+ }
224
+ return preset;
225
+ }
226
+ return config;
227
+ }
228
+ function createRedactor(config) {
229
+ const { paths, censor = DEFAULT_CENSOR, remove = false } = resolveConfig(config);
230
+ if (paths.length === 0) {
231
+ return (obj) => obj;
232
+ }
233
+ const parsed = paths.map((p) => parsePath(p));
234
+ const tree = buildPathTree(parsed);
235
+ return function redactor(obj) {
236
+ if (obj == null || typeof obj !== "object") return obj;
237
+ const clone = deepClone(obj);
238
+ redactWithTree(clone, tree, censor, remove);
239
+ return clone;
240
+ };
241
+ }
242
+
3
243
  // src/api/logger.ts
4
244
  var LOG_LEVEL_KEY = createContextKey("autotel-edge-log-level");
245
+ var PINO_LEVELS = {
246
+ values: {
247
+ trace: 10,
248
+ debug: 20,
249
+ info: 30,
250
+ warn: 40,
251
+ error: 50,
252
+ fatal: 60,
253
+ silent: Infinity
254
+ }};
255
+ var LOGGER_VERSION = "autotel-edge";
5
256
  function getActiveLogLevel() {
6
257
  return context.active().getValue(LOG_LEVEL_KEY);
7
258
  }
@@ -20,62 +271,552 @@ function getTraceContext() {
20
271
  // First 16 chars for grouping
21
272
  };
22
273
  }
274
+ function isRecord(value) {
275
+ return typeof value === "object" && value !== null;
276
+ }
277
+ function toErrorAttrs(error) {
278
+ if (error instanceof Error) {
279
+ return {
280
+ error: {
281
+ message: error.message,
282
+ type: error.name,
283
+ stack: error.stack
284
+ }
285
+ };
286
+ }
287
+ return { error: { message: String(error), type: "Error" } };
288
+ }
289
+ function formatMessage(template, args) {
290
+ if (args.length === 0) return template;
291
+ let argIndex = 0;
292
+ const formatted = template.replaceAll(/%[sdjifoO%]/g, (token) => {
293
+ if (token === "%%") return "%";
294
+ if (argIndex >= args.length) return token;
295
+ const value = args[argIndex++];
296
+ switch (token) {
297
+ case "%d":
298
+ case "%i":
299
+ case "%f": {
300
+ return String(Number(value));
301
+ }
302
+ case "%j": {
303
+ try {
304
+ return JSON.stringify(value);
305
+ } catch {
306
+ return "[Circular]";
307
+ }
308
+ }
309
+ case "%s": {
310
+ return String(value);
311
+ }
312
+ case "%o":
313
+ case "%O": {
314
+ try {
315
+ return JSON.stringify(value);
316
+ } catch {
317
+ return String(value);
318
+ }
319
+ }
320
+ default: {
321
+ return token;
322
+ }
323
+ }
324
+ });
325
+ return formatted;
326
+ }
327
+ var ANSI_RESET = "\x1B[0m";
328
+ var ANSI_DIM = "\x1B[2m";
329
+ var ANSI_BOLD = "\x1B[1m";
330
+ var ANSI_COLORS = {
331
+ fatal: "\x1B[41m\x1B[37m",
332
+ // white on red bg
333
+ error: "\x1B[31m",
334
+ // red
335
+ warn: "\x1B[33m",
336
+ // yellow
337
+ info: "\x1B[36m",
338
+ // cyan
339
+ debug: "\x1B[34m",
340
+ // blue
341
+ trace: "\x1B[90m"
342
+ // gray
343
+ };
344
+ var LEVEL_SYMBOLS = {
345
+ fatal: "\u2717",
346
+ error: "\u2717",
347
+ warn: "\u26A0",
348
+ info: "\u25CF",
349
+ debug: "\u25E6",
350
+ trace: "\u2026"
351
+ };
352
+ function formatPrettyTimestamp() {
353
+ const d = /* @__PURE__ */ new Date();
354
+ const h = String(d.getHours()).padStart(2, "0");
355
+ const m = String(d.getMinutes()).padStart(2, "0");
356
+ const s = String(d.getSeconds()).padStart(2, "0");
357
+ const ms = String(d.getMilliseconds()).padStart(3, "0");
358
+ return `${h}:${m}:${s}.${ms}`;
359
+ }
360
+ function formatPrettyAttrs(attrs) {
361
+ const keys = Object.keys(attrs);
362
+ if (keys.length === 0) return "";
363
+ return "\n" + JSON.stringify(attrs, null, 2).split("\n").map((line) => ` ${line}`).join("\n");
364
+ }
365
+ function safeStringify(obj, depthLimit, edgeLimit) {
366
+ const ancestors = [];
367
+ return JSON.stringify(obj, function replacer(_key, value) {
368
+ if (typeof value === "object" && value !== null) {
369
+ while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) {
370
+ ancestors.pop();
371
+ }
372
+ if (ancestors.includes(value)) return "[Circular]";
373
+ if (ancestors.length >= depthLimit) return "[Object]";
374
+ ancestors.push(value);
375
+ if (!Array.isArray(value)) {
376
+ const keys = Object.keys(value);
377
+ if (keys.length > edgeLimit) {
378
+ const truncated = {};
379
+ for (let i = 0; i < edgeLimit; i++) {
380
+ truncated[keys[i]] = value[keys[i]];
381
+ }
382
+ truncated["..."] = `[${keys.length - edgeLimit} more properties]`;
383
+ return truncated;
384
+ }
385
+ }
386
+ }
387
+ return value;
388
+ });
389
+ }
390
+ function parseLogArgs(args) {
391
+ const [first, ...rest] = args;
392
+ if (typeof first === "string") {
393
+ return {
394
+ msg: formatMessage(first, rest),
395
+ attrs: void 0
396
+ };
397
+ }
398
+ if (first instanceof Error) {
399
+ return {
400
+ msg: typeof rest[0] === "string" ? formatMessage(rest[0], rest.slice(1)) : first.message,
401
+ attrs: toErrorAttrs(first)
402
+ };
403
+ }
404
+ if (isRecord(first)) {
405
+ return {
406
+ msg: typeof rest[0] === "string" ? formatMessage(rest[0], rest.slice(1)) : "",
407
+ attrs: first
408
+ };
409
+ }
410
+ return {
411
+ msg: String(first ?? ""),
412
+ attrs: void 0
413
+ };
414
+ }
23
415
  function createEdgeLogger(service, options) {
24
- const defaultLevel = options?.level || "info";
416
+ const customLevels = {
417
+ ...options?.customLevels
418
+ };
419
+ const availableLevels = options?.useOnlyCustomLevels ? { ...customLevels, silent: Infinity } : { ...PINO_LEVELS.values, ...customLevels };
420
+ const defaultLevel = options?.level ?? (options?.useOnlyCustomLevels ? Object.keys(customLevels)[0] : "info") ?? "info";
421
+ let currentLevel = defaultLevel;
25
422
  const pretty = options?.pretty || false;
26
- const levelPriority = {
27
- none: -1,
28
- debug: 0,
29
- info: 1,
30
- warn: 2,
31
- error: 3
423
+ const currentBindings = { ...options?.bindings };
424
+ const resolvedRedact = Array.isArray(options?.redact) ? { paths: options.redact } : options?.redact;
425
+ const redactor = resolvedRedact ? createRedactor(resolvedRedact) : null;
426
+ const msgPrefix = options?.msgPrefix;
427
+ const levelValues = availableLevels;
428
+ const levelListeners = [];
429
+ const onChildCallback = options?.onChild ?? (() => {
430
+ });
431
+ const listeners = /* @__PURE__ */ new Map();
432
+ let maxListeners = 10;
433
+ const messageKey = options?.messageKey ?? "msg";
434
+ const errorKey = options?.errorKey ?? "err";
435
+ const nestedKey = options?.nestedKey;
436
+ const serializers = { ...options?.serializers };
437
+ const bindingsFormatter = options?.formatters?.bindings;
438
+ const levelFormatter = options?.formatters?.level;
439
+ const logFormatter = options?.formatters?.log;
440
+ const mixin = options?.mixin;
441
+ const levelComparison = options?.levelComparison;
442
+ const mixinMergeStrategy = options?.mixinMergeStrategy ?? ((mergeObject, mixinObject) => ({ ...mergeObject, ...mixinObject }));
443
+ let enabled = options?.enabled ?? true;
444
+ const loggerName = options?.name;
445
+ const base = options?.base;
446
+ const timestamp = options?.timestamp ?? true;
447
+ const safe = options?.safe ?? true;
448
+ const crlf = options?.crlf ?? false;
449
+ const depthLimit = options?.depthLimit ?? 5;
450
+ const edgeLimitOpt = options?.edgeLimit ?? 100;
451
+ const hooks = options?.hooks;
452
+ const writeFn = options?.write;
453
+ const transmit = options?.transmit;
454
+ const bindingsChain = options?._bindingsChain ?? [];
455
+ const compareLevels = (current, expected, comparison) => {
456
+ if (typeof comparison === "function") return comparison(current, expected);
457
+ if (comparison === "DESC") return current <= expected;
458
+ return current >= expected;
459
+ };
460
+ const addListener = (event, listener, prepend = false) => {
461
+ const activeListeners = listeners.get(event) ?? [];
462
+ if (prepend) {
463
+ activeListeners.unshift(listener);
464
+ } else {
465
+ activeListeners.push(listener);
466
+ }
467
+ listeners.set(event, activeListeners);
468
+ if (event === "level-change") {
469
+ levelListeners.length = 0;
470
+ levelListeners.push(
471
+ ...listeners.get(event) ?? []
472
+ );
473
+ }
474
+ };
475
+ const notifyLevelChange = (nextLevel, previousLevel, instance) => {
476
+ const nextValue = levelValues[nextLevel] ?? Infinity;
477
+ const previousValue = levelValues[previousLevel] ?? Infinity;
478
+ const snapshot = [...levelListeners];
479
+ for (const listener of snapshot) {
480
+ listener(nextLevel, nextValue, previousLevel, previousValue, instance);
481
+ }
482
+ };
483
+ const removeEventListener = (event, listener) => {
484
+ const activeListeners = listeners.get(event);
485
+ if (!activeListeners) {
486
+ return;
487
+ }
488
+ const index = activeListeners.indexOf(listener);
489
+ if (index !== -1) {
490
+ activeListeners.splice(index, 1);
491
+ }
492
+ if (activeListeners.length === 0) {
493
+ listeners.delete(event);
494
+ } else {
495
+ listeners.set(event, activeListeners);
496
+ }
497
+ if (event === "level-change") {
498
+ levelListeners.length = 0;
499
+ levelListeners.push(
500
+ ...listeners.get(event) ?? []
501
+ );
502
+ }
32
503
  };
33
504
  const shouldLog = (level) => {
34
- const activeLevel = getActiveLogLevel() ?? defaultLevel;
35
- if (activeLevel === "none") return false;
36
- return levelPriority[level] >= levelPriority[activeLevel];
505
+ if (!enabled) return false;
506
+ const activeLevel = getActiveLogLevel() ?? currentLevel;
507
+ if (activeLevel === "silent") return false;
508
+ const currentValue = levelValues[activeLevel];
509
+ const expectedValue = levelValues[level];
510
+ if (currentValue === void 0 || expectedValue === void 0) return false;
511
+ return compareLevels(
512
+ expectedValue,
513
+ currentValue,
514
+ levelComparison
515
+ );
516
+ };
517
+ const stringify = (obj) => {
518
+ if (safe) {
519
+ return safeStringify(obj, depthLimit, edgeLimitOpt);
520
+ }
521
+ return JSON.stringify(obj);
522
+ };
523
+ const getTimestamp = () => {
524
+ if (timestamp === false) return void 0;
525
+ if (typeof timestamp === "function") return timestamp();
526
+ return (/* @__PURE__ */ new Date()).toISOString();
37
527
  };
38
- const log = (level, msg, attrs) => {
528
+ const writeOutput = (level, logObject) => {
529
+ if (writeFn) {
530
+ if (typeof writeFn === "function") {
531
+ writeFn(logObject);
532
+ } else if (typeof writeFn === "object" && writeFn[level]) {
533
+ writeFn[level](logObject);
534
+ } else {
535
+ console.log(stringify(logObject));
536
+ }
537
+ } else if (pretty) {
538
+ return;
539
+ } else {
540
+ const json = stringify(logObject);
541
+ console.log(crlf ? json + "\r\n" : json);
542
+ }
543
+ };
544
+ const applySerializers = (obj) => {
545
+ if (Object.keys(serializers).length === 0) return obj;
546
+ return Object.fromEntries(
547
+ Object.entries(obj).map(([key, value]) => [
548
+ key,
549
+ key in serializers ? serializers[key](value) : value
550
+ ])
551
+ );
552
+ };
553
+ const emitTransmit = (level, rawArgs) => {
554
+ if (!transmit) return;
555
+ if (transmit.level) {
556
+ const transmitValue = levelValues[transmit.level];
557
+ const logValue = levelValues[level];
558
+ if (transmitValue !== void 0 && logValue !== void 0 && logValue < transmitValue) {
559
+ return;
560
+ }
561
+ }
562
+ const processedMessages = rawArgs.map((m) => {
563
+ if (typeof m !== "object" || m === null) return m;
564
+ const serialized = applySerializers(m);
565
+ return redactor ? redactor(serialized) : serialized;
566
+ });
567
+ const processedBindings = bindingsChain.map((b) => {
568
+ const serialized = applySerializers({ ...b });
569
+ return redactor ? redactor(serialized) : serialized;
570
+ });
571
+ const logEvent = {
572
+ ts: Date.now(),
573
+ messages: processedMessages,
574
+ bindings: processedBindings,
575
+ level: { label: level, value: levelValues[level] }
576
+ };
577
+ transmit.send(level, logEvent);
578
+ };
579
+ const log = (level, msg, attrs, rawArgs) => {
39
580
  if (!shouldLog(level)) return;
40
581
  const ctx = getTraceContext();
582
+ const message = msgPrefix ? `${msgPrefix}${msg}` : msg;
583
+ const baseBindings = bindingsFormatter ? bindingsFormatter({ ...currentBindings }) : { ...currentBindings };
584
+ const serializedAttrs = attrs ? Object.fromEntries(
585
+ Object.entries(attrs).map(([key, value]) => [
586
+ key,
587
+ key in serializers ? serializers[key](value) : value
588
+ ])
589
+ ) : void 0;
590
+ const mergeObject = nestedKey ? { [nestedKey]: serializedAttrs ?? {} } : serializedAttrs ?? {};
591
+ const mixinObject = mixin?.(mergeObject, levelValues[level], logger) ?? {};
592
+ const mergedLogObject = mixinMergeStrategy(mergeObject, mixinObject);
593
+ const formattedLogObject = logFormatter ? logFormatter(mergedLogObject) : mergedLogObject;
594
+ const formattedLevel = levelFormatter ? levelFormatter(level, levelValues[level]) : {
595
+ level: logger.useLevelLabels ? level : levelValues[level]
596
+ };
597
+ const ts = getTimestamp();
41
598
  const logEntry = {
42
- level,
599
+ ...formattedLevel,
600
+ ...loggerName === void 0 ? {} : { name: loggerName },
43
601
  service,
44
- msg,
45
- ...attrs,
602
+ ...message === "" ? {} : { [messageKey]: message },
603
+ ...base === null || base === void 0 ? {} : base,
604
+ ...baseBindings,
605
+ ...formattedLogObject,
46
606
  ...ctx,
47
607
  // Auto-inject traceId, spanId, correlationId
48
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
608
+ ...ts === void 0 ? {} : { timestamp: ts }
49
609
  };
50
- if (pretty) {
51
- const traceInfo = ctx ? ` [${ctx.traceId.slice(0, 8)}.../${ctx.spanId.slice(0, 8)}...]` : "";
610
+ if (serializedAttrs && !nestedKey && errorKey !== "error" && "error" in logEntry) {
611
+ logEntry[errorKey] = logEntry.error;
612
+ delete logEntry.error;
613
+ }
614
+ if (pretty && !writeFn) {
615
+ const color = ANSI_COLORS[level] ?? ANSI_COLORS.info;
616
+ const symbol = LEVEL_SYMBOLS[level] ?? "\u25CF";
617
+ const time = formatPrettyTimestamp();
618
+ const traceInfo = ctx ? ` ${ANSI_DIM}[${ctx.traceId.slice(0, 8)}/${ctx.spanId.slice(0, 8)}]${ANSI_RESET}` : "";
619
+ const prettyAttrs = {
620
+ ...baseBindings,
621
+ ...formattedLogObject
622
+ };
623
+ const safeAttrs = redactor ? redactor(prettyAttrs) : prettyAttrs;
624
+ const attrsStr = formatPrettyAttrs(safeAttrs);
52
625
  console.log(
53
- `[${level.toUpperCase()}]${traceInfo} ${service}: ${msg}`,
54
- attrs || ""
626
+ `${ANSI_DIM}${time}${ANSI_RESET} ${color}${ANSI_BOLD}${symbol} ${level.toUpperCase()}${ANSI_RESET}${traceInfo} ${ANSI_DIM}(${service})${ANSI_RESET} ${message}${attrsStr}`
55
627
  );
56
628
  } else {
57
- console.log(JSON.stringify(logEntry));
629
+ const safeEntry = redactor ? redactor(logEntry) : logEntry;
630
+ writeOutput(level, safeEntry);
58
631
  }
632
+ emitTransmit(level, rawArgs ?? []);
59
633
  };
60
- return {
61
- info: (msg, attrs) => log("info", msg, attrs),
62
- error: (msg, error, attrs) => {
63
- const errorAttrs = error instanceof Error ? {
64
- error: error.message,
65
- stack: error.stack,
66
- name: error.name,
67
- ...attrs
68
- } : { error: String(error), ...attrs };
69
- log("error", msg, errorAttrs);
634
+ const makeLogMethod = (levelName) => {
635
+ return ((...args) => {
636
+ if (hooks?.logMethod) {
637
+ const method = ((...methodArgs) => {
638
+ const { msg: msg2, attrs: attrs2 } = parseLogArgs(methodArgs);
639
+ log(levelName, msg2, attrs2, methodArgs);
640
+ });
641
+ hooks.logMethod.call(logger, args, method, levelValues[levelName]);
642
+ return;
643
+ }
644
+ const { msg, attrs } = parseLogArgs(args);
645
+ log(levelName, msg, attrs, args);
646
+ });
647
+ };
648
+ const logger = {
649
+ version: LOGGER_VERSION,
650
+ get name() {
651
+ return loggerName;
652
+ },
653
+ levels: {
654
+ values: levelValues,
655
+ labels: Object.fromEntries(
656
+ Object.entries(levelValues).map(([label, value]) => [value, label])
657
+ )
658
+ },
659
+ useLevelLabels: options?.useLevelLabels ?? false,
660
+ customLevels: { ...customLevels },
661
+ useOnlyCustomLevels: options?.useOnlyCustomLevels ?? false,
662
+ get level() {
663
+ return currentLevel;
664
+ },
665
+ set level(level) {
666
+ const previousLevel = currentLevel;
667
+ currentLevel = level;
668
+ notifyLevelChange(level, previousLevel, logger);
669
+ },
670
+ get levelVal() {
671
+ return levelValues[currentLevel] ?? Infinity;
672
+ },
673
+ get msgPrefix() {
674
+ return msgPrefix;
675
+ },
676
+ onChild: onChildCallback,
677
+ get enabled() {
678
+ return enabled;
679
+ },
680
+ set enabled(value) {
681
+ enabled = value;
682
+ },
683
+ info: makeLogMethod("info"),
684
+ error: makeLogMethod("error"),
685
+ warn: makeLogMethod("warn"),
686
+ debug: makeLogMethod("debug"),
687
+ trace: makeLogMethod("trace"),
688
+ fatal: makeLogMethod("fatal"),
689
+ silent: (() => {
690
+ }),
691
+ child: (bindings, childOptions) => {
692
+ const childLogger = createEdgeLogger(service, {
693
+ level: childOptions?.level ?? currentLevel,
694
+ pretty,
695
+ bindings: { ...currentBindings, ...bindings },
696
+ redact: childOptions?.redact ?? options?.redact,
697
+ msgPrefix: childOptions?.msgPrefix === void 0 ? msgPrefix : `${msgPrefix ?? ""}${childOptions.msgPrefix}`,
698
+ useLevelLabels: logger.useLevelLabels,
699
+ onChild: onChildCallback,
700
+ enabled,
701
+ messageKey,
702
+ errorKey,
703
+ nestedKey,
704
+ serializers: { ...serializers, ...childOptions?.serializers },
705
+ formatters: {
706
+ level: childOptions?.formatters?.level ?? levelFormatter,
707
+ bindings: childOptions?.formatters?.bindings ?? bindingsFormatter,
708
+ log: childOptions?.formatters?.log ?? logFormatter
709
+ },
710
+ mixin,
711
+ mixinMergeStrategy,
712
+ customLevels,
713
+ useOnlyCustomLevels: options?.useOnlyCustomLevels,
714
+ levelComparison: options?.levelComparison,
715
+ name: loggerName,
716
+ base,
717
+ timestamp,
718
+ safe,
719
+ crlf,
720
+ depthLimit,
721
+ edgeLimit: edgeLimitOpt,
722
+ hooks,
723
+ write: writeFn,
724
+ transmit,
725
+ _bindingsChain: [...bindingsChain, bindings]
726
+ });
727
+ onChildCallback(childLogger);
728
+ return childLogger;
729
+ },
730
+ isLevelEnabled: (level) => shouldLog(level),
731
+ bindings: () => ({ ...currentBindings }),
732
+ setBindings: (bindings) => {
733
+ for (const [key, value] of Object.entries(bindings)) {
734
+ if (!(key in currentBindings)) {
735
+ currentBindings[key] = value;
736
+ }
737
+ }
738
+ },
739
+ flush: (cb) => {
740
+ cb?.();
70
741
  },
71
- warn: (msg, attrs) => log("warn", msg, attrs),
72
- debug: (msg, attrs) => log("debug", msg, attrs)
742
+ emit: (event, ...args) => {
743
+ const activeListeners = listeners.get(event);
744
+ if (!activeListeners || activeListeners.length === 0) {
745
+ return false;
746
+ }
747
+ const snapshot = [...activeListeners];
748
+ for (const listener of snapshot) {
749
+ listener(...args);
750
+ }
751
+ return true;
752
+ },
753
+ eventNames: () => [...listeners.keys()],
754
+ getMaxListeners: () => maxListeners,
755
+ listenerCount: (event) => listeners.get(event)?.length ?? 0,
756
+ listeners: (event) => [...listeners.get(event) ?? []],
757
+ on: (event, listener) => {
758
+ addListener(event, listener);
759
+ return logger;
760
+ },
761
+ addListener: (event, listener) => {
762
+ addListener(event, listener);
763
+ return logger;
764
+ },
765
+ once: (event, listener) => {
766
+ const wrapped = (...args) => {
767
+ removeEventListener(event, wrapped);
768
+ listener(...args);
769
+ };
770
+ addListener(event, wrapped);
771
+ return logger;
772
+ },
773
+ prependListener: (event, listener) => {
774
+ addListener(event, listener, true);
775
+ return logger;
776
+ },
777
+ prependOnceListener: (event, listener) => {
778
+ const wrapped = (...args) => {
779
+ removeEventListener(event, wrapped);
780
+ listener(...args);
781
+ };
782
+ addListener(event, wrapped, true);
783
+ return logger;
784
+ },
785
+ rawListeners: (event) => [...listeners.get(event) ?? []],
786
+ off: (event, listener) => {
787
+ removeEventListener(event, listener);
788
+ return logger;
789
+ },
790
+ removeAllListeners: (event) => {
791
+ if (event === void 0) {
792
+ listeners.clear();
793
+ levelListeners.length = 0;
794
+ return logger;
795
+ }
796
+ listeners.delete(event);
797
+ if (event === "level-change") {
798
+ levelListeners.length = 0;
799
+ }
800
+ return logger;
801
+ },
802
+ removeListener: (event, listener) => {
803
+ removeEventListener(event, listener);
804
+ return logger;
805
+ },
806
+ setMaxListeners: (n) => {
807
+ maxListeners = n;
808
+ return logger;
809
+ }
73
810
  };
811
+ for (const levelName of Object.keys(customLevels)) {
812
+ logger[levelName] = makeLogMethod(levelName);
813
+ }
814
+ return logger;
74
815
  }
75
816
  function getEdgeTraceContext() {
76
817
  return getTraceContext();
77
818
  }
78
819
 
79
- export { createEdgeLogger, getActiveLogLevel, getEdgeTraceContext, runWithLogLevel };
820
+ export { REDACT_PRESETS, createEdgeLogger, createRedactor, getActiveLogLevel, getEdgeTraceContext, runWithLogLevel };
80
821
  //# sourceMappingURL=logger.js.map
81
822
  //# sourceMappingURL=logger.js.map