apitally 0.11.5 → 0.12.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 (60) hide show
  1. package/README.md +2 -2
  2. package/dist/common/client.cjs +116 -105
  3. package/dist/common/client.cjs.map +1 -1
  4. package/dist/common/client.js +111 -100
  5. package/dist/common/client.js.map +1 -1
  6. package/dist/common/requestLogger.cjs +55 -2
  7. package/dist/common/requestLogger.cjs.map +1 -1
  8. package/dist/common/requestLogger.d.cts +2 -1
  9. package/dist/common/requestLogger.d.ts +2 -1
  10. package/dist/common/requestLogger.js +55 -2
  11. package/dist/common/requestLogger.js.map +1 -1
  12. package/dist/common/sentry.cjs +55 -0
  13. package/dist/common/sentry.cjs.map +1 -0
  14. package/dist/common/sentry.d.cts +6 -0
  15. package/dist/common/sentry.d.ts +6 -0
  16. package/dist/common/sentry.js +22 -0
  17. package/dist/common/sentry.js.map +1 -0
  18. package/dist/common/serverErrorCounter.cjs +58 -45
  19. package/dist/common/serverErrorCounter.cjs.map +1 -1
  20. package/dist/common/serverErrorCounter.d.cts +3 -6
  21. package/dist/common/serverErrorCounter.d.ts +3 -6
  22. package/dist/common/serverErrorCounter.js +53 -45
  23. package/dist/common/serverErrorCounter.js.map +1 -1
  24. package/dist/express/index.cjs +117 -106
  25. package/dist/express/index.cjs.map +1 -1
  26. package/dist/express/index.js +112 -101
  27. package/dist/express/index.js.map +1 -1
  28. package/dist/express/middleware.cjs +117 -106
  29. package/dist/express/middleware.cjs.map +1 -1
  30. package/dist/express/middleware.js +112 -101
  31. package/dist/express/middleware.js.map +1 -1
  32. package/dist/fastify/index.cjs +117 -106
  33. package/dist/fastify/index.cjs.map +1 -1
  34. package/dist/fastify/index.js +112 -101
  35. package/dist/fastify/index.js.map +1 -1
  36. package/dist/fastify/plugin.cjs +117 -106
  37. package/dist/fastify/plugin.cjs.map +1 -1
  38. package/dist/fastify/plugin.js +112 -101
  39. package/dist/fastify/plugin.js.map +1 -1
  40. package/dist/hono/index.cjs +117 -106
  41. package/dist/hono/index.cjs.map +1 -1
  42. package/dist/hono/index.js +112 -101
  43. package/dist/hono/index.js.map +1 -1
  44. package/dist/hono/middleware.cjs +117 -106
  45. package/dist/hono/middleware.cjs.map +1 -1
  46. package/dist/hono/middleware.js +112 -101
  47. package/dist/hono/middleware.js.map +1 -1
  48. package/dist/koa/index.cjs +119 -106
  49. package/dist/koa/index.cjs.map +1 -1
  50. package/dist/koa/index.js +114 -101
  51. package/dist/koa/index.js.map +1 -1
  52. package/dist/koa/middleware.cjs +119 -106
  53. package/dist/koa/middleware.cjs.map +1 -1
  54. package/dist/koa/middleware.js +114 -101
  55. package/dist/koa/middleware.js.map +1 -1
  56. package/dist/nestjs/index.cjs +117 -106
  57. package/dist/nestjs/index.cjs.map +1 -1
  58. package/dist/nestjs/index.js +112 -101
  59. package/dist/nestjs/index.js.map +1 -1
  60. package/package.json +1 -1
@@ -214,14 +214,116 @@ var RequestCounter = _RequestCounter;
214
214
  // src/common/requestLogger.ts
215
215
  var import_async_lock = __toESM(require("async-lock"), 1);
216
216
  var import_buffer2 = require("buffer");
217
- var import_crypto2 = require("crypto");
217
+ var import_crypto3 = require("crypto");
218
218
  var import_fs2 = require("fs");
219
219
  var import_os2 = require("os");
220
220
  var import_path2 = require("path");
221
221
 
222
+ // src/common/sentry.ts
223
+ var sentry;
224
+ (async () => {
225
+ try {
226
+ sentry = await import("@sentry/node");
227
+ } catch (e) {
228
+ }
229
+ })();
230
+ function getSentryEventId() {
231
+ if (sentry && sentry.lastEventId) {
232
+ return sentry.lastEventId();
233
+ }
234
+ return void 0;
235
+ }
236
+ __name(getSentryEventId, "getSentryEventId");
237
+
238
+ // src/common/serverErrorCounter.ts
239
+ var import_crypto = require("crypto");
240
+ var MAX_MSG_LENGTH = 2048;
241
+ var MAX_STACKTRACE_LENGTH = 65536;
242
+ var _ServerErrorCounter = class _ServerErrorCounter {
243
+ errorCounts;
244
+ errorDetails;
245
+ sentryEventIds;
246
+ constructor() {
247
+ this.errorCounts = /* @__PURE__ */ new Map();
248
+ this.errorDetails = /* @__PURE__ */ new Map();
249
+ this.sentryEventIds = /* @__PURE__ */ new Map();
250
+ }
251
+ addServerError(serverError) {
252
+ const key = this.getKey(serverError);
253
+ if (!this.errorDetails.has(key)) {
254
+ this.errorDetails.set(key, serverError);
255
+ }
256
+ this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
257
+ const sentryEventId = getSentryEventId();
258
+ if (sentryEventId) {
259
+ this.sentryEventIds.set(key, sentryEventId);
260
+ }
261
+ }
262
+ getAndResetServerErrors() {
263
+ const data = [];
264
+ this.errorCounts.forEach((count, key) => {
265
+ const serverError = this.errorDetails.get(key);
266
+ if (serverError) {
267
+ data.push({
268
+ consumer: serverError.consumer || null,
269
+ method: serverError.method,
270
+ path: serverError.path,
271
+ type: serverError.type,
272
+ msg: truncateExceptionMessage(serverError.msg),
273
+ traceback: truncateExceptionStackTrace(serverError.traceback),
274
+ sentry_event_id: this.sentryEventIds.get(key) || null,
275
+ error_count: count
276
+ });
277
+ }
278
+ });
279
+ this.errorCounts.clear();
280
+ this.errorDetails.clear();
281
+ return data;
282
+ }
283
+ getKey(serverError) {
284
+ const hashInput = [
285
+ serverError.consumer || "",
286
+ serverError.method.toUpperCase(),
287
+ serverError.path,
288
+ serverError.type,
289
+ serverError.msg.trim(),
290
+ serverError.traceback.trim()
291
+ ].join("|");
292
+ return (0, import_crypto.createHash)("md5").update(hashInput).digest("hex");
293
+ }
294
+ };
295
+ __name(_ServerErrorCounter, "ServerErrorCounter");
296
+ var ServerErrorCounter = _ServerErrorCounter;
297
+ function truncateExceptionMessage(msg) {
298
+ if (msg.length <= MAX_MSG_LENGTH) {
299
+ return msg;
300
+ }
301
+ const suffix = "... (truncated)";
302
+ const cutoff = MAX_MSG_LENGTH - suffix.length;
303
+ return msg.substring(0, cutoff) + suffix;
304
+ }
305
+ __name(truncateExceptionMessage, "truncateExceptionMessage");
306
+ function truncateExceptionStackTrace(stack) {
307
+ const suffix = "... (truncated) ...";
308
+ const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
309
+ const lines = stack.trim().split("\n");
310
+ const truncatedLines = [];
311
+ let length = 0;
312
+ for (const line of lines) {
313
+ if (length + line.length + 1 > cutoff) {
314
+ truncatedLines.push(suffix);
315
+ break;
316
+ }
317
+ truncatedLines.push(line);
318
+ length += line.length + 1;
319
+ }
320
+ return truncatedLines.join("\n");
321
+ }
322
+ __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
323
+
222
324
  // src/common/tempGzipFile.ts
223
325
  var import_buffer = require("buffer");
224
- var import_crypto = require("crypto");
326
+ var import_crypto2 = require("crypto");
225
327
  var import_fs = require("fs");
226
328
  var import_os = require("os");
227
329
  var import_path = require("path");
@@ -234,7 +336,7 @@ var _TempGzipFile = class _TempGzipFile {
234
336
  readyPromise;
235
337
  closedPromise;
236
338
  constructor() {
237
- this.uuid = (0, import_crypto.randomUUID)();
339
+ this.uuid = (0, import_crypto2.randomUUID)();
238
340
  this.filePath = (0, import_path.join)((0, import_os.tmpdir)(), `apitally-${this.uuid}.gz`);
239
341
  this.writeStream = (0, import_fs.createWriteStream)(this.filePath);
240
342
  this.readyPromise = new Promise((resolve, reject) => {
@@ -341,6 +443,7 @@ var DEFAULT_CONFIG = {
341
443
  logRequestBody: false,
342
444
  logResponseHeaders: true,
343
445
  logResponseBody: false,
446
+ logException: true,
344
447
  maskQueryParams: [],
345
448
  maskHeaders: [],
346
449
  excludePaths: []
@@ -413,7 +516,7 @@ var _RequestLogger = class _RequestLogger {
413
516
  this.shouldMaskHeader(k) ? MASKED : v
414
517
  ]);
415
518
  }
416
- logRequest(request, response) {
519
+ logRequest(request, response, error) {
417
520
  var _a2, _b, _c;
418
521
  if (!this.enabled || this.suspendUntil !== null) return;
419
522
  const url = new URL(request.url);
@@ -459,9 +562,15 @@ var _RequestLogger = class _RequestLogger {
459
562
  request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
460
563
  response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
461
564
  const item = {
462
- uuid: (0, import_crypto2.randomUUID)(),
565
+ uuid: (0, import_crypto3.randomUUID)(),
463
566
  request: skipEmptyValues(request),
464
- response: skipEmptyValues(response)
567
+ response: skipEmptyValues(response),
568
+ exception: error && this.config.logException ? {
569
+ type: error.name,
570
+ message: truncateExceptionMessage(error.message),
571
+ stacktrace: truncateExceptionStackTrace(error.stack || ""),
572
+ sentryEventId: getSentryEventId()
573
+ } : null
465
574
  };
466
575
  [
467
576
  item.request.body,
@@ -581,7 +690,7 @@ function skipEmptyValues(data) {
581
690
  __name(skipEmptyValues, "skipEmptyValues");
582
691
  function checkWritableFs() {
583
692
  try {
584
- const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto2.randomUUID)()}`);
693
+ const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto3.randomUUID)()}`);
585
694
  (0, import_fs2.writeFileSync)(testPath, "test");
586
695
  (0, import_fs2.unlinkSync)(testPath);
587
696
  return true;
@@ -591,104 +700,6 @@ function checkWritableFs() {
591
700
  }
592
701
  __name(checkWritableFs, "checkWritableFs");
593
702
 
594
- // src/common/serverErrorCounter.ts
595
- var import_crypto3 = require("crypto");
596
- var MAX_MSG_LENGTH = 2048;
597
- var MAX_STACKTRACE_LENGTH = 65536;
598
- var _ServerErrorCounter = class _ServerErrorCounter {
599
- errorCounts;
600
- errorDetails;
601
- sentryEventIds;
602
- sentry;
603
- constructor() {
604
- this.errorCounts = /* @__PURE__ */ new Map();
605
- this.errorDetails = /* @__PURE__ */ new Map();
606
- this.sentryEventIds = /* @__PURE__ */ new Map();
607
- this.tryImportSentry();
608
- }
609
- addServerError(serverError) {
610
- const key = this.getKey(serverError);
611
- if (!this.errorDetails.has(key)) {
612
- this.errorDetails.set(key, serverError);
613
- }
614
- this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
615
- this.captureSentryEventId(key);
616
- }
617
- getAndResetServerErrors() {
618
- const data = [];
619
- this.errorCounts.forEach((count, key) => {
620
- const serverError = this.errorDetails.get(key);
621
- if (serverError) {
622
- data.push({
623
- consumer: serverError.consumer || null,
624
- method: serverError.method,
625
- path: serverError.path,
626
- type: serverError.type,
627
- msg: this.getTruncatedMessage(serverError.msg),
628
- traceback: this.getTruncatedStack(serverError.traceback),
629
- sentry_event_id: this.sentryEventIds.get(key) || null,
630
- error_count: count
631
- });
632
- }
633
- });
634
- this.errorCounts.clear();
635
- this.errorDetails.clear();
636
- return data;
637
- }
638
- getKey(serverError) {
639
- const hashInput = [
640
- serverError.consumer || "",
641
- serverError.method.toUpperCase(),
642
- serverError.path,
643
- serverError.type,
644
- serverError.msg.trim(),
645
- serverError.traceback.trim()
646
- ].join("|");
647
- return (0, import_crypto3.createHash)("md5").update(hashInput).digest("hex");
648
- }
649
- getTruncatedMessage(msg) {
650
- msg = msg.trim();
651
- if (msg.length <= MAX_MSG_LENGTH) {
652
- return msg;
653
- }
654
- const suffix = "... (truncated)";
655
- const cutoff = MAX_MSG_LENGTH - suffix.length;
656
- return msg.substring(0, cutoff) + suffix;
657
- }
658
- getTruncatedStack(stack) {
659
- const suffix = "... (truncated) ...";
660
- const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
661
- const lines = stack.trim().split("\n");
662
- const truncatedLines = [];
663
- let length = 0;
664
- for (const line of lines) {
665
- if (length + line.length + 1 > cutoff) {
666
- truncatedLines.push(suffix);
667
- break;
668
- }
669
- truncatedLines.push(line);
670
- length += line.length + 1;
671
- }
672
- return truncatedLines.join("\n");
673
- }
674
- captureSentryEventId(serverErrorKey) {
675
- if (this.sentry && this.sentry.lastEventId) {
676
- const eventId = this.sentry.lastEventId();
677
- if (eventId) {
678
- this.sentryEventIds.set(serverErrorKey, eventId);
679
- }
680
- }
681
- }
682
- async tryImportSentry() {
683
- try {
684
- this.sentry = await import("@sentry/node");
685
- } catch (e) {
686
- }
687
- }
688
- };
689
- __name(_ServerErrorCounter, "ServerErrorCounter");
690
- var ServerErrorCounter = _ServerErrorCounter;
691
-
692
703
  // src/common/validationErrorCounter.ts
693
704
  var import_crypto4 = require("crypto");
694
705
  var _ValidationErrorCounter = class _ValidationErrorCounter {
@@ -1113,7 +1124,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
1113
1124
  headers: convertHeaders(c.res.headers),
1114
1125
  size: responseSize,
1115
1126
  body: responseBody
1116
- });
1127
+ }, c.error);
1117
1128
  }
1118
1129
  c.res = response;
1119
1130
  };