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.
- package/README.md +2 -2
- package/dist/common/client.cjs +116 -105
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.js +111 -100
- package/dist/common/client.js.map +1 -1
- package/dist/common/requestLogger.cjs +55 -2
- package/dist/common/requestLogger.cjs.map +1 -1
- package/dist/common/requestLogger.d.cts +2 -1
- package/dist/common/requestLogger.d.ts +2 -1
- package/dist/common/requestLogger.js +55 -2
- package/dist/common/requestLogger.js.map +1 -1
- package/dist/common/sentry.cjs +55 -0
- package/dist/common/sentry.cjs.map +1 -0
- package/dist/common/sentry.d.cts +6 -0
- package/dist/common/sentry.d.ts +6 -0
- package/dist/common/sentry.js +22 -0
- package/dist/common/sentry.js.map +1 -0
- package/dist/common/serverErrorCounter.cjs +58 -45
- package/dist/common/serverErrorCounter.cjs.map +1 -1
- package/dist/common/serverErrorCounter.d.cts +3 -6
- package/dist/common/serverErrorCounter.d.ts +3 -6
- package/dist/common/serverErrorCounter.js +53 -45
- package/dist/common/serverErrorCounter.js.map +1 -1
- package/dist/express/index.cjs +117 -106
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.js +112 -101
- package/dist/express/index.js.map +1 -1
- package/dist/express/middleware.cjs +117 -106
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.js +112 -101
- package/dist/express/middleware.js.map +1 -1
- package/dist/fastify/index.cjs +117 -106
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.js +112 -101
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.cjs +117 -106
- package/dist/fastify/plugin.cjs.map +1 -1
- package/dist/fastify/plugin.js +112 -101
- package/dist/fastify/plugin.js.map +1 -1
- package/dist/hono/index.cjs +117 -106
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.js +112 -101
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.cjs +117 -106
- package/dist/hono/middleware.cjs.map +1 -1
- package/dist/hono/middleware.js +112 -101
- package/dist/hono/middleware.js.map +1 -1
- package/dist/koa/index.cjs +119 -106
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.js +114 -101
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +119 -106
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.js +114 -101
- package/dist/koa/middleware.js.map +1 -1
- package/dist/nestjs/index.cjs +117 -106
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.js +112 -101
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +1 -1
package/dist/koa/middleware.cjs
CHANGED
|
@@ -210,14 +210,116 @@ var RequestCounter = _RequestCounter;
|
|
|
210
210
|
// src/common/requestLogger.ts
|
|
211
211
|
var import_async_lock = __toESM(require("async-lock"), 1);
|
|
212
212
|
var import_buffer2 = require("buffer");
|
|
213
|
-
var
|
|
213
|
+
var import_crypto3 = require("crypto");
|
|
214
214
|
var import_fs2 = require("fs");
|
|
215
215
|
var import_os2 = require("os");
|
|
216
216
|
var import_path2 = require("path");
|
|
217
217
|
|
|
218
|
+
// src/common/sentry.ts
|
|
219
|
+
var sentry;
|
|
220
|
+
(async () => {
|
|
221
|
+
try {
|
|
222
|
+
sentry = await import("@sentry/node");
|
|
223
|
+
} catch (e) {
|
|
224
|
+
}
|
|
225
|
+
})();
|
|
226
|
+
function getSentryEventId() {
|
|
227
|
+
if (sentry && sentry.lastEventId) {
|
|
228
|
+
return sentry.lastEventId();
|
|
229
|
+
}
|
|
230
|
+
return void 0;
|
|
231
|
+
}
|
|
232
|
+
__name(getSentryEventId, "getSentryEventId");
|
|
233
|
+
|
|
234
|
+
// src/common/serverErrorCounter.ts
|
|
235
|
+
var import_crypto = require("crypto");
|
|
236
|
+
var MAX_MSG_LENGTH = 2048;
|
|
237
|
+
var MAX_STACKTRACE_LENGTH = 65536;
|
|
238
|
+
var _ServerErrorCounter = class _ServerErrorCounter {
|
|
239
|
+
errorCounts;
|
|
240
|
+
errorDetails;
|
|
241
|
+
sentryEventIds;
|
|
242
|
+
constructor() {
|
|
243
|
+
this.errorCounts = /* @__PURE__ */ new Map();
|
|
244
|
+
this.errorDetails = /* @__PURE__ */ new Map();
|
|
245
|
+
this.sentryEventIds = /* @__PURE__ */ new Map();
|
|
246
|
+
}
|
|
247
|
+
addServerError(serverError) {
|
|
248
|
+
const key = this.getKey(serverError);
|
|
249
|
+
if (!this.errorDetails.has(key)) {
|
|
250
|
+
this.errorDetails.set(key, serverError);
|
|
251
|
+
}
|
|
252
|
+
this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
|
|
253
|
+
const sentryEventId = getSentryEventId();
|
|
254
|
+
if (sentryEventId) {
|
|
255
|
+
this.sentryEventIds.set(key, sentryEventId);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
getAndResetServerErrors() {
|
|
259
|
+
const data = [];
|
|
260
|
+
this.errorCounts.forEach((count, key) => {
|
|
261
|
+
const serverError = this.errorDetails.get(key);
|
|
262
|
+
if (serverError) {
|
|
263
|
+
data.push({
|
|
264
|
+
consumer: serverError.consumer || null,
|
|
265
|
+
method: serverError.method,
|
|
266
|
+
path: serverError.path,
|
|
267
|
+
type: serverError.type,
|
|
268
|
+
msg: truncateExceptionMessage(serverError.msg),
|
|
269
|
+
traceback: truncateExceptionStackTrace(serverError.traceback),
|
|
270
|
+
sentry_event_id: this.sentryEventIds.get(key) || null,
|
|
271
|
+
error_count: count
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
this.errorCounts.clear();
|
|
276
|
+
this.errorDetails.clear();
|
|
277
|
+
return data;
|
|
278
|
+
}
|
|
279
|
+
getKey(serverError) {
|
|
280
|
+
const hashInput = [
|
|
281
|
+
serverError.consumer || "",
|
|
282
|
+
serverError.method.toUpperCase(),
|
|
283
|
+
serverError.path,
|
|
284
|
+
serverError.type,
|
|
285
|
+
serverError.msg.trim(),
|
|
286
|
+
serverError.traceback.trim()
|
|
287
|
+
].join("|");
|
|
288
|
+
return (0, import_crypto.createHash)("md5").update(hashInput).digest("hex");
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
__name(_ServerErrorCounter, "ServerErrorCounter");
|
|
292
|
+
var ServerErrorCounter = _ServerErrorCounter;
|
|
293
|
+
function truncateExceptionMessage(msg) {
|
|
294
|
+
if (msg.length <= MAX_MSG_LENGTH) {
|
|
295
|
+
return msg;
|
|
296
|
+
}
|
|
297
|
+
const suffix = "... (truncated)";
|
|
298
|
+
const cutoff = MAX_MSG_LENGTH - suffix.length;
|
|
299
|
+
return msg.substring(0, cutoff) + suffix;
|
|
300
|
+
}
|
|
301
|
+
__name(truncateExceptionMessage, "truncateExceptionMessage");
|
|
302
|
+
function truncateExceptionStackTrace(stack) {
|
|
303
|
+
const suffix = "... (truncated) ...";
|
|
304
|
+
const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
|
|
305
|
+
const lines = stack.trim().split("\n");
|
|
306
|
+
const truncatedLines = [];
|
|
307
|
+
let length = 0;
|
|
308
|
+
for (const line of lines) {
|
|
309
|
+
if (length + line.length + 1 > cutoff) {
|
|
310
|
+
truncatedLines.push(suffix);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
truncatedLines.push(line);
|
|
314
|
+
length += line.length + 1;
|
|
315
|
+
}
|
|
316
|
+
return truncatedLines.join("\n");
|
|
317
|
+
}
|
|
318
|
+
__name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
|
|
319
|
+
|
|
218
320
|
// src/common/tempGzipFile.ts
|
|
219
321
|
var import_buffer = require("buffer");
|
|
220
|
-
var
|
|
322
|
+
var import_crypto2 = require("crypto");
|
|
221
323
|
var import_fs = require("fs");
|
|
222
324
|
var import_os = require("os");
|
|
223
325
|
var import_path = require("path");
|
|
@@ -230,7 +332,7 @@ var _TempGzipFile = class _TempGzipFile {
|
|
|
230
332
|
readyPromise;
|
|
231
333
|
closedPromise;
|
|
232
334
|
constructor() {
|
|
233
|
-
this.uuid = (0,
|
|
335
|
+
this.uuid = (0, import_crypto2.randomUUID)();
|
|
234
336
|
this.filePath = (0, import_path.join)((0, import_os.tmpdir)(), `apitally-${this.uuid}.gz`);
|
|
235
337
|
this.writeStream = (0, import_fs.createWriteStream)(this.filePath);
|
|
236
338
|
this.readyPromise = new Promise((resolve, reject) => {
|
|
@@ -337,6 +439,7 @@ var DEFAULT_CONFIG = {
|
|
|
337
439
|
logRequestBody: false,
|
|
338
440
|
logResponseHeaders: true,
|
|
339
441
|
logResponseBody: false,
|
|
442
|
+
logException: true,
|
|
340
443
|
maskQueryParams: [],
|
|
341
444
|
maskHeaders: [],
|
|
342
445
|
excludePaths: []
|
|
@@ -409,7 +512,7 @@ var _RequestLogger = class _RequestLogger {
|
|
|
409
512
|
this.shouldMaskHeader(k) ? MASKED : v
|
|
410
513
|
]);
|
|
411
514
|
}
|
|
412
|
-
logRequest(request, response) {
|
|
515
|
+
logRequest(request, response, error) {
|
|
413
516
|
var _a2, _b, _c;
|
|
414
517
|
if (!this.enabled || this.suspendUntil !== null) return;
|
|
415
518
|
const url = new URL(request.url);
|
|
@@ -455,9 +558,15 @@ var _RequestLogger = class _RequestLogger {
|
|
|
455
558
|
request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
|
|
456
559
|
response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
|
|
457
560
|
const item = {
|
|
458
|
-
uuid: (0,
|
|
561
|
+
uuid: (0, import_crypto3.randomUUID)(),
|
|
459
562
|
request: skipEmptyValues(request),
|
|
460
|
-
response: skipEmptyValues(response)
|
|
563
|
+
response: skipEmptyValues(response),
|
|
564
|
+
exception: error && this.config.logException ? {
|
|
565
|
+
type: error.name,
|
|
566
|
+
message: truncateExceptionMessage(error.message),
|
|
567
|
+
stacktrace: truncateExceptionStackTrace(error.stack || ""),
|
|
568
|
+
sentryEventId: getSentryEventId()
|
|
569
|
+
} : null
|
|
461
570
|
};
|
|
462
571
|
[
|
|
463
572
|
item.request.body,
|
|
@@ -609,7 +718,7 @@ function skipEmptyValues(data) {
|
|
|
609
718
|
__name(skipEmptyValues, "skipEmptyValues");
|
|
610
719
|
function checkWritableFs() {
|
|
611
720
|
try {
|
|
612
|
-
const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0,
|
|
721
|
+
const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto3.randomUUID)()}`);
|
|
613
722
|
(0, import_fs2.writeFileSync)(testPath, "test");
|
|
614
723
|
(0, import_fs2.unlinkSync)(testPath);
|
|
615
724
|
return true;
|
|
@@ -619,104 +728,6 @@ function checkWritableFs() {
|
|
|
619
728
|
}
|
|
620
729
|
__name(checkWritableFs, "checkWritableFs");
|
|
621
730
|
|
|
622
|
-
// src/common/serverErrorCounter.ts
|
|
623
|
-
var import_crypto3 = require("crypto");
|
|
624
|
-
var MAX_MSG_LENGTH = 2048;
|
|
625
|
-
var MAX_STACKTRACE_LENGTH = 65536;
|
|
626
|
-
var _ServerErrorCounter = class _ServerErrorCounter {
|
|
627
|
-
errorCounts;
|
|
628
|
-
errorDetails;
|
|
629
|
-
sentryEventIds;
|
|
630
|
-
sentry;
|
|
631
|
-
constructor() {
|
|
632
|
-
this.errorCounts = /* @__PURE__ */ new Map();
|
|
633
|
-
this.errorDetails = /* @__PURE__ */ new Map();
|
|
634
|
-
this.sentryEventIds = /* @__PURE__ */ new Map();
|
|
635
|
-
this.tryImportSentry();
|
|
636
|
-
}
|
|
637
|
-
addServerError(serverError) {
|
|
638
|
-
const key = this.getKey(serverError);
|
|
639
|
-
if (!this.errorDetails.has(key)) {
|
|
640
|
-
this.errorDetails.set(key, serverError);
|
|
641
|
-
}
|
|
642
|
-
this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
|
|
643
|
-
this.captureSentryEventId(key);
|
|
644
|
-
}
|
|
645
|
-
getAndResetServerErrors() {
|
|
646
|
-
const data = [];
|
|
647
|
-
this.errorCounts.forEach((count, key) => {
|
|
648
|
-
const serverError = this.errorDetails.get(key);
|
|
649
|
-
if (serverError) {
|
|
650
|
-
data.push({
|
|
651
|
-
consumer: serverError.consumer || null,
|
|
652
|
-
method: serverError.method,
|
|
653
|
-
path: serverError.path,
|
|
654
|
-
type: serverError.type,
|
|
655
|
-
msg: this.getTruncatedMessage(serverError.msg),
|
|
656
|
-
traceback: this.getTruncatedStack(serverError.traceback),
|
|
657
|
-
sentry_event_id: this.sentryEventIds.get(key) || null,
|
|
658
|
-
error_count: count
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
});
|
|
662
|
-
this.errorCounts.clear();
|
|
663
|
-
this.errorDetails.clear();
|
|
664
|
-
return data;
|
|
665
|
-
}
|
|
666
|
-
getKey(serverError) {
|
|
667
|
-
const hashInput = [
|
|
668
|
-
serverError.consumer || "",
|
|
669
|
-
serverError.method.toUpperCase(),
|
|
670
|
-
serverError.path,
|
|
671
|
-
serverError.type,
|
|
672
|
-
serverError.msg.trim(),
|
|
673
|
-
serverError.traceback.trim()
|
|
674
|
-
].join("|");
|
|
675
|
-
return (0, import_crypto3.createHash)("md5").update(hashInput).digest("hex");
|
|
676
|
-
}
|
|
677
|
-
getTruncatedMessage(msg) {
|
|
678
|
-
msg = msg.trim();
|
|
679
|
-
if (msg.length <= MAX_MSG_LENGTH) {
|
|
680
|
-
return msg;
|
|
681
|
-
}
|
|
682
|
-
const suffix = "... (truncated)";
|
|
683
|
-
const cutoff = MAX_MSG_LENGTH - suffix.length;
|
|
684
|
-
return msg.substring(0, cutoff) + suffix;
|
|
685
|
-
}
|
|
686
|
-
getTruncatedStack(stack) {
|
|
687
|
-
const suffix = "... (truncated) ...";
|
|
688
|
-
const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
|
|
689
|
-
const lines = stack.trim().split("\n");
|
|
690
|
-
const truncatedLines = [];
|
|
691
|
-
let length = 0;
|
|
692
|
-
for (const line of lines) {
|
|
693
|
-
if (length + line.length + 1 > cutoff) {
|
|
694
|
-
truncatedLines.push(suffix);
|
|
695
|
-
break;
|
|
696
|
-
}
|
|
697
|
-
truncatedLines.push(line);
|
|
698
|
-
length += line.length + 1;
|
|
699
|
-
}
|
|
700
|
-
return truncatedLines.join("\n");
|
|
701
|
-
}
|
|
702
|
-
captureSentryEventId(serverErrorKey) {
|
|
703
|
-
if (this.sentry && this.sentry.lastEventId) {
|
|
704
|
-
const eventId = this.sentry.lastEventId();
|
|
705
|
-
if (eventId) {
|
|
706
|
-
this.sentryEventIds.set(serverErrorKey, eventId);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
async tryImportSentry() {
|
|
711
|
-
try {
|
|
712
|
-
this.sentry = await import("@sentry/node");
|
|
713
|
-
} catch (e) {
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
};
|
|
717
|
-
__name(_ServerErrorCounter, "ServerErrorCounter");
|
|
718
|
-
var ServerErrorCounter = _ServerErrorCounter;
|
|
719
|
-
|
|
720
731
|
// src/common/validationErrorCounter.ts
|
|
721
732
|
var import_crypto4 = require("crypto");
|
|
722
733
|
var _ValidationErrorCounter = class _ValidationErrorCounter {
|
|
@@ -1076,6 +1087,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
|
|
|
1076
1087
|
}
|
|
1077
1088
|
let path;
|
|
1078
1089
|
let statusCode;
|
|
1090
|
+
let serverError;
|
|
1079
1091
|
const startTime = performance.now();
|
|
1080
1092
|
try {
|
|
1081
1093
|
await next();
|
|
@@ -1083,6 +1095,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
|
|
|
1083
1095
|
path = getPath(ctx);
|
|
1084
1096
|
statusCode = error.statusCode || error.status || 500;
|
|
1085
1097
|
if (path && statusCode === 500 && error instanceof Error) {
|
|
1098
|
+
serverError = error;
|
|
1086
1099
|
client.serverErrorCounter.addServerError({
|
|
1087
1100
|
consumer: (_a2 = getConsumer(ctx)) == null ? void 0 : _a2.identifier,
|
|
1088
1101
|
method: ctx.request.method,
|
|
@@ -1134,7 +1147,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
|
|
|
1134
1147
|
headers: convertHeaders(ctx.response.headers),
|
|
1135
1148
|
size: Number(ctx.response.headers["content-length"]),
|
|
1136
1149
|
body: convertBody(ctx.response.body, ctx.response.get("content-type"))
|
|
1137
|
-
});
|
|
1150
|
+
}, serverError);
|
|
1138
1151
|
}
|
|
1139
1152
|
}
|
|
1140
1153
|
};
|