@vtvlive/interactive-apm 0.0.3 → 0.0.4

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 (38) hide show
  1. package/dist/factories/tracing-provider.factory.d.ts +6 -4
  2. package/dist/factories/tracing-provider.factory.d.ts.map +1 -1
  3. package/dist/factories/tracing-provider.factory.js +17 -14
  4. package/dist/index.d.ts +12 -11
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/init/elastic-apm-init.d.ts +25 -3
  7. package/dist/init/elastic-apm-init.d.ts.map +1 -1
  8. package/dist/init/elastic-apm-init.js +12 -12
  9. package/dist/init/opentelemetry-init.d.ts +6 -2
  10. package/dist/init/opentelemetry-init.d.ts.map +1 -1
  11. package/dist/init/opentelemetry-init.js +46 -42
  12. package/dist/interfaces/tracing-provider.interface.d.ts +13 -3
  13. package/dist/interfaces/tracing-provider.interface.d.ts.map +1 -1
  14. package/dist/modules/tracing.module.d.ts +5 -5
  15. package/dist/modules/tracing.module.d.ts.map +1 -1
  16. package/dist/modules/tracing.module.js +2 -1
  17. package/dist/providers/elastic-apm.tracing-provider.d.ts +23 -5
  18. package/dist/providers/elastic-apm.tracing-provider.d.ts.map +1 -1
  19. package/dist/providers/elastic-apm.tracing-provider.js +94 -30
  20. package/dist/providers/opentelemetry.tracing-provider.d.ts +6 -5
  21. package/dist/providers/opentelemetry.tracing-provider.d.ts.map +1 -1
  22. package/dist/providers/opentelemetry.tracing-provider.js +178 -85
  23. package/dist/services/tracing.service.d.ts +6 -5
  24. package/dist/services/tracing.service.d.ts.map +1 -1
  25. package/dist/services/tracing.service.js +2 -2
  26. package/dist/types/apm.types.d.ts +162 -0
  27. package/dist/types/apm.types.d.ts.map +1 -0
  28. package/dist/types/apm.types.js +37 -0
  29. package/dist/utils/debug-exporter-wrapper.d.ts +13 -2
  30. package/dist/utils/debug-exporter-wrapper.d.ts.map +1 -1
  31. package/dist/utils/debug-exporter-wrapper.js +82 -42
  32. package/dist/utils/debug-logger.d.ts +34 -9
  33. package/dist/utils/debug-logger.d.ts.map +1 -1
  34. package/dist/utils/debug-logger.js +37 -28
  35. package/dist/utils/tracing.helper.d.ts +2 -2
  36. package/dist/utils/tracing.helper.d.ts.map +1 -1
  37. package/dist/utils/tracing.helper.js +8 -4
  38. package/package.json +15 -4
@@ -22,16 +22,24 @@ exports.logSpan = logSpan;
22
22
  * Check if debug mode is enabled via environment variable
23
23
  */
24
24
  function isDebugEnabled() {
25
- return process.env.APM_DEBUG === 'true';
25
+ return process.env.APM_DEBUG === "true";
26
26
  }
27
27
  /**
28
28
  * Mask sensitive values in headers and config for logging
29
29
  */
30
30
  function maskSensitive(value, key) {
31
- const sensitiveKeys = ['authorization', 'token', 'secret', 'password', 'apikey', 'api-key', 'x-api-key'];
31
+ const sensitiveKeys = [
32
+ "authorization",
33
+ "token",
34
+ "secret",
35
+ "password",
36
+ "apikey",
37
+ "api-key",
38
+ "x-api-key",
39
+ ];
32
40
  const lowerKey = key.toLowerCase();
33
41
  if (sensitiveKeys.some(k => lowerKey.includes(k))) {
34
- return '[REDACTED]';
42
+ return "[REDACTED]";
35
43
  }
36
44
  return value;
37
45
  }
@@ -51,21 +59,21 @@ function sanitizeHeaders(headers) {
51
59
  */
52
60
  function sanitizeConfig(config, seen = new WeakMap()) {
53
61
  // Handle primitives and null
54
- if (config === null || typeof config !== 'object') {
62
+ if (config === null || typeof config !== "object") {
55
63
  return config;
56
64
  }
57
65
  // Handle circular references
58
66
  if (seen.has(config)) {
59
- return '[Circular]';
67
+ return "[Circular]";
60
68
  }
61
- seen.set(config, '[Circular]');
69
+ seen.set(config, "[Circular]");
62
70
  // Handle arrays
63
71
  if (Array.isArray(config)) {
64
72
  return config.map(item => {
65
- if (typeof item === 'string') {
66
- return maskSensitive(item, '');
73
+ if (typeof item === "string") {
74
+ return maskSensitive(item, "");
67
75
  }
68
- else if (typeof item === 'object' && item !== null) {
76
+ else if (typeof item === "object" && item !== null) {
69
77
  return sanitizeConfig(item, seen);
70
78
  }
71
79
  return item;
@@ -74,21 +82,21 @@ function sanitizeConfig(config, seen = new WeakMap()) {
74
82
  // Handle objects
75
83
  const sanitized = {};
76
84
  for (const [key, value] of Object.entries(config)) {
77
- if (typeof value === 'string') {
85
+ if (typeof value === "string") {
78
86
  sanitized[key] = maskSensitive(value, key);
79
87
  }
80
88
  else if (Array.isArray(value)) {
81
89
  sanitized[key] = value.map(item => {
82
- if (typeof item === 'string') {
90
+ if (typeof item === "string") {
83
91
  return maskSensitive(item, key);
84
92
  }
85
- else if (typeof item === 'object' && item !== null) {
93
+ else if (typeof item === "object" && item !== null) {
86
94
  return sanitizeConfig(item, seen);
87
95
  }
88
96
  return item;
89
97
  });
90
98
  }
91
- else if (typeof value === 'object' && value !== null) {
99
+ else if (typeof value === "object" && value !== null) {
92
100
  sanitized[key] = sanitizeConfig(value, seen);
93
101
  }
94
102
  else {
@@ -125,8 +133,8 @@ function logInitialization(provider, config) {
125
133
  return;
126
134
  }
127
135
  debugLog(`=== ${provider} Initialization ===`);
128
- debugLog('Configuration:', sanitizeConfig(config));
129
- debugLog('Environment Variables:', {
136
+ debugLog("Configuration:", sanitizeConfig(config));
137
+ debugLog("Environment Variables:", {
130
138
  APM_PROVIDER: process.env.APM_PROVIDER,
131
139
  ELASTIC_APM_SERVICE_NAME: process.env.ELASTIC_APM_SERVICE_NAME,
132
140
  ELASTIC_APM_ENVIRONMENT: process.env.ELASTIC_APM_ENVIRONMENT,
@@ -134,12 +142,12 @@ function logInitialization(provider, config) {
134
142
  ELASTIC_APM_SERVER_URL: process.env.ELASTIC_APM_SERVER_URL,
135
143
  APM_DEBUG: process.env.APM_DEBUG,
136
144
  });
137
- debugLog('System Info:', {
145
+ debugLog("System Info:", {
138
146
  nodeVersion: process.version,
139
147
  platform: process.platform,
140
148
  arch: process.arch,
141
149
  pid: process.pid,
142
- hostname: require('os').hostname(),
150
+ hostname: require("os").hostname(),
143
151
  });
144
152
  }
145
153
  /**
@@ -155,10 +163,11 @@ function logExportSuccess(provider, spanCount) {
155
163
  */
156
164
  function logExportFailure(provider, error, requestDetails) {
157
165
  // Always log export failures as errors
158
- errorLog(`[${provider}] Export failed:`, error);
166
+ const errorMessage = error instanceof Error ? error.message : String(error);
167
+ errorLog(`[${provider}] Export failed:`, errorMessage);
159
168
  // Log additional details only in debug mode
160
169
  if (isDebugEnabled() && requestDetails) {
161
- debugLog('Request details:', sanitizeConfig(requestDetails));
170
+ debugLog("Request details:", sanitizeConfig(requestDetails));
162
171
  }
163
172
  }
164
173
  /**
@@ -169,24 +178,24 @@ function logRequest(provider, url, headers, body) {
169
178
  return;
170
179
  }
171
180
  debugLog(`[${provider}] → Sending request to: ${url}`);
172
- debugLog('Headers:', sanitizeHeaders(headers));
181
+ debugLog("Headers:", sanitizeHeaders(headers));
173
182
  // Sanitize request body for sensitive data before logging
174
183
  if (body) {
175
184
  // WARNING: Request bodies may contain sensitive data - we sanitize common patterns
176
185
  let sanitizedBody;
177
- if (typeof body === 'string') {
186
+ if (typeof body === "string") {
178
187
  // Redact common auth/token patterns in strings
179
- sanitizedBody = body.replace(/"(?:password|pass|pwd|token|access_token|auth|authorization|cookie|ssn|creditCard|cardNumber|cvv|secret)"\s*:\s*"[^"]*"/gi, '"$1": "[REDACTED]"');
180
- sanitizedBody = sanitizedBody.replace(/Bearer\s+[A-Za-z0-9\-._~+/=]*/gi, 'Bearer [REDACTED]');
188
+ sanitizedBody = body.replace(/"(password|pass|pwd|token|access_token|auth|authorization|cookie|ssn|creditCard|cardNumber|cvv|secret)"\s*:\s*"[^"]*"/gi, '"$1": "[REDACTED]"');
189
+ sanitizedBody = sanitizedBody.replace(/Bearer\s+[A-Za-z0-9\-._~+/=]*/gi, "Bearer [REDACTED]");
181
190
  }
182
- else if (typeof body === 'object' && body !== null) {
191
+ else if (typeof body === "object" && body !== null) {
183
192
  // Deep clone and sanitize object
184
193
  sanitizedBody = sanitizeConfig(body);
185
194
  }
186
195
  else {
187
- sanitizedBody = body;
196
+ sanitizedBody = String(body);
188
197
  }
189
- debugLog('Body:', typeof sanitizedBody === 'string' ? sanitizedBody : JSON.stringify(sanitizedBody, null, 2));
198
+ debugLog("Body:", typeof sanitizedBody === "string" ? sanitizedBody : JSON.stringify(sanitizedBody, null, 2));
190
199
  }
191
200
  }
192
201
  /**
@@ -197,9 +206,9 @@ function logResponse(provider, statusCode, headers, body) {
197
206
  return;
198
207
  }
199
208
  debugLog(`[${provider}] ← Received response: ${statusCode}`);
200
- debugLog('Response Headers:', sanitizeHeaders(headers));
209
+ debugLog("Response Headers:", sanitizeHeaders(headers));
201
210
  if (body) {
202
- debugLog('Response Body:', typeof body === 'string' ? body : JSON.stringify(body, null, 2));
211
+ debugLog("Response Body:", typeof body === "string" ? body : JSON.stringify(body, null, 2));
203
212
  }
204
213
  }
205
214
  /**
@@ -1,4 +1,4 @@
1
- import { Span, SpanKind } from '@opentelemetry/api';
1
+ import { Span, SpanKind } from "@opentelemetry/api";
2
2
  /**
3
3
  * TracingHelper - Static utility class for direct OpenTelemetry usage
4
4
  *
@@ -37,7 +37,7 @@ export declare class TracingHelper {
37
37
  * @param attributes Các attributes metadata
38
38
  * @returns Kết quả của function
39
39
  */
40
- static startSpanWithParent<T>(name: string, fn: (span: Span) => Promise<T>, attributes?: Record<string, string | number>): Promise<T>;
40
+ static startSpanWithParent<T>(name: string, fn: (span: Span | undefined) => Promise<T>, attributes?: Record<string, string | number>): Promise<T>;
41
41
  /**
42
42
  * Capture error vào active span hiện tại
43
43
  * @param error Error object
@@ -1 +1 @@
1
- {"version":3,"file":"tracing.helper.d.ts","sourceRoot":"","sources":["../../src/utils/tracing.helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,IAAI,EAAkB,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAsC;IAE3D;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,QAAQ,GAAE,QAA4B,GAAG,IAAI;IAa1H;;;;;;OAMG;IACH,MAAM,CAAC,mBAAmB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAiBrI;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAQvC;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO9D;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI;IAOjC;;;OAGG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI,GAAG,SAAS;IAIxC;;;OAGG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM,GAAG,SAAS;CAIxC"}
1
+ {"version":3,"file":"tracing.helper.d.ts","sourceRoot":"","sources":["../../src/utils/tracing.helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,IAAI,EAAkB,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAsC;IAE3D;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CACd,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAC5C,QAAQ,GAAE,QAA4B,GACrC,IAAI;IAaP;;;;;;OAMG;IACH,MAAM,CAAC,mBAAmB,CAAC,CAAC,EAC1B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,EAC1C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAC3C,OAAO,CAAC,CAAC,CAAC;IA2Bb;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAQvC;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO9D;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI;IAOjC;;;OAGG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI,GAAG,SAAS;IAIxC;;;OAGG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM,GAAG,SAAS;CAIxC"}
@@ -49,17 +49,21 @@ class TracingHelper {
49
49
  static startSpanWithParent(name, fn, attributes) {
50
50
  return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), TracingHelper.startSpan(name, attributes)), async () => {
51
51
  const span = api_1.trace.getActiveSpan();
52
+ // If no active span, throw an error - this should not happen if the span was just started
53
+ if (!span) {
54
+ throw new Error(`Failed to get active span for "${name}". The OpenTelemetry context may not be properly initialized.`);
55
+ }
52
56
  try {
53
57
  const result = await fn(span);
54
58
  return result;
55
59
  }
56
60
  catch (error) {
57
- span?.recordException(error);
58
- span?.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error.message });
61
+ span.recordException(error);
62
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error.message });
59
63
  throw error;
60
64
  }
61
65
  finally {
62
- span?.end();
66
+ span.end();
63
67
  }
64
68
  });
65
69
  }
@@ -112,4 +116,4 @@ class TracingHelper {
112
116
  }
113
117
  }
114
118
  exports.TracingHelper = TracingHelper;
115
- TracingHelper.tracer = api_1.trace.getTracer('interactive-apm');
119
+ TracingHelper.tracer = api_1.trace.getTracer("interactive-apm");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtvlive/interactive-apm",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "APM integration package supporting both Elastic APM and OpenTelemetry with NestJS integration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -28,7 +28,12 @@
28
28
  "test:watch": "jest --watch",
29
29
  "test:coverage": "jest --coverage",
30
30
  "test:unit": "jest __tests__/unit",
31
- "test:integration": "jest __tests__/integration"
31
+ "test:integration": "jest __tests__/integration",
32
+ "lint": "eslint src",
33
+ "lint:fix": "eslint src --fix",
34
+ "format": "prettier --write \"src/**/*.ts\"",
35
+ "format:check": "prettier --check \"src/**/*.ts\"",
36
+ "typecheck": "tsc --noEmit"
32
37
  },
33
38
  "peerDependencies": {
34
39
  "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0",
@@ -92,7 +97,7 @@
92
97
  "@opentelemetry/api": "^1.9.0",
93
98
  "@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
94
99
  "@opentelemetry/exporter-trace-otlp-grpc": "^0.213.0",
95
- "@opentelemetry/exporter-trace-otlp-proto": "^1.22.0",
100
+ "@opentelemetry/exporter-trace-otlp-proto": "^0.213.0",
96
101
  "@opentelemetry/instrumentation-express": "^0.61.0",
97
102
  "@opentelemetry/instrumentation-http": "^0.213.0",
98
103
  "@opentelemetry/resources": "^2.6.0",
@@ -102,9 +107,15 @@
102
107
  "@types/jest": "^29.5.0",
103
108
  "@types/node": "^20.0.0",
104
109
  "elastic-apm-node": "^4.15.0",
110
+ "eslint": "^9.18.0",
111
+ "eslint-config-prettier": "^9.1.0",
112
+ "eslint-plugin-prettier": "^5.2.1",
105
113
  "jest": "^29.7.0",
114
+ "prettier": "^3.4.2",
106
115
  "ts-jest": "^29.1.0",
107
- "typescript": "^5.3.0"
116
+ "typescript": "^5.3.0",
117
+ "@typescript-eslint/eslint-plugin": "^8.19.1",
118
+ "@typescript-eslint/parser": "^8.19.1"
108
119
  },
109
120
  "engines": {
110
121
  "node": ">=14.0.0"