@contractspec/lib.logger 1.56.1 → 1.58.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.
Files changed (108) hide show
  1. package/dist/context.browser.d.ts +44 -0
  2. package/dist/context.browser.d.ts.map +1 -0
  3. package/dist/context.browser.js +77 -0
  4. package/dist/context.d.ts +22 -0
  5. package/dist/context.d.ts.map +1 -0
  6. package/dist/context.js +1 -0
  7. package/dist/context.node.d.ts +43 -0
  8. package/dist/context.node.d.ts.map +1 -0
  9. package/dist/context.node.js +62 -0
  10. package/dist/elysia-plugin.d.ts +58 -0
  11. package/dist/elysia-plugin.d.ts.map +1 -0
  12. package/dist/elysia-plugin.js +793 -0
  13. package/dist/formatters.d.ts +25 -0
  14. package/dist/formatters.d.ts.map +1 -0
  15. package/dist/formatters.js +232 -0
  16. package/dist/index.browser.d.ts +8 -0
  17. package/dist/index.browser.d.ts.map +1 -0
  18. package/dist/index.browser.js +728 -0
  19. package/dist/index.d.ts +9 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +800 -0
  22. package/dist/logger.browser.d.ts +48 -0
  23. package/dist/logger.browser.d.ts.map +1 -0
  24. package/dist/logger.browser.js +722 -0
  25. package/dist/logger.d.ts +2 -0
  26. package/dist/logger.d.ts.map +1 -0
  27. package/dist/logger.js +707 -0
  28. package/dist/logger.node.d.ts +48 -0
  29. package/dist/logger.node.d.ts.map +1 -0
  30. package/dist/logger.node.js +707 -0
  31. package/dist/node/context.js +0 -0
  32. package/dist/node/context.node.js +61 -0
  33. package/dist/node/elysia-plugin.js +792 -0
  34. package/dist/node/formatters.js +231 -0
  35. package/dist/node/index.js +799 -0
  36. package/dist/node/logger.js +706 -0
  37. package/dist/node/logger.node.js +706 -0
  38. package/dist/node/timer.js +122 -0
  39. package/dist/node/tracer.js +274 -0
  40. package/dist/node/tracer.node.js +274 -0
  41. package/dist/node/types.js +13 -0
  42. package/dist/timer.d.ts +99 -0
  43. package/dist/timer.d.ts.map +1 -0
  44. package/dist/timer.js +123 -0
  45. package/dist/tracer.browser.d.ts +47 -0
  46. package/dist/tracer.browser.d.ts.map +1 -0
  47. package/dist/tracer.browser.js +290 -0
  48. package/dist/tracer.d.ts +2 -0
  49. package/dist/tracer.d.ts.map +1 -0
  50. package/dist/tracer.js +275 -0
  51. package/dist/tracer.node.d.ts +47 -0
  52. package/dist/tracer.node.d.ts.map +1 -0
  53. package/dist/tracer.node.js +275 -0
  54. package/dist/types.d.ts +68 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +14 -0
  57. package/package.json +112 -42
  58. package/dist/context.browser.d.mts +0 -49
  59. package/dist/context.browser.d.mts.map +0 -1
  60. package/dist/context.browser.mjs +0 -89
  61. package/dist/context.browser.mjs.map +0 -1
  62. package/dist/context.d.mts +0 -17
  63. package/dist/context.d.mts.map +0 -1
  64. package/dist/context.mjs +0 -1
  65. package/dist/context.node.d.mts +0 -48
  66. package/dist/context.node.d.mts.map +0 -1
  67. package/dist/context.node.mjs +0 -79
  68. package/dist/context.node.mjs.map +0 -1
  69. package/dist/elysia-plugin.d.mts +0 -63
  70. package/dist/elysia-plugin.d.mts.map +0 -1
  71. package/dist/elysia-plugin.mjs +0 -84
  72. package/dist/elysia-plugin.mjs.map +0 -1
  73. package/dist/formatters.d.mts +0 -29
  74. package/dist/formatters.d.mts.map +0 -1
  75. package/dist/formatters.mjs +0 -180
  76. package/dist/formatters.mjs.map +0 -1
  77. package/dist/index.browser.d.mts +0 -7
  78. package/dist/index.browser.mjs +0 -8
  79. package/dist/index.d.mts +0 -8
  80. package/dist/index.mjs +0 -9
  81. package/dist/logger.browser.d.mts +0 -51
  82. package/dist/logger.browser.d.mts.map +0 -1
  83. package/dist/logger.browser.mjs +0 -190
  84. package/dist/logger.browser.mjs.map +0 -1
  85. package/dist/logger.d.mts +0 -2
  86. package/dist/logger.mjs +0 -3
  87. package/dist/logger.node.d.mts +0 -51
  88. package/dist/logger.node.d.mts.map +0 -1
  89. package/dist/logger.node.mjs +0 -190
  90. package/dist/logger.node.mjs.map +0 -1
  91. package/dist/timer.d.mts +0 -103
  92. package/dist/timer.d.mts.map +0 -1
  93. package/dist/timer.mjs +0 -165
  94. package/dist/timer.mjs.map +0 -1
  95. package/dist/tracer.browser.d.mts +0 -51
  96. package/dist/tracer.browser.d.mts.map +0 -1
  97. package/dist/tracer.browser.mjs +0 -116
  98. package/dist/tracer.browser.mjs.map +0 -1
  99. package/dist/tracer.d.mts +0 -2
  100. package/dist/tracer.mjs +0 -3
  101. package/dist/tracer.node.d.mts +0 -51
  102. package/dist/tracer.node.d.mts.map +0 -1
  103. package/dist/tracer.node.mjs +0 -116
  104. package/dist/tracer.node.mjs.map +0 -1
  105. package/dist/types.d.mts +0 -71
  106. package/dist/types.d.mts.map +0 -1
  107. package/dist/types.mjs +0 -14
  108. package/dist/types.mjs.map +0 -1
@@ -0,0 +1,728 @@
1
+ // @bun
2
+ // src/context.browser.ts
3
+ import"zone.js";
4
+ var ZONE = globalThis.Zone;
5
+ var STORE_KEY = "__lssm_log_context_data__";
6
+ function getStore() {
7
+ if (!ZONE)
8
+ return;
9
+ return ZONE.current.get(STORE_KEY);
10
+ }
11
+
12
+ class LogContext {
13
+ static instance;
14
+ static fallbackCounter = 0;
15
+ static getInstance() {
16
+ if (!LogContext.instance) {
17
+ LogContext.instance = new LogContext;
18
+ }
19
+ return LogContext.instance;
20
+ }
21
+ run(context, fn) {
22
+ const contextData = {
23
+ context: { ...context },
24
+ trace: this.getCurrentTrace()
25
+ };
26
+ if (!ZONE) {
27
+ return fn();
28
+ }
29
+ const zone = ZONE.current.fork({
30
+ name: "log-context",
31
+ properties: { [STORE_KEY]: contextData }
32
+ });
33
+ return zone.run(fn);
34
+ }
35
+ extend(additionalContext, fn) {
36
+ const currentContext = this.getContext();
37
+ const mergedContext = {
38
+ ...currentContext,
39
+ ...additionalContext
40
+ };
41
+ return this.run(mergedContext, fn);
42
+ }
43
+ set(key, value) {
44
+ const current = getStore();
45
+ if (current) {
46
+ current.context[key] = value;
47
+ }
48
+ }
49
+ get(key) {
50
+ const current = getStore();
51
+ return current?.context?.[key];
52
+ }
53
+ getContext() {
54
+ const current = getStore();
55
+ return current?.context || {};
56
+ }
57
+ setTrace(trace) {
58
+ const current = getStore();
59
+ if (current) {
60
+ current.trace = trace;
61
+ }
62
+ }
63
+ getCurrentTrace() {
64
+ const current = getStore();
65
+ return current?.trace;
66
+ }
67
+ generateId() {
68
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
69
+ return crypto.randomUUID();
70
+ }
71
+ LogContext.fallbackCounter += 1;
72
+ return `log-${LogContext.fallbackCounter}`;
73
+ }
74
+ }
75
+
76
+ // src/types.ts
77
+ var LogLevel;
78
+ ((LogLevel2) => {
79
+ LogLevel2[LogLevel2["TRACE"] = 0] = "TRACE";
80
+ LogLevel2[LogLevel2["DEBUG"] = 1] = "DEBUG";
81
+ LogLevel2[LogLevel2["INFO"] = 2] = "INFO";
82
+ LogLevel2[LogLevel2["WARN"] = 3] = "WARN";
83
+ LogLevel2[LogLevel2["ERROR"] = 4] = "ERROR";
84
+ LogLevel2[LogLevel2["FATAL"] = 5] = "FATAL";
85
+ })(LogLevel ||= {});
86
+
87
+ // src/timer.ts
88
+ class Timer {
89
+ id;
90
+ startTime;
91
+ laps = [];
92
+ stopped = false;
93
+ stopTime;
94
+ constructor(id) {
95
+ this.id = id || crypto.randomUUID();
96
+ this.startTime = performance.now();
97
+ }
98
+ stop() {
99
+ if (this.stopped) {
100
+ return this.getElapsed();
101
+ }
102
+ this.stopTime = performance.now();
103
+ this.stopped = true;
104
+ const elapsed = this.stopTime - this.startTime;
105
+ this.laps.push({
106
+ label: "stop",
107
+ time: this.stopTime,
108
+ elapsed
109
+ });
110
+ return elapsed;
111
+ }
112
+ lap(label) {
113
+ if (this.stopped) {
114
+ return this.getElapsed();
115
+ }
116
+ const now = performance.now();
117
+ const elapsed = now - this.startTime;
118
+ this.laps.push({
119
+ label: label || `lap-${this.laps.length + 1}`,
120
+ time: now,
121
+ elapsed
122
+ });
123
+ return elapsed;
124
+ }
125
+ getElapsed() {
126
+ if (this.stopped && this.stopTime) {
127
+ return this.stopTime - this.startTime;
128
+ }
129
+ return performance.now() - this.startTime;
130
+ }
131
+ getLaps() {
132
+ return [...this.laps];
133
+ }
134
+ getSummary() {
135
+ return {
136
+ id: this.id,
137
+ totalTime: this.getElapsed(),
138
+ isRunning: !this.stopped,
139
+ laps: this.getLaps()
140
+ };
141
+ }
142
+ reset() {
143
+ this.startTime = performance.now();
144
+ this.laps = [];
145
+ this.stopped = false;
146
+ this.stopTime = undefined;
147
+ }
148
+ }
149
+
150
+ class TimerManager {
151
+ timers = new Map;
152
+ start(id) {
153
+ const timer = new Timer(id);
154
+ this.timers.set(timer.id, timer);
155
+ return timer;
156
+ }
157
+ get(id) {
158
+ return this.timers.get(id);
159
+ }
160
+ stop(id) {
161
+ const timer = this.timers.get(id);
162
+ if (timer) {
163
+ const elapsed = timer.stop();
164
+ this.timers.delete(id);
165
+ return elapsed;
166
+ }
167
+ return;
168
+ }
169
+ getActive() {
170
+ return Array.from(this.timers.values()).filter((timer) => !timer.getSummary().isRunning === false);
171
+ }
172
+ clear() {
173
+ this.timers.clear();
174
+ }
175
+ getSummary() {
176
+ return Array.from(this.timers.values()).map((timer) => timer.getSummary());
177
+ }
178
+ }
179
+ async function timed(operation, options) {
180
+ const timer = new Timer(options?.id);
181
+ try {
182
+ const result = await operation();
183
+ const elapsed = timer.stop();
184
+ options?.onComplete?.(elapsed);
185
+ return { result, elapsed, timer };
186
+ } catch (error) {
187
+ timer.stop();
188
+ throw error;
189
+ }
190
+ }
191
+ function timedSync(operation, options) {
192
+ const timer = new Timer(options?.id);
193
+ try {
194
+ const result = operation();
195
+ const elapsed = timer.stop();
196
+ options?.onComplete?.(elapsed);
197
+ return { result, elapsed, timer };
198
+ } catch (error) {
199
+ timer.stop();
200
+ throw error;
201
+ }
202
+ }
203
+
204
+ // src/formatters.ts
205
+ var colors = {
206
+ reset: "\x1B[0m",
207
+ bright: "\x1B[1m",
208
+ dim: "\x1B[2m",
209
+ red: "\x1B[31m",
210
+ green: "\x1B[32m",
211
+ yellow: "\x1B[33m",
212
+ blue: "\x1B[34m",
213
+ magenta: "\x1B[35m",
214
+ cyan: "\x1B[36m",
215
+ white: "\x1B[37m",
216
+ gray: "\x1B[90m",
217
+ bgRed: "\x1B[41m",
218
+ bgYellow: "\x1B[43m"
219
+ };
220
+ var levelConfig = {
221
+ [0 /* TRACE */]: { color: colors.gray, symbol: "\u25CB", name: "TRACE" },
222
+ [1 /* DEBUG */]: { color: colors.blue, symbol: "\u25CF", name: "DEBUG" },
223
+ [2 /* INFO */]: { color: colors.green, symbol: "\u25CF", name: "INFO " },
224
+ [3 /* WARN */]: { color: colors.yellow, symbol: "\u25B2", name: "WARN " },
225
+ [4 /* ERROR */]: { color: colors.red, symbol: "\u2716", name: "ERROR" },
226
+ [5 /* FATAL */]: {
227
+ color: colors.bgRed + colors.white,
228
+ symbol: "\uD83D\uDC80",
229
+ name: "FATAL"
230
+ }
231
+ };
232
+
233
+ class DevFormatter {
234
+ enableColors;
235
+ constructor(enableColors = true) {
236
+ this.enableColors = enableColors;
237
+ }
238
+ format(entry) {
239
+ const parts = [];
240
+ const config = levelConfig[entry.level];
241
+ const timestamp = this.formatTimestamp(entry.timestamp);
242
+ parts.push(this.colorize(timestamp, colors.gray));
243
+ const levelText = `${config.symbol} ${config.name}`;
244
+ parts.push(this.colorize(levelText, config.color));
245
+ if (entry.traceId) {
246
+ const traceInfo = this.formatTraceInfo(entry);
247
+ parts.push(this.colorize(traceInfo, colors.cyan));
248
+ }
249
+ parts.push(this.colorize(entry.message, colors.white));
250
+ if (entry.duration !== undefined) {
251
+ const durationText = `(${this.formatDuration(entry.duration)})`;
252
+ parts.push(this.colorize(durationText, colors.magenta));
253
+ }
254
+ let output = parts.join(" ");
255
+ if (entry.context && Object.keys(entry.context).length > 0) {
256
+ output += `
257
+ ` + this.formatContext(entry.context);
258
+ }
259
+ if (entry.metadata && Object.keys(entry.metadata).length > 0) {
260
+ output += `
261
+ ` + this.formatMetadata(entry.metadata);
262
+ }
263
+ if (entry.error) {
264
+ output += `
265
+ ` + this.formatError(entry.error);
266
+ }
267
+ if (entry.tags && entry.tags.length > 0) {
268
+ const tagsText = entry.tags.map((tag) => `#${tag}`).join(" ");
269
+ output += `
270
+ ` + this.colorize(`Tags: ${tagsText}`, colors.blue);
271
+ }
272
+ return output;
273
+ }
274
+ formatTimestamp(timestamp) {
275
+ return timestamp.toISOString().substring(11, 23);
276
+ }
277
+ formatTraceInfo(entry) {
278
+ const parts = [`trace:${entry.traceId?.substring(0, 8) || "unknown"}`];
279
+ if (entry.spanId && entry.spanId.length >= 8) {
280
+ parts.push(`span:${entry.spanId.substring(0, 8)}`);
281
+ }
282
+ if (entry.parentId && entry.parentId.length >= 8) {
283
+ parts.push(`parent:${entry.parentId.substring(0, 8)}`);
284
+ }
285
+ return `[${parts.join("|")}]`;
286
+ }
287
+ formatDuration(duration) {
288
+ if (duration < 1) {
289
+ return `${(duration * 1000).toFixed(0)}\u03BCs`;
290
+ } else if (duration < 1000) {
291
+ return `${duration.toFixed(2)}ms`;
292
+ } else {
293
+ return `${(duration / 1000).toFixed(2)}s`;
294
+ }
295
+ }
296
+ formatContext(context) {
297
+ const formatted = this.formatObject(context, 2);
298
+ return this.colorize(`Context: ${formatted}`, colors.cyan);
299
+ }
300
+ formatMetadata(metadata) {
301
+ const formatted = this.formatObject(metadata, 2);
302
+ return this.colorize(`Metadata: ${formatted}`, colors.blue);
303
+ }
304
+ formatError(error) {
305
+ let output = this.colorize(`Error: ${error.name}: ${error.message}`, colors.red);
306
+ if (error.stack) {
307
+ const stackLines = error.stack.split(`
308
+ `).slice(1, 6);
309
+ const indentedStack = stackLines.map((line) => ` ${line}`).join(`
310
+ `);
311
+ output += `
312
+ ` + this.colorize(indentedStack, colors.gray);
313
+ }
314
+ return output;
315
+ }
316
+ formatObject(obj, indent = 0) {
317
+ const spaces = " ".repeat(indent);
318
+ const entries = Object.entries(obj);
319
+ if (entries.length === 0)
320
+ return "{}";
321
+ if (entries[0] && typeof entries[0][1] !== "object") {
322
+ return `{ ${entries[0][0]}: ${this.formatValue(entries[0][1])} }`;
323
+ }
324
+ const formatted = entries.map(([key, value]) => {
325
+ return `${spaces} ${key}: ${this.formatValue(value, indent + 2)}`;
326
+ }).join(`
327
+ `);
328
+ return `{
329
+ ${formatted}
330
+ ${spaces}}`;
331
+ }
332
+ formatValue(value, indent = 0) {
333
+ if (value === null)
334
+ return "null";
335
+ if (value === undefined)
336
+ return "undefined";
337
+ if (typeof value === "string")
338
+ return `"${value}"`;
339
+ if (typeof value === "boolean" || typeof value === "number")
340
+ return String(value);
341
+ if (value instanceof Date)
342
+ return value.toISOString();
343
+ if (Array.isArray(value)) {
344
+ if (value.length === 0)
345
+ return "[]";
346
+ return `[${value.map((v) => this.formatValue(v)).join(", ")}]`;
347
+ }
348
+ if (typeof value === "object") {
349
+ return this.formatObject(value, indent);
350
+ }
351
+ return String(value);
352
+ }
353
+ colorize(text, color) {
354
+ if (!this.enableColors)
355
+ return text;
356
+ return `${color}${text}${colors.reset}`;
357
+ }
358
+ }
359
+
360
+ class ProductionFormatter {
361
+ format(entry) {
362
+ const logObject = {
363
+ timestamp: entry.timestamp,
364
+ level: entry.level,
365
+ message: entry.message
366
+ };
367
+ if (entry.traceId) {
368
+ logObject.traceId = entry.traceId;
369
+ }
370
+ if (entry.spanId) {
371
+ logObject.spanId = entry.spanId;
372
+ }
373
+ if (entry.parentId) {
374
+ logObject.parentId = entry.parentId;
375
+ }
376
+ if (entry.duration !== undefined) {
377
+ logObject.duration = entry.duration;
378
+ }
379
+ if (entry.context && Object.keys(entry.context).length > 0) {
380
+ logObject.context = entry.context;
381
+ }
382
+ if (entry.metadata && Object.keys(entry.metadata).length > 0) {
383
+ logObject.metadata = entry.metadata;
384
+ }
385
+ if (entry.error) {
386
+ logObject.error = {
387
+ name: entry.error.name,
388
+ message: entry.error.message,
389
+ stack: entry.error.stack
390
+ };
391
+ }
392
+ if (entry.tags && entry.tags.length > 0) {
393
+ logObject.tags = entry.tags;
394
+ }
395
+ return JSON.stringify(logObject);
396
+ }
397
+ }
398
+
399
+ class CustomFormatter {
400
+ template;
401
+ dateFormat;
402
+ constructor(template = "{timestamp} [{level}] {message}", dateFormat) {
403
+ this.template = template;
404
+ this.dateFormat = dateFormat || ((date) => date.toISOString());
405
+ }
406
+ format(entry) {
407
+ const levelName = LogLevel[entry.level];
408
+ const timestamp = this.dateFormat(entry.timestamp);
409
+ let formatted = this.template.replace("{timestamp}", timestamp).replace("{level}", levelName).replace("{message}", entry.message).replace("{traceId}", entry.traceId || "").replace("{spanId}", entry.spanId || "").replace("{duration}", entry.duration?.toString() || "");
410
+ if (entry.context) {
411
+ formatted = formatted.replace("{context}", JSON.stringify(entry.context));
412
+ }
413
+ if (entry.metadata) {
414
+ formatted = formatted.replace("{metadata}", JSON.stringify(entry.metadata));
415
+ }
416
+ return formatted;
417
+ }
418
+ }
419
+
420
+ // src/tracer.browser.ts
421
+ class Tracer {
422
+ context;
423
+ activeSpans = new Map;
424
+ constructor() {
425
+ this.context = LogContext.getInstance();
426
+ }
427
+ startSpan(options) {
428
+ const parentTrace = this.context.getCurrentTrace();
429
+ const traceId = parentTrace?.traceId || this.generateTraceId();
430
+ const span = {
431
+ traceId,
432
+ parentId: parentTrace?.spanId,
433
+ spanId: this.generateSpanId(),
434
+ operationType: options.operationType,
435
+ operationName: options.operationName,
436
+ startTime: performance.now(),
437
+ metadata: { ...options.metadata },
438
+ tags: [...options.tags || []]
439
+ };
440
+ this.activeSpans.set(span.spanId, span);
441
+ this.context.setTrace(span);
442
+ return span;
443
+ }
444
+ finishSpan(spanId) {
445
+ const span = this.activeSpans.get(spanId);
446
+ if (!span) {
447
+ return;
448
+ }
449
+ const duration = performance.now() - span.startTime;
450
+ this.activeSpans.delete(spanId);
451
+ const currentTrace = this.context.getCurrentTrace();
452
+ if (currentTrace?.spanId === spanId && span.parentId) {
453
+ const parentSpan = this.findSpanById(span.parentId);
454
+ if (parentSpan) {
455
+ this.context.setTrace(parentSpan);
456
+ }
457
+ }
458
+ return duration;
459
+ }
460
+ async trace(options, fn) {
461
+ const span = this.startSpan(options);
462
+ const timer = options.autoTiming !== false ? new Timer(`trace-${span.spanId}`) : undefined;
463
+ try {
464
+ const result = await fn();
465
+ const duration = this.finishSpan(span.spanId);
466
+ if (timer) {
467
+ timer.stop();
468
+ }
469
+ if (duration !== undefined) {
470
+ span.metadata.duration = duration;
471
+ }
472
+ return result;
473
+ } catch (error) {
474
+ span.metadata.error = {
475
+ name: error.name || "Unknown",
476
+ message: error.message || "Unknown error",
477
+ stack: error.stack
478
+ };
479
+ const duration = this.finishSpan(span.spanId);
480
+ span.metadata.duration = duration;
481
+ if (timer) {
482
+ timer.stop();
483
+ }
484
+ throw error;
485
+ }
486
+ }
487
+ addMetadata(key, value) {
488
+ const currentTrace = this.context.getCurrentTrace();
489
+ if (currentTrace) {
490
+ currentTrace.metadata[key] = value;
491
+ }
492
+ }
493
+ addTags(...tags) {
494
+ const currentTrace = this.context.getCurrentTrace();
495
+ if (currentTrace) {
496
+ currentTrace.tags.push(...tags);
497
+ }
498
+ }
499
+ getCurrentTrace() {
500
+ return this.context.getCurrentTrace();
501
+ }
502
+ getActiveSpans() {
503
+ return Array.from(this.activeSpans.values());
504
+ }
505
+ findSpanById(spanId) {
506
+ return this.activeSpans.get(spanId);
507
+ }
508
+ generateTraceId() {
509
+ return crypto.randomUUID().replace(/-/g, "");
510
+ }
511
+ generateSpanId() {
512
+ return crypto.randomUUID().replace(/-/g, "").substring(0, 16);
513
+ }
514
+ }
515
+
516
+ // src/logger.browser.ts
517
+ class Logger {
518
+ config;
519
+ formatter;
520
+ context;
521
+ tracer;
522
+ timerManager;
523
+ constructor(config) {
524
+ this.config = {
525
+ level: 2 /* INFO */,
526
+ environment: "development",
527
+ enableTracing: true,
528
+ enableTiming: true,
529
+ enableContext: true,
530
+ enableColors: true,
531
+ maxContextDepth: 10,
532
+ timestampFormat: "iso",
533
+ ...config
534
+ };
535
+ this.context = LogContext.getInstance();
536
+ this.tracer = new Tracer;
537
+ this.timerManager = new TimerManager;
538
+ this.formatter = this.config.environment === "production" ? new ProductionFormatter : new DevFormatter(this.config.enableColors);
539
+ }
540
+ traceLog(message, metadata) {
541
+ this.log(0 /* TRACE */, message, metadata);
542
+ }
543
+ debug(message, metadata) {
544
+ this.log(1 /* DEBUG */, message, metadata);
545
+ }
546
+ info(message, metadata) {
547
+ this.log(2 /* INFO */, message, metadata);
548
+ }
549
+ warn(message, metadata) {
550
+ this.log(3 /* WARN */, message, metadata);
551
+ }
552
+ error(message, metadata, error) {
553
+ this.log(4 /* ERROR */, message, metadata, error);
554
+ }
555
+ fatal(message, metadata, error) {
556
+ this.log(5 /* FATAL */, message, metadata, error);
557
+ }
558
+ withContext(context, fn) {
559
+ return this.context.run(context, fn);
560
+ }
561
+ extendContext(additionalContext, fn) {
562
+ return this.context.extend(additionalContext, fn);
563
+ }
564
+ setContext(key, value) {
565
+ this.context.set(key, value);
566
+ }
567
+ getContext() {
568
+ return this.context.getContext();
569
+ }
570
+ trace = async (options, fn) => {
571
+ if (!this.config.enableTracing) {
572
+ return await fn();
573
+ }
574
+ return this.tracer.trace(options, fn);
575
+ };
576
+ getTraceId() {
577
+ return this.tracer.getCurrentTrace()?.traceId;
578
+ }
579
+ startSpan(options) {
580
+ if (!this.config.enableTracing) {
581
+ return null;
582
+ }
583
+ return this.tracer.startSpan(options);
584
+ }
585
+ finishSpan(spanId) {
586
+ if (!this.config.enableTracing) {
587
+ return;
588
+ }
589
+ return this.tracer.finishSpan(spanId);
590
+ }
591
+ addTraceMetadata(key, value) {
592
+ if (this.config.enableTracing) {
593
+ this.tracer.addMetadata(key, value);
594
+ }
595
+ }
596
+ addTraceTags(...tags) {
597
+ if (this.config.enableTracing) {
598
+ this.tracer.addTags(...tags);
599
+ }
600
+ }
601
+ startTimer(id) {
602
+ if (!this.config.enableTiming) {
603
+ return null;
604
+ }
605
+ return this.timerManager.start(id);
606
+ }
607
+ stopTimer(id) {
608
+ if (!this.config.enableTiming) {
609
+ return;
610
+ }
611
+ return this.timerManager.stop(id);
612
+ }
613
+ getTimer(id) {
614
+ return this.timerManager.get(id);
615
+ }
616
+ child(context) {
617
+ const childLogger = new Logger(this.config);
618
+ Object.entries(context).forEach(([key, value]) => {
619
+ childLogger.setContext(key, value);
620
+ });
621
+ return childLogger;
622
+ }
623
+ setLevel(level) {
624
+ this.config.level = level;
625
+ }
626
+ setFormatter(formatter) {
627
+ this.formatter = formatter;
628
+ }
629
+ async profile(operationName, fn, options) {
630
+ const timer = this.startTimer(`profile-${operationName}`);
631
+ const startTime = performance.now();
632
+ try {
633
+ const result = await this.tracer.trace({
634
+ operationType: "custom",
635
+ operationName: `profile:${operationName}`,
636
+ autoTiming: true
637
+ }, fn);
638
+ const duration = performance.now() - startTime;
639
+ timer?.stop();
640
+ const logLevel = options?.logLevel || 1 /* DEBUG */;
641
+ this.log(logLevel, `Profile: ${operationName} completed`, {
642
+ operation: operationName,
643
+ duration: `${duration.toFixed(2)}ms`,
644
+ result: options?.logResult ? result : "[result hidden]"
645
+ });
646
+ return result;
647
+ } catch (error) {
648
+ const duration = performance.now() - startTime;
649
+ timer?.stop();
650
+ this.error(`Profile: ${operationName} failed`, {
651
+ operation: operationName,
652
+ duration: `${duration.toFixed(2)}ms`,
653
+ error: error.message
654
+ }, error);
655
+ throw error;
656
+ }
657
+ }
658
+ logRequest(method, url, statusCode, duration) {
659
+ const level = this.getHttpLogLevel(statusCode);
660
+ const message = `${method.toUpperCase()} ${url}${statusCode ? ` ${statusCode}` : ""}`;
661
+ this.log(level, message, {
662
+ method,
663
+ url,
664
+ statusCode,
665
+ duration: duration ? `${duration.toFixed(2)}ms` : undefined,
666
+ type: "http_request"
667
+ });
668
+ }
669
+ async flush() {
670
+ this.timerManager.clear();
671
+ }
672
+ getStats() {
673
+ return {
674
+ activeTimers: this.timerManager.getActive().length,
675
+ activeSpans: this.tracer.getActiveSpans().length,
676
+ config: { ...this.config }
677
+ };
678
+ }
679
+ output(message, level) {
680
+ if (level >= 4 /* ERROR */) {
681
+ console.error(message);
682
+ } else {
683
+ console.log(message);
684
+ }
685
+ }
686
+ log(level, message, metadata, error) {
687
+ if (level < this.config.level) {
688
+ return;
689
+ }
690
+ const currentTrace = this.config.enableTracing ? this.tracer.getCurrentTrace() : undefined;
691
+ const contextData = this.config.enableContext ? this.context.getContext() : undefined;
692
+ const entry = {
693
+ level,
694
+ message,
695
+ timestamp: new Date,
696
+ traceId: currentTrace?.traceId,
697
+ parentId: currentTrace?.parentId,
698
+ spanId: currentTrace?.spanId,
699
+ context: contextData,
700
+ metadata,
701
+ error,
702
+ tags: currentTrace?.tags
703
+ };
704
+ if (currentTrace?.metadata?.duration) {
705
+ entry.duration = currentTrace.metadata.duration;
706
+ }
707
+ const formatted = this.formatter.format(entry);
708
+ this.output(formatted, level);
709
+ }
710
+ getHttpLogLevel(statusCode) {
711
+ if (!statusCode)
712
+ return 2 /* INFO */;
713
+ if (statusCode >= 500)
714
+ return 4 /* ERROR */;
715
+ if (statusCode >= 400)
716
+ return 3 /* WARN */;
717
+ return 2 /* INFO */;
718
+ }
719
+ }
720
+ export {
721
+ Tracer,
722
+ Timer,
723
+ ProductionFormatter,
724
+ Logger,
725
+ LogLevel,
726
+ LogContext,
727
+ DevFormatter
728
+ };