apitally 0.11.5 → 0.13.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 +43 -2
- package/dist/adonisjs/index.cjs +41 -0
- package/dist/adonisjs/index.cjs.map +1 -0
- package/dist/adonisjs/index.d.cts +14 -0
- package/dist/adonisjs/index.d.ts +14 -0
- package/dist/adonisjs/index.js +17 -0
- package/dist/adonisjs/index.js.map +1 -0
- package/dist/adonisjs/middleware.cjs +214 -0
- package/dist/adonisjs/middleware.cjs.map +1 -0
- package/dist/adonisjs/middleware.d.cts +21 -0
- package/dist/adonisjs/middleware.d.ts +21 -0
- package/dist/adonisjs/middleware.js +185 -0
- package/dist/adonisjs/middleware.js.map +1 -0
- package/dist/adonisjs/provider.cjs +1083 -0
- package/dist/adonisjs/provider.cjs.map +1 -0
- package/dist/adonisjs/provider.d.cts +28 -0
- package/dist/adonisjs/provider.d.ts +28 -0
- package/dist/adonisjs/provider.js +1057 -0
- package/dist/adonisjs/provider.js.map +1 -0
- package/dist/common/client.cjs +117 -106
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.js +112 -101
- package/dist/common/client.js.map +1 -1
- package/dist/common/consumerRegistry.cjs.map +1 -1
- package/dist/common/consumerRegistry.js.map +1 -1
- package/dist/common/logging.cjs.map +1 -1
- package/dist/common/logging.js.map +1 -1
- package/dist/common/packageVersions.cjs.map +1 -1
- package/dist/common/packageVersions.js.map +1 -1
- package/dist/common/paramValidation.cjs.map +1 -1
- package/dist/common/paramValidation.js.map +1 -1
- package/dist/common/requestCounter.cjs.map +1 -1
- package/dist/common/requestCounter.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/common/tempGzipFile.cjs.map +1 -1
- package/dist/common/tempGzipFile.js.map +1 -1
- package/dist/common/types.cjs.map +1 -1
- package/dist/common/utils.cjs +48 -0
- package/dist/common/utils.cjs.map +1 -0
- package/dist/common/utils.d.cts +5 -0
- package/dist/common/utils.d.ts +5 -0
- package/dist/common/utils.js +25 -0
- package/dist/common/utils.js.map +1 -0
- package/dist/common/validationErrorCounter.cjs.map +1 -1
- package/dist/common/validationErrorCounter.js.map +1 -1
- package/dist/express/index.cjs +143 -111
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.js +138 -106
- package/dist/express/index.js.map +1 -1
- package/dist/express/middleware.cjs +143 -111
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.js +138 -106
- package/dist/express/middleware.js.map +1 -1
- package/dist/express/utils.cjs.map +1 -1
- package/dist/express/utils.js.map +1 -1
- package/dist/fastify/index.cjs +139 -112
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.js +134 -107
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.cjs +139 -112
- package/dist/fastify/plugin.cjs.map +1 -1
- package/dist/fastify/plugin.js +134 -107
- package/dist/fastify/plugin.js.map +1 -1
- package/dist/hono/index.cjs +138 -108
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.js +133 -103
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.cjs +138 -108
- package/dist/hono/middleware.cjs.map +1 -1
- package/dist/hono/middleware.js +133 -103
- package/dist/hono/middleware.js.map +1 -1
- package/dist/koa/index.cjs +122 -109
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.js +117 -104
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +122 -109
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.js +117 -104
- package/dist/koa/middleware.js.map +1 -1
- package/dist/nestjs/index.cjs +143 -111
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.js +138 -106
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +46 -1
package/dist/fastify/index.js
CHANGED
|
@@ -190,6 +190,108 @@ import { unlinkSync as unlinkSync2, writeFileSync } from "fs";
|
|
|
190
190
|
import { tmpdir as tmpdir2 } from "os";
|
|
191
191
|
import { join as join2 } from "path";
|
|
192
192
|
|
|
193
|
+
// src/common/sentry.ts
|
|
194
|
+
var sentry;
|
|
195
|
+
(async () => {
|
|
196
|
+
try {
|
|
197
|
+
sentry = await import("@sentry/node");
|
|
198
|
+
} catch (e) {
|
|
199
|
+
}
|
|
200
|
+
})();
|
|
201
|
+
function getSentryEventId() {
|
|
202
|
+
if (sentry && sentry.lastEventId) {
|
|
203
|
+
return sentry.lastEventId();
|
|
204
|
+
}
|
|
205
|
+
return void 0;
|
|
206
|
+
}
|
|
207
|
+
__name(getSentryEventId, "getSentryEventId");
|
|
208
|
+
|
|
209
|
+
// src/common/serverErrorCounter.ts
|
|
210
|
+
import { createHash } from "crypto";
|
|
211
|
+
var MAX_MSG_LENGTH = 2048;
|
|
212
|
+
var MAX_STACKTRACE_LENGTH = 65536;
|
|
213
|
+
var _ServerErrorCounter = class _ServerErrorCounter {
|
|
214
|
+
errorCounts;
|
|
215
|
+
errorDetails;
|
|
216
|
+
sentryEventIds;
|
|
217
|
+
constructor() {
|
|
218
|
+
this.errorCounts = /* @__PURE__ */ new Map();
|
|
219
|
+
this.errorDetails = /* @__PURE__ */ new Map();
|
|
220
|
+
this.sentryEventIds = /* @__PURE__ */ new Map();
|
|
221
|
+
}
|
|
222
|
+
addServerError(serverError) {
|
|
223
|
+
const key = this.getKey(serverError);
|
|
224
|
+
if (!this.errorDetails.has(key)) {
|
|
225
|
+
this.errorDetails.set(key, serverError);
|
|
226
|
+
}
|
|
227
|
+
this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
|
|
228
|
+
const sentryEventId = getSentryEventId();
|
|
229
|
+
if (sentryEventId) {
|
|
230
|
+
this.sentryEventIds.set(key, sentryEventId);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
getAndResetServerErrors() {
|
|
234
|
+
const data = [];
|
|
235
|
+
this.errorCounts.forEach((count, key) => {
|
|
236
|
+
const serverError = this.errorDetails.get(key);
|
|
237
|
+
if (serverError) {
|
|
238
|
+
data.push({
|
|
239
|
+
consumer: serverError.consumer || null,
|
|
240
|
+
method: serverError.method,
|
|
241
|
+
path: serverError.path,
|
|
242
|
+
type: serverError.type,
|
|
243
|
+
msg: truncateExceptionMessage(serverError.msg),
|
|
244
|
+
traceback: truncateExceptionStackTrace(serverError.traceback),
|
|
245
|
+
sentry_event_id: this.sentryEventIds.get(key) || null,
|
|
246
|
+
error_count: count
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
this.errorCounts.clear();
|
|
251
|
+
this.errorDetails.clear();
|
|
252
|
+
return data;
|
|
253
|
+
}
|
|
254
|
+
getKey(serverError) {
|
|
255
|
+
const hashInput = [
|
|
256
|
+
serverError.consumer || "",
|
|
257
|
+
serverError.method.toUpperCase(),
|
|
258
|
+
serverError.path,
|
|
259
|
+
serverError.type,
|
|
260
|
+
serverError.msg.trim(),
|
|
261
|
+
serverError.traceback.trim()
|
|
262
|
+
].join("|");
|
|
263
|
+
return createHash("md5").update(hashInput).digest("hex");
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
__name(_ServerErrorCounter, "ServerErrorCounter");
|
|
267
|
+
var ServerErrorCounter = _ServerErrorCounter;
|
|
268
|
+
function truncateExceptionMessage(msg) {
|
|
269
|
+
if (msg.length <= MAX_MSG_LENGTH) {
|
|
270
|
+
return msg;
|
|
271
|
+
}
|
|
272
|
+
const suffix = "... (truncated)";
|
|
273
|
+
const cutoff = MAX_MSG_LENGTH - suffix.length;
|
|
274
|
+
return msg.substring(0, cutoff) + suffix;
|
|
275
|
+
}
|
|
276
|
+
__name(truncateExceptionMessage, "truncateExceptionMessage");
|
|
277
|
+
function truncateExceptionStackTrace(stack) {
|
|
278
|
+
const suffix = "... (truncated) ...";
|
|
279
|
+
const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
|
|
280
|
+
const lines = stack.trim().split("\n");
|
|
281
|
+
const truncatedLines = [];
|
|
282
|
+
let length = 0;
|
|
283
|
+
for (const line of lines) {
|
|
284
|
+
if (length + line.length + 1 > cutoff) {
|
|
285
|
+
truncatedLines.push(suffix);
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
truncatedLines.push(line);
|
|
289
|
+
length += line.length + 1;
|
|
290
|
+
}
|
|
291
|
+
return truncatedLines.join("\n");
|
|
292
|
+
}
|
|
293
|
+
__name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
|
|
294
|
+
|
|
193
295
|
// src/common/tempGzipFile.ts
|
|
194
296
|
import { Buffer as Buffer2 } from "buffer";
|
|
195
297
|
import { randomUUID } from "crypto";
|
|
@@ -312,6 +414,7 @@ var DEFAULT_CONFIG = {
|
|
|
312
414
|
logRequestBody: false,
|
|
313
415
|
logResponseHeaders: true,
|
|
314
416
|
logResponseBody: false,
|
|
417
|
+
logException: true,
|
|
315
418
|
maskQueryParams: [],
|
|
316
419
|
maskHeaders: [],
|
|
317
420
|
excludePaths: []
|
|
@@ -384,7 +487,7 @@ var _RequestLogger = class _RequestLogger {
|
|
|
384
487
|
this.shouldMaskHeader(k) ? MASKED : v
|
|
385
488
|
]);
|
|
386
489
|
}
|
|
387
|
-
logRequest(request, response) {
|
|
490
|
+
logRequest(request, response, error) {
|
|
388
491
|
var _a2, _b, _c;
|
|
389
492
|
if (!this.enabled || this.suspendUntil !== null) return;
|
|
390
493
|
const url = new URL(request.url);
|
|
@@ -432,7 +535,13 @@ var _RequestLogger = class _RequestLogger {
|
|
|
432
535
|
const item = {
|
|
433
536
|
uuid: randomUUID2(),
|
|
434
537
|
request: skipEmptyValues(request),
|
|
435
|
-
response: skipEmptyValues(response)
|
|
538
|
+
response: skipEmptyValues(response),
|
|
539
|
+
exception: error && this.config.logException ? {
|
|
540
|
+
type: error.name,
|
|
541
|
+
message: truncateExceptionMessage(error.message),
|
|
542
|
+
stacktrace: truncateExceptionStackTrace(error.stack || ""),
|
|
543
|
+
sentryEventId: getSentryEventId()
|
|
544
|
+
} : null
|
|
436
545
|
};
|
|
437
546
|
[
|
|
438
547
|
item.request.body,
|
|
@@ -594,104 +703,6 @@ function checkWritableFs() {
|
|
|
594
703
|
}
|
|
595
704
|
__name(checkWritableFs, "checkWritableFs");
|
|
596
705
|
|
|
597
|
-
// src/common/serverErrorCounter.ts
|
|
598
|
-
import { createHash } from "crypto";
|
|
599
|
-
var MAX_MSG_LENGTH = 2048;
|
|
600
|
-
var MAX_STACKTRACE_LENGTH = 65536;
|
|
601
|
-
var _ServerErrorCounter = class _ServerErrorCounter {
|
|
602
|
-
errorCounts;
|
|
603
|
-
errorDetails;
|
|
604
|
-
sentryEventIds;
|
|
605
|
-
sentry;
|
|
606
|
-
constructor() {
|
|
607
|
-
this.errorCounts = /* @__PURE__ */ new Map();
|
|
608
|
-
this.errorDetails = /* @__PURE__ */ new Map();
|
|
609
|
-
this.sentryEventIds = /* @__PURE__ */ new Map();
|
|
610
|
-
this.tryImportSentry();
|
|
611
|
-
}
|
|
612
|
-
addServerError(serverError) {
|
|
613
|
-
const key = this.getKey(serverError);
|
|
614
|
-
if (!this.errorDetails.has(key)) {
|
|
615
|
-
this.errorDetails.set(key, serverError);
|
|
616
|
-
}
|
|
617
|
-
this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
|
|
618
|
-
this.captureSentryEventId(key);
|
|
619
|
-
}
|
|
620
|
-
getAndResetServerErrors() {
|
|
621
|
-
const data = [];
|
|
622
|
-
this.errorCounts.forEach((count, key) => {
|
|
623
|
-
const serverError = this.errorDetails.get(key);
|
|
624
|
-
if (serverError) {
|
|
625
|
-
data.push({
|
|
626
|
-
consumer: serverError.consumer || null,
|
|
627
|
-
method: serverError.method,
|
|
628
|
-
path: serverError.path,
|
|
629
|
-
type: serverError.type,
|
|
630
|
-
msg: this.getTruncatedMessage(serverError.msg),
|
|
631
|
-
traceback: this.getTruncatedStack(serverError.traceback),
|
|
632
|
-
sentry_event_id: this.sentryEventIds.get(key) || null,
|
|
633
|
-
error_count: count
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
});
|
|
637
|
-
this.errorCounts.clear();
|
|
638
|
-
this.errorDetails.clear();
|
|
639
|
-
return data;
|
|
640
|
-
}
|
|
641
|
-
getKey(serverError) {
|
|
642
|
-
const hashInput = [
|
|
643
|
-
serverError.consumer || "",
|
|
644
|
-
serverError.method.toUpperCase(),
|
|
645
|
-
serverError.path,
|
|
646
|
-
serverError.type,
|
|
647
|
-
serverError.msg.trim(),
|
|
648
|
-
serverError.traceback.trim()
|
|
649
|
-
].join("|");
|
|
650
|
-
return createHash("md5").update(hashInput).digest("hex");
|
|
651
|
-
}
|
|
652
|
-
getTruncatedMessage(msg) {
|
|
653
|
-
msg = msg.trim();
|
|
654
|
-
if (msg.length <= MAX_MSG_LENGTH) {
|
|
655
|
-
return msg;
|
|
656
|
-
}
|
|
657
|
-
const suffix = "... (truncated)";
|
|
658
|
-
const cutoff = MAX_MSG_LENGTH - suffix.length;
|
|
659
|
-
return msg.substring(0, cutoff) + suffix;
|
|
660
|
-
}
|
|
661
|
-
getTruncatedStack(stack) {
|
|
662
|
-
const suffix = "... (truncated) ...";
|
|
663
|
-
const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
|
|
664
|
-
const lines = stack.trim().split("\n");
|
|
665
|
-
const truncatedLines = [];
|
|
666
|
-
let length = 0;
|
|
667
|
-
for (const line of lines) {
|
|
668
|
-
if (length + line.length + 1 > cutoff) {
|
|
669
|
-
truncatedLines.push(suffix);
|
|
670
|
-
break;
|
|
671
|
-
}
|
|
672
|
-
truncatedLines.push(line);
|
|
673
|
-
length += line.length + 1;
|
|
674
|
-
}
|
|
675
|
-
return truncatedLines.join("\n");
|
|
676
|
-
}
|
|
677
|
-
captureSentryEventId(serverErrorKey) {
|
|
678
|
-
if (this.sentry && this.sentry.lastEventId) {
|
|
679
|
-
const eventId = this.sentry.lastEventId();
|
|
680
|
-
if (eventId) {
|
|
681
|
-
this.sentryEventIds.set(serverErrorKey, eventId);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
async tryImportSentry() {
|
|
686
|
-
try {
|
|
687
|
-
this.sentry = await import("@sentry/node");
|
|
688
|
-
} catch (e) {
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
};
|
|
692
|
-
__name(_ServerErrorCounter, "ServerErrorCounter");
|
|
693
|
-
var ServerErrorCounter = _ServerErrorCounter;
|
|
694
|
-
|
|
695
706
|
// src/common/validationErrorCounter.ts
|
|
696
707
|
import { createHash as createHash2 } from "crypto";
|
|
697
708
|
var _ValidationErrorCounter = class _ValidationErrorCounter {
|
|
@@ -777,7 +788,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
777
788
|
throw new Error("Apitally client is already initialized");
|
|
778
789
|
}
|
|
779
790
|
if (!isValidClientId(clientId)) {
|
|
780
|
-
throw new Error(`Invalid client ID '${clientId}' (expecting
|
|
791
|
+
throw new Error(`Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`);
|
|
781
792
|
}
|
|
782
793
|
if (!isValidEnv(env)) {
|
|
783
794
|
throw new Error(`Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`);
|
|
@@ -1032,6 +1043,25 @@ function getPackageVersion(name) {
|
|
|
1032
1043
|
}
|
|
1033
1044
|
__name(getPackageVersion, "getPackageVersion");
|
|
1034
1045
|
|
|
1046
|
+
// src/common/utils.ts
|
|
1047
|
+
function parseContentLength(contentLength) {
|
|
1048
|
+
if (contentLength === void 0 || contentLength === null) {
|
|
1049
|
+
return void 0;
|
|
1050
|
+
}
|
|
1051
|
+
if (typeof contentLength === "number") {
|
|
1052
|
+
return contentLength;
|
|
1053
|
+
}
|
|
1054
|
+
if (typeof contentLength === "string") {
|
|
1055
|
+
const parsed = parseInt(contentLength);
|
|
1056
|
+
return isNaN(parsed) ? void 0 : parsed;
|
|
1057
|
+
}
|
|
1058
|
+
if (Array.isArray(contentLength)) {
|
|
1059
|
+
return parseContentLength(contentLength[0]);
|
|
1060
|
+
}
|
|
1061
|
+
return void 0;
|
|
1062
|
+
}
|
|
1063
|
+
__name(parseContentLength, "parseContentLength");
|
|
1064
|
+
|
|
1035
1065
|
// src/fastify/plugin.ts
|
|
1036
1066
|
var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
|
|
1037
1067
|
const client = new ApitallyClient(config);
|
|
@@ -1079,11 +1109,8 @@ var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
|
|
|
1079
1109
|
if (client.isEnabled() && request.method.toUpperCase() !== "OPTIONS") {
|
|
1080
1110
|
const consumer = getConsumer(request);
|
|
1081
1111
|
const path = "routeOptions" in request ? request.routeOptions.url : request.routerPath;
|
|
1082
|
-
const requestSize = request.headers["content-length"];
|
|
1083
|
-
|
|
1084
|
-
if (Array.isArray(responseSize)) {
|
|
1085
|
-
responseSize = responseSize[0];
|
|
1086
|
-
}
|
|
1112
|
+
const requestSize = parseContentLength(request.headers["content-length"]);
|
|
1113
|
+
const responseSize = parseContentLength(reply.getHeader("content-length"));
|
|
1087
1114
|
const responseTime = getResponseTime(reply);
|
|
1088
1115
|
client.consumerRegistry.addOrUpdateConsumer(consumer);
|
|
1089
1116
|
client.requestCounter.addRequest({
|
|
@@ -1138,7 +1165,7 @@ var apitallyPlugin = /* @__PURE__ */ __name(async (fastify, config) => {
|
|
|
1138
1165
|
headers: convertHeaders(reply.getHeaders()),
|
|
1139
1166
|
size: Number(responseSize),
|
|
1140
1167
|
body: convertBody(reply.payload, (_a2 = reply.getHeader("content-type")) == null ? void 0 : _a2.toString())
|
|
1141
|
-
});
|
|
1168
|
+
}, reply.serverError);
|
|
1142
1169
|
}
|
|
1143
1170
|
}
|
|
1144
1171
|
done();
|