@dex-monit/observability-sdk-node 1.0.8 → 1.0.10

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.
@@ -13,6 +13,9 @@ export declare class ErrorCaptureInterceptor implements NestInterceptor {
13
13
  constructor(monitoringClient?: MonitoringClient | undefined);
14
14
  intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
15
15
  private captureError;
16
+ private getFullUrl;
16
17
  private sanitizeHeaders;
18
+ private sanitizeBody;
19
+ private sanitizeCookies;
17
20
  }
18
21
  //# sourceMappingURL=error-capture.interceptor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-capture.interceptor.d.ts","sourceRoot":"","sources":["../../src/lib/error-capture.interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,gBAAgB,EAChB,WAAW,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAc,MAAM,MAAM,CAAC;AAG9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;;;GAMG;AACH,qBACa,uBAAwB,YAAW,eAAe;IAE3D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBAAjB,gBAAgB,CAAC,EAAE,gBAAgB,YAAA;IAGtD,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC;IAY5E,OAAO,CAAC,YAAY;IAiCpB,OAAO,CAAC,eAAe;CAcxB"}
1
+ {"version":3,"file":"error-capture.interceptor.d.ts","sourceRoot":"","sources":["../../src/lib/error-capture.interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,gBAAgB,EAChB,WAAW,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAc,MAAM,MAAM,CAAC;AAI9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;;;GAMG;AACH,qBACa,uBAAwB,YAAW,eAAe;IAE3D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBAAjB,gBAAgB,CAAC,EAAE,gBAAgB,YAAA;IAGtD,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC;IAY5E,OAAO,CAAC,YAAY;IAkEpB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,eAAe;CASxB"}
@@ -2,6 +2,7 @@ import { __esDecorate, __runInitializers } from "tslib";
2
2
  import { Injectable, } from '@nestjs/common';
3
3
  import { throwError } from 'rxjs';
4
4
  import { catchError } from 'rxjs/operators';
5
+ import * as os from 'os';
5
6
  /**
6
7
  * Error Capture Interceptor
7
8
  *
@@ -46,11 +47,44 @@ let ErrorCaptureInterceptor = (() => {
46
47
  console.log('[DEX SDK] Sending error to monitoring...');
47
48
  this.monitoringClient
48
49
  .captureException(errorObj, {
50
+ // Full request context like Sentry
49
51
  request: {
50
- url: request?.url,
52
+ url: this.getFullUrl(request),
51
53
  method: request?.method,
52
54
  headers: this.sanitizeHeaders(request?.headers || {}),
53
55
  query: request?.query,
56
+ body: this.sanitizeBody(request?.body),
57
+ cookies: this.sanitizeCookies(request?.cookies),
58
+ },
59
+ // OS context
60
+ context: {
61
+ os: {
62
+ name: os.platform(),
63
+ version: os.release(),
64
+ kernelVersion: os.release(),
65
+ },
66
+ runtime: {
67
+ name: 'node',
68
+ version: process.version,
69
+ },
70
+ device: {
71
+ arch: os.arch(),
72
+ memory: os.totalmem(),
73
+ cpus: os.cpus().length,
74
+ hostname: os.hostname(),
75
+ },
76
+ app: {
77
+ startTime: process.uptime(),
78
+ memoryUsage: process.memoryUsage(),
79
+ },
80
+ },
81
+ // Tags for filtering
82
+ tags: {
83
+ 'http.method': request?.method || 'unknown',
84
+ 'http.status_code': '500',
85
+ 'runtime': 'node',
86
+ 'runtime.version': process.version,
87
+ 'os': os.platform(),
54
88
  },
55
89
  })
56
90
  .then(() => {
@@ -64,12 +98,20 @@ let ErrorCaptureInterceptor = (() => {
64
98
  console.log('[DEX SDK] No monitoring client configured');
65
99
  }
66
100
  }
101
+ getFullUrl(request) {
102
+ if (!request)
103
+ return 'unknown';
104
+ const protocol = request.protocol || 'http';
105
+ const host = request.get?.('host') || request.hostname || 'localhost';
106
+ const path = request.originalUrl || request.url || '/';
107
+ return `${protocol}://${host}${path}`;
108
+ }
67
109
  sanitizeHeaders(headers) {
68
- const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'x-dex-key'];
110
+ const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'x-dex-key', 'x-auth-token'];
69
111
  const sanitized = {};
70
112
  for (const [key, value] of Object.entries(headers)) {
71
113
  if (sensitiveHeaders.includes(key.toLowerCase())) {
72
- sanitized[key] = '[REDACTED]';
114
+ sanitized[key] = '[Filtered]';
73
115
  }
74
116
  else if (typeof value === 'string') {
75
117
  sanitized[key] = value;
@@ -77,6 +119,30 @@ let ErrorCaptureInterceptor = (() => {
77
119
  }
78
120
  return sanitized;
79
121
  }
122
+ sanitizeBody(body) {
123
+ if (!body || typeof body !== 'object')
124
+ return undefined;
125
+ const sensitiveKeys = ['password', 'token', 'secret', 'apiKey', 'api_key', 'credit_card', 'cvv'];
126
+ const sanitized = {};
127
+ for (const [key, value] of Object.entries(body)) {
128
+ if (sensitiveKeys.some(k => key.toLowerCase().includes(k.toLowerCase()))) {
129
+ sanitized[key] = '[Filtered]';
130
+ }
131
+ else {
132
+ sanitized[key] = value;
133
+ }
134
+ }
135
+ return sanitized;
136
+ }
137
+ sanitizeCookies(cookies) {
138
+ if (!cookies || typeof cookies !== 'object')
139
+ return undefined;
140
+ const sanitized = {};
141
+ for (const key of Object.keys(cookies)) {
142
+ sanitized[key] = '[Filtered]';
143
+ }
144
+ return sanitized;
145
+ }
80
146
  };
81
147
  return ErrorCaptureInterceptor = _classThis;
82
148
  })();
@@ -1,4 +1,4 @@
1
- import { ErrorEvent, EventContext, Severity } from '@dex-monit/observability-contracts';
1
+ import { ErrorEvent, EventContext, Severity, Breadcrumb } from '@dex-monit/observability-contracts';
2
2
  import { ScrubberOptions } from '@dex-monit/observability-scrubber';
3
3
  /**
4
4
  * Monitoring client configuration
@@ -100,4 +100,29 @@ export declare class MonitoringClient {
100
100
  * Create a monitoring client instance
101
101
  */
102
102
  export declare function createMonitoringClient(config: MonitoringClientConfig): MonitoringClient;
103
+ /**
104
+ * Add a breadcrumb to the global breadcrumb trail
105
+ */
106
+ export declare function addBreadcrumb(breadcrumb: Omit<Breadcrumb, 'timestamp'>): void;
107
+ /**
108
+ * Get current breadcrumbs
109
+ */
110
+ export declare function getBreadcrumbs(): Breadcrumb[];
111
+ /**
112
+ * Clear all breadcrumbs
113
+ */
114
+ export declare function clearBreadcrumbs(): void;
115
+ /**
116
+ * Add an HTTP breadcrumb (convenience function)
117
+ */
118
+ export declare function addHttpBreadcrumb(data: {
119
+ url: string;
120
+ method: string;
121
+ statusCode?: number;
122
+ duration?: number;
123
+ }): void;
124
+ /**
125
+ * Add a console breadcrumb (convenience function)
126
+ */
127
+ export declare function addConsoleBreadcrumb(level: Severity, message: string, data?: Record<string, unknown>): void;
103
128
  //# sourceMappingURL=monitoring-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"monitoring-client.d.ts","sourceRoot":"","sources":["../../src/lib/monitoring-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"monitoring-client.d.ts","sourceRoot":"","sources":["../../src/lib/monitoring-client.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,9 @@
1
1
  import { v4 as uuidv4 } from 'uuid';
2
2
  import { RequestContextService } from '@dex-monit/observability-request-context';
3
3
  import { scrubSensitiveData } from '@dex-monit/observability-scrubber';
4
+ // Global breadcrumb storage
5
+ const MAX_BREADCRUMBS = 100;
6
+ let globalBreadcrumbs = [];
4
7
  /**
5
8
  * Parse stack trace into structured frames
6
9
  */
@@ -86,6 +89,8 @@ export class MonitoringClient {
86
89
  value: error.message,
87
90
  stacktrace: parseStackTrace(error.stack),
88
91
  },
92
+ // Include breadcrumbs (events leading up to the error)
93
+ breadcrumbs: getBreadcrumbs(),
89
94
  requestId: requestContext?.requestId,
90
95
  transactionId: requestContext?.transactionId,
91
96
  fingerprint: options.fingerprint || generateFingerprint(error),
@@ -331,3 +336,58 @@ export class MonitoringClient {
331
336
  export function createMonitoringClient(config) {
332
337
  return new MonitoringClient(config);
333
338
  }
339
+ /**
340
+ * Add a breadcrumb to the global breadcrumb trail
341
+ */
342
+ export function addBreadcrumb(breadcrumb) {
343
+ const crumb = {
344
+ timestamp: new Date().toISOString(),
345
+ ...breadcrumb,
346
+ };
347
+ globalBreadcrumbs.push(crumb);
348
+ // Keep only the last MAX_BREADCRUMBS
349
+ if (globalBreadcrumbs.length > MAX_BREADCRUMBS) {
350
+ globalBreadcrumbs = globalBreadcrumbs.slice(-MAX_BREADCRUMBS);
351
+ }
352
+ }
353
+ /**
354
+ * Get current breadcrumbs
355
+ */
356
+ export function getBreadcrumbs() {
357
+ return [...globalBreadcrumbs];
358
+ }
359
+ /**
360
+ * Clear all breadcrumbs
361
+ */
362
+ export function clearBreadcrumbs() {
363
+ globalBreadcrumbs = [];
364
+ }
365
+ /**
366
+ * Add an HTTP breadcrumb (convenience function)
367
+ */
368
+ export function addHttpBreadcrumb(data) {
369
+ addBreadcrumb({
370
+ category: 'http',
371
+ type: 'http',
372
+ level: data.statusCode && data.statusCode >= 400 ? 'error' : 'info',
373
+ message: `${data.method} ${data.url}`,
374
+ data: {
375
+ url: data.url,
376
+ method: data.method,
377
+ status_code: data.statusCode,
378
+ duration_ms: data.duration,
379
+ },
380
+ });
381
+ }
382
+ /**
383
+ * Add a console breadcrumb (convenience function)
384
+ */
385
+ export function addConsoleBreadcrumb(level, message, data) {
386
+ addBreadcrumb({
387
+ category: 'console',
388
+ type: 'debug',
389
+ level,
390
+ message,
391
+ data,
392
+ });
393
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"nest-logger-capture.d.ts","sourceRoot":"","sources":["../../src/lib/nest-logger-capture.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AA2B1D;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAsD/E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAe5C;AAcD;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD"}
1
+ {"version":3,"file":"nest-logger-capture.d.ts","sourceRoot":"","sources":["../../src/lib/nest-logger-capture.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAqF1D;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAiD/E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAuC5C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD"}
@@ -1,4 +1,5 @@
1
- import { Logger as NestLogger } from '@nestjs/common';
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { Logger as NestLogger, ConsoleLogger } from '@nestjs/common';
2
3
  import { RequestContextService } from '@dex-monit/observability-request-context';
3
4
  const NEST_TO_SEVERITY = {
4
5
  debug: 'debug',
@@ -8,8 +9,55 @@ const NEST_TO_SEVERITY = {
8
9
  error: 'error',
9
10
  fatal: 'fatal',
10
11
  };
11
- let originalMethods = null;
12
+ let originalStaticMethods = null;
13
+ let originalPrototypeMethods = null;
14
+ let originalConsoleLoggerMethods = null;
12
15
  let isCapturing = false;
16
+ let monitoringClientRef = null;
17
+ /**
18
+ * Send log to monitoring service
19
+ */
20
+ function sendToMonitoring(severity, message, context) {
21
+ if (!monitoringClientRef)
22
+ return;
23
+ // Skip SDK internal logs to avoid loops
24
+ if (context?.startsWith('DEX') || message.startsWith('[DEX') || message.startsWith('[MonitoringClient]')) {
25
+ return;
26
+ }
27
+ const requestContext = RequestContextService.get();
28
+ monitoringClientRef.captureLog(severity, message, {
29
+ source: 'nest-logger',
30
+ context,
31
+ requestId: requestContext?.requestId,
32
+ transactionId: requestContext?.transactionId,
33
+ }).catch(() => {
34
+ // Silently ignore
35
+ });
36
+ }
37
+ /**
38
+ * Extract message and context from NestJS logger arguments
39
+ */
40
+ function extractMessageAndContext(message, optionalParams) {
41
+ const messageStr = typeof message === 'string' ? message : JSON.stringify(message);
42
+ // Last param is usually the context
43
+ const lastParam = optionalParams[optionalParams.length - 1];
44
+ const context = typeof lastParam === 'string' ? lastParam : undefined;
45
+ return { message: messageStr, context };
46
+ }
47
+ /**
48
+ * Create a wrapped method that sends to monitoring
49
+ */
50
+ function createWrappedMethod(original, severity, getContext) {
51
+ return function (message, ...optionalParams) {
52
+ // Call original method
53
+ original.call(this, message, ...optionalParams);
54
+ // Extract message and context
55
+ const { message: msg, context } = extractMessageAndContext(message, optionalParams);
56
+ const finalContext = context || (getContext ? getContext.call(this) : undefined);
57
+ // Send to monitoring
58
+ sendToMonitoring(severity, msg, finalContext);
59
+ };
60
+ }
13
61
  /**
14
62
  * Start capturing NestJS native Logger output
15
63
  */
@@ -17,72 +65,72 @@ export function startNestLoggerCapture(monitoringClient) {
17
65
  if (isCapturing) {
18
66
  return;
19
67
  }
20
- // Store original static methods
21
- originalMethods = {
22
- log: NestLogger.log.bind(NestLogger),
23
- error: NestLogger.error.bind(NestLogger),
24
- warn: NestLogger.warn.bind(NestLogger),
25
- debug: NestLogger.debug.bind(NestLogger),
26
- verbose: NestLogger.verbose.bind(NestLogger),
27
- fatal: NestLogger.fatal.bind(NestLogger),
28
- };
68
+ monitoringClientRef = monitoringClient;
29
69
  const methods = ['log', 'error', 'warn', 'debug', 'verbose', 'fatal'];
70
+ // 1. Patch static methods on NestLogger
71
+ originalStaticMethods = {};
30
72
  for (const method of methods) {
31
- const original = originalMethods[method];
32
- const severity = NEST_TO_SEVERITY[method];
33
- // Override the static method
34
- NestLogger[method] = function (message, ...optionalParams) {
35
- // Call original method first
36
- original(message, ...optionalParams);
37
- // Extract context from params
38
- const context = extractContext(optionalParams);
39
- const messageStr = typeof message === 'string' ? message : JSON.stringify(message);
40
- // Skip SDK internal logs to avoid loops
41
- if (context?.startsWith('DEX') || messageStr.startsWith('[DEX')) {
42
- return;
43
- }
44
- // Get request context
45
- const requestContext = RequestContextService.get();
46
- // Send to monitoring (fire and forget)
47
- monitoringClient.captureLog(severity, messageStr, {
48
- source: 'nest-logger',
49
- context,
50
- requestId: requestContext?.requestId,
51
- transactionId: requestContext?.transactionId,
52
- }).catch(() => {
53
- // Silently ignore
54
- });
55
- };
73
+ if (typeof NestLogger[method] === 'function') {
74
+ originalStaticMethods[method] = NestLogger[method].bind(NestLogger);
75
+ NestLogger[method] = createWrappedMethod(originalStaticMethods[method], NEST_TO_SEVERITY[method]);
76
+ }
77
+ }
78
+ // 2. Patch prototype methods on NestLogger
79
+ originalPrototypeMethods = {};
80
+ for (const method of methods) {
81
+ if (typeof NestLogger.prototype[method] === 'function') {
82
+ originalPrototypeMethods[method] = NestLogger.prototype[method];
83
+ NestLogger.prototype[method] = createWrappedMethod(originalPrototypeMethods[method], NEST_TO_SEVERITY[method], function () { return this.context; });
84
+ }
85
+ }
86
+ // 3. Patch ConsoleLogger prototype (NestJS internal logger)
87
+ originalConsoleLoggerMethods = {};
88
+ for (const method of methods) {
89
+ if (typeof ConsoleLogger.prototype[method] === 'function') {
90
+ originalConsoleLoggerMethods[method] = ConsoleLogger.prototype[method];
91
+ ConsoleLogger.prototype[method] = createWrappedMethod(originalConsoleLoggerMethods[method], NEST_TO_SEVERITY[method], function () { return this.context; });
92
+ }
56
93
  }
57
94
  isCapturing = true;
95
+ console.log('[DEX SDK] NestJS Logger capture started');
58
96
  }
59
97
  /**
60
98
  * Stop capturing NestJS native Logger output
61
99
  */
62
100
  export function stopNestLoggerCapture() {
63
- if (!isCapturing || !originalMethods) {
101
+ if (!isCapturing) {
64
102
  return;
65
103
  }
66
- // Restore original methods
67
- NestLogger.log = originalMethods.log;
68
- NestLogger.error = originalMethods.error;
69
- NestLogger.warn = originalMethods.warn;
70
- NestLogger.debug = originalMethods.debug;
71
- NestLogger.verbose = originalMethods.verbose;
72
- NestLogger.fatal = originalMethods.fatal;
73
- originalMethods = null;
74
- isCapturing = false;
75
- }
76
- /**
77
- * Extract context from optional params
78
- */
79
- function extractContext(optionalParams) {
80
- // Last param is usually the context
81
- const lastParam = optionalParams[optionalParams.length - 1];
82
- if (typeof lastParam === 'string') {
83
- return lastParam;
104
+ const methods = ['log', 'error', 'warn', 'debug', 'verbose', 'fatal'];
105
+ // Restore static methods
106
+ if (originalStaticMethods) {
107
+ for (const method of methods) {
108
+ if (originalStaticMethods[method]) {
109
+ NestLogger[method] = originalStaticMethods[method];
110
+ }
111
+ }
112
+ originalStaticMethods = null;
113
+ }
114
+ // Restore prototype methods
115
+ if (originalPrototypeMethods) {
116
+ for (const method of methods) {
117
+ if (originalPrototypeMethods[method]) {
118
+ NestLogger.prototype[method] = originalPrototypeMethods[method];
119
+ }
120
+ }
121
+ originalPrototypeMethods = null;
122
+ }
123
+ // Restore ConsoleLogger methods
124
+ if (originalConsoleLoggerMethods) {
125
+ for (const method of methods) {
126
+ if (originalConsoleLoggerMethods[method]) {
127
+ ConsoleLogger.prototype[method] = originalConsoleLoggerMethods[method];
128
+ }
129
+ }
130
+ originalConsoleLoggerMethods = null;
84
131
  }
85
- return undefined;
132
+ monitoringClientRef = null;
133
+ isCapturing = false;
86
134
  }
87
135
  /**
88
136
  * Check if NestJS Logger capture is active
@@ -1 +1 @@
1
- {"version":3,"file":"sdk-node.module.d.ts","sourceRoot":"","sources":["../../src/lib/sdk-node.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAEb,kBAAkB,EAClB,UAAU,EACV,eAAe,EAChB,MAAM,gBAAgB,CAAC;AAKxB,OAAO,EAEL,sBAAsB,EAEvB,MAAM,wBAAwB,CAAC;AAKhC,OAAO,EAEL,YAAY,EACZ,YAAY,EACb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,2BAA2B;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,yFAAyF;IACzF,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,QAAQ,CAAC;IAC1B,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE;;;;;;;;;;;GAWG;AACH,qBAEa,aAAc,YAAW,UAAU,EAAE,eAAe;IAC/D,OAAO,CAAC,MAAM,CAAC,YAAY,CAA6B;IAExD;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,aAAa;IAgG1D;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI;IAK7C;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAUvC"}
1
+ {"version":3,"file":"sdk-node.module.d.ts","sourceRoot":"","sources":["../../src/lib/sdk-node.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAEb,kBAAkB,EAClB,UAAU,EACV,eAAe,EAChB,MAAM,gBAAgB,CAAC;AAKxB,OAAO,EAEL,sBAAsB,EAEvB,MAAM,wBAAwB,CAAC;AAQhC,OAAO,EAEL,YAAY,EACZ,YAAY,EACb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,2BAA2B;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,yFAAyF;IACzF,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,QAAQ,CAAC;IAC1B,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE;;;;;;;;;;;GAWG;AACH,qBAEa,aAAc,YAAW,UAAU,EAAE,eAAe;IAC/D,OAAO,CAAC,MAAM,CAAC,YAAY,CAA6B;IAExD;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,aAAa;IAgG1D;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI;IAK7C;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAUvC"}
@@ -8,7 +8,7 @@ import { MonitoringClient, createMonitoringClient, } from './monitoring-client.j
8
8
  import { RemoteLogger, createRemoteLogger } from './remote-logger.js';
9
9
  import { DexLoggerService, DEX_LOGGER_TOKEN } from './dex-logger.service.js';
10
10
  import { startConsoleCapture, stopConsoleCapture } from './console-capture.js';
11
- import { startNestLoggerCapture, stopNestLoggerCapture } from './nest-logger-capture.js';
11
+ import { startNestLoggerCapture, stopNestLoggerCapture, } from './nest-logger-capture.js';
12
12
  import { Logger, LOGGER_TOKEN, } from '@dex-monit/observability-logger';
13
13
  // Re-export LOGGER_TOKEN for convenience
14
14
  export { LOGGER_TOKEN };