apitally 0.11.4 → 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 +27 -14
- package/dist/common/client.cjs +130 -110
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.d.cts +2 -0
- package/dist/common/client.d.ts +2 -0
- package/dist/common/client.js +125 -105
- 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 +63 -7
- package/dist/common/requestLogger.cjs.map +1 -1
- package/dist/common/requestLogger.d.cts +3 -1
- package/dist/common/requestLogger.d.ts +3 -1
- package/dist/common/requestLogger.js +63 -7
- 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 +2 -2
- package/dist/common/tempGzipFile.cjs.map +1 -1
- package/dist/common/tempGzipFile.js +2 -2
- package/dist/common/tempGzipFile.js.map +1 -1
- package/dist/common/types.cjs.map +1 -1
- package/dist/common/validationErrorCounter.cjs.map +1 -1
- package/dist/common/validationErrorCounter.js.map +1 -1
- package/dist/express/index.cjs +139 -112
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.js +134 -107
- package/dist/express/index.js.map +1 -1
- package/dist/express/middleware.cjs +139 -112
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.js +134 -107
- 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 +136 -113
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.js +131 -108
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.cjs +136 -113
- package/dist/fastify/plugin.cjs.map +1 -1
- package/dist/fastify/plugin.js +131 -108
- package/dist/fastify/plugin.js.map +1 -1
- package/dist/hono/index.cjs +137 -112
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.js +132 -107
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.cjs +137 -112
- package/dist/hono/middleware.cjs.map +1 -1
- package/dist/hono/middleware.js +132 -107
- package/dist/hono/middleware.js.map +1 -1
- package/dist/koa/index.cjs +137 -111
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.js +132 -106
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +137 -111
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.js +132 -106
- package/dist/koa/middleware.js.map +1 -1
- package/dist/nestjs/index.cjs +139 -112
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.js +134 -107
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +1 -1
package/dist/hono/middleware.js
CHANGED
|
@@ -191,6 +191,108 @@ import { unlinkSync as unlinkSync2, writeFileSync } from "fs";
|
|
|
191
191
|
import { tmpdir as tmpdir2 } from "os";
|
|
192
192
|
import { join as join2 } from "path";
|
|
193
193
|
|
|
194
|
+
// src/common/sentry.ts
|
|
195
|
+
var sentry;
|
|
196
|
+
(async () => {
|
|
197
|
+
try {
|
|
198
|
+
sentry = await import("@sentry/node");
|
|
199
|
+
} catch (e) {
|
|
200
|
+
}
|
|
201
|
+
})();
|
|
202
|
+
function getSentryEventId() {
|
|
203
|
+
if (sentry && sentry.lastEventId) {
|
|
204
|
+
return sentry.lastEventId();
|
|
205
|
+
}
|
|
206
|
+
return void 0;
|
|
207
|
+
}
|
|
208
|
+
__name(getSentryEventId, "getSentryEventId");
|
|
209
|
+
|
|
210
|
+
// src/common/serverErrorCounter.ts
|
|
211
|
+
import { createHash } from "crypto";
|
|
212
|
+
var MAX_MSG_LENGTH = 2048;
|
|
213
|
+
var MAX_STACKTRACE_LENGTH = 65536;
|
|
214
|
+
var _ServerErrorCounter = class _ServerErrorCounter {
|
|
215
|
+
errorCounts;
|
|
216
|
+
errorDetails;
|
|
217
|
+
sentryEventIds;
|
|
218
|
+
constructor() {
|
|
219
|
+
this.errorCounts = /* @__PURE__ */ new Map();
|
|
220
|
+
this.errorDetails = /* @__PURE__ */ new Map();
|
|
221
|
+
this.sentryEventIds = /* @__PURE__ */ new Map();
|
|
222
|
+
}
|
|
223
|
+
addServerError(serverError) {
|
|
224
|
+
const key = this.getKey(serverError);
|
|
225
|
+
if (!this.errorDetails.has(key)) {
|
|
226
|
+
this.errorDetails.set(key, serverError);
|
|
227
|
+
}
|
|
228
|
+
this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
|
|
229
|
+
const sentryEventId = getSentryEventId();
|
|
230
|
+
if (sentryEventId) {
|
|
231
|
+
this.sentryEventIds.set(key, sentryEventId);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
getAndResetServerErrors() {
|
|
235
|
+
const data = [];
|
|
236
|
+
this.errorCounts.forEach((count, key) => {
|
|
237
|
+
const serverError = this.errorDetails.get(key);
|
|
238
|
+
if (serverError) {
|
|
239
|
+
data.push({
|
|
240
|
+
consumer: serverError.consumer || null,
|
|
241
|
+
method: serverError.method,
|
|
242
|
+
path: serverError.path,
|
|
243
|
+
type: serverError.type,
|
|
244
|
+
msg: truncateExceptionMessage(serverError.msg),
|
|
245
|
+
traceback: truncateExceptionStackTrace(serverError.traceback),
|
|
246
|
+
sentry_event_id: this.sentryEventIds.get(key) || null,
|
|
247
|
+
error_count: count
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
this.errorCounts.clear();
|
|
252
|
+
this.errorDetails.clear();
|
|
253
|
+
return data;
|
|
254
|
+
}
|
|
255
|
+
getKey(serverError) {
|
|
256
|
+
const hashInput = [
|
|
257
|
+
serverError.consumer || "",
|
|
258
|
+
serverError.method.toUpperCase(),
|
|
259
|
+
serverError.path,
|
|
260
|
+
serverError.type,
|
|
261
|
+
serverError.msg.trim(),
|
|
262
|
+
serverError.traceback.trim()
|
|
263
|
+
].join("|");
|
|
264
|
+
return createHash("md5").update(hashInput).digest("hex");
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
__name(_ServerErrorCounter, "ServerErrorCounter");
|
|
268
|
+
var ServerErrorCounter = _ServerErrorCounter;
|
|
269
|
+
function truncateExceptionMessage(msg) {
|
|
270
|
+
if (msg.length <= MAX_MSG_LENGTH) {
|
|
271
|
+
return msg;
|
|
272
|
+
}
|
|
273
|
+
const suffix = "... (truncated)";
|
|
274
|
+
const cutoff = MAX_MSG_LENGTH - suffix.length;
|
|
275
|
+
return msg.substring(0, cutoff) + suffix;
|
|
276
|
+
}
|
|
277
|
+
__name(truncateExceptionMessage, "truncateExceptionMessage");
|
|
278
|
+
function truncateExceptionStackTrace(stack) {
|
|
279
|
+
const suffix = "... (truncated) ...";
|
|
280
|
+
const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
|
|
281
|
+
const lines = stack.trim().split("\n");
|
|
282
|
+
const truncatedLines = [];
|
|
283
|
+
let length = 0;
|
|
284
|
+
for (const line of lines) {
|
|
285
|
+
if (length + line.length + 1 > cutoff) {
|
|
286
|
+
truncatedLines.push(suffix);
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
truncatedLines.push(line);
|
|
290
|
+
length += line.length + 1;
|
|
291
|
+
}
|
|
292
|
+
return truncatedLines.join("\n");
|
|
293
|
+
}
|
|
294
|
+
__name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
|
|
295
|
+
|
|
194
296
|
// src/common/tempGzipFile.ts
|
|
195
297
|
import { Buffer as Buffer2 } from "buffer";
|
|
196
298
|
import { randomUUID } from "crypto";
|
|
@@ -213,9 +315,9 @@ var _TempGzipFile = class _TempGzipFile {
|
|
|
213
315
|
this.writeStream.once("ready", resolve);
|
|
214
316
|
this.writeStream.once("error", reject);
|
|
215
317
|
});
|
|
216
|
-
this.closedPromise = new Promise((resolve) => {
|
|
318
|
+
this.closedPromise = new Promise((resolve, reject) => {
|
|
217
319
|
this.writeStream.once("close", resolve);
|
|
218
|
-
this.writeStream.once("error",
|
|
320
|
+
this.writeStream.once("error", reject);
|
|
219
321
|
});
|
|
220
322
|
this.gzip = createGzip();
|
|
221
323
|
this.gzip.pipe(this.writeStream);
|
|
@@ -313,6 +415,7 @@ var DEFAULT_CONFIG = {
|
|
|
313
415
|
logRequestBody: false,
|
|
314
416
|
logResponseHeaders: true,
|
|
315
417
|
logResponseBody: false,
|
|
418
|
+
logException: true,
|
|
316
419
|
maskQueryParams: [],
|
|
317
420
|
maskHeaders: [],
|
|
318
421
|
excludePaths: []
|
|
@@ -365,7 +468,10 @@ var _RequestLogger = class _RequestLogger {
|
|
|
365
468
|
hasSupportedContentType(headers) {
|
|
366
469
|
var _a2;
|
|
367
470
|
const contentType = (_a2 = headers.find(([k]) => k.toLowerCase() === "content-type")) == null ? void 0 : _a2[1];
|
|
368
|
-
return
|
|
471
|
+
return this.isSupportedContentType(contentType);
|
|
472
|
+
}
|
|
473
|
+
isSupportedContentType(contentType) {
|
|
474
|
+
return typeof contentType === "string" && ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t));
|
|
369
475
|
}
|
|
370
476
|
maskQueryParams(search) {
|
|
371
477
|
const params = new URLSearchParams(search);
|
|
@@ -382,7 +488,7 @@ var _RequestLogger = class _RequestLogger {
|
|
|
382
488
|
this.shouldMaskHeader(k) ? MASKED : v
|
|
383
489
|
]);
|
|
384
490
|
}
|
|
385
|
-
logRequest(request, response) {
|
|
491
|
+
logRequest(request, response, error) {
|
|
386
492
|
var _a2, _b, _c;
|
|
387
493
|
if (!this.enabled || this.suspendUntil !== null) return;
|
|
388
494
|
const url = new URL(request.url);
|
|
@@ -393,8 +499,6 @@ var _RequestLogger = class _RequestLogger {
|
|
|
393
499
|
}
|
|
394
500
|
url.search = this.config.logQueryParams ? this.maskQueryParams(url.search) : "";
|
|
395
501
|
request.url = url.toString();
|
|
396
|
-
request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
|
|
397
|
-
response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
|
|
398
502
|
if (!this.config.logRequestBody || !this.hasSupportedContentType(request.headers)) {
|
|
399
503
|
request.body = void 0;
|
|
400
504
|
} else if (request.body) {
|
|
@@ -427,10 +531,18 @@ var _RequestLogger = class _RequestLogger {
|
|
|
427
531
|
}
|
|
428
532
|
}
|
|
429
533
|
}
|
|
534
|
+
request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
|
|
535
|
+
response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
|
|
430
536
|
const item = {
|
|
431
537
|
uuid: randomUUID2(),
|
|
432
538
|
request: skipEmptyValues(request),
|
|
433
|
-
response: skipEmptyValues(response)
|
|
539
|
+
response: skipEmptyValues(response),
|
|
540
|
+
exception: error && this.config.logException ? {
|
|
541
|
+
type: error.name,
|
|
542
|
+
message: truncateExceptionMessage(error.message),
|
|
543
|
+
stacktrace: truncateExceptionStackTrace(error.stack || ""),
|
|
544
|
+
sentryEventId: getSentryEventId()
|
|
545
|
+
} : null
|
|
434
546
|
};
|
|
435
547
|
[
|
|
436
548
|
item.request.body,
|
|
@@ -560,104 +672,6 @@ function checkWritableFs() {
|
|
|
560
672
|
}
|
|
561
673
|
__name(checkWritableFs, "checkWritableFs");
|
|
562
674
|
|
|
563
|
-
// src/common/serverErrorCounter.ts
|
|
564
|
-
import { createHash } from "crypto";
|
|
565
|
-
var MAX_MSG_LENGTH = 2048;
|
|
566
|
-
var MAX_STACKTRACE_LENGTH = 65536;
|
|
567
|
-
var _ServerErrorCounter = class _ServerErrorCounter {
|
|
568
|
-
errorCounts;
|
|
569
|
-
errorDetails;
|
|
570
|
-
sentryEventIds;
|
|
571
|
-
sentry;
|
|
572
|
-
constructor() {
|
|
573
|
-
this.errorCounts = /* @__PURE__ */ new Map();
|
|
574
|
-
this.errorDetails = /* @__PURE__ */ new Map();
|
|
575
|
-
this.sentryEventIds = /* @__PURE__ */ new Map();
|
|
576
|
-
this.tryImportSentry();
|
|
577
|
-
}
|
|
578
|
-
addServerError(serverError) {
|
|
579
|
-
const key = this.getKey(serverError);
|
|
580
|
-
if (!this.errorDetails.has(key)) {
|
|
581
|
-
this.errorDetails.set(key, serverError);
|
|
582
|
-
}
|
|
583
|
-
this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
|
|
584
|
-
this.captureSentryEventId(key);
|
|
585
|
-
}
|
|
586
|
-
getAndResetServerErrors() {
|
|
587
|
-
const data = [];
|
|
588
|
-
this.errorCounts.forEach((count, key) => {
|
|
589
|
-
const serverError = this.errorDetails.get(key);
|
|
590
|
-
if (serverError) {
|
|
591
|
-
data.push({
|
|
592
|
-
consumer: serverError.consumer || null,
|
|
593
|
-
method: serverError.method,
|
|
594
|
-
path: serverError.path,
|
|
595
|
-
type: serverError.type,
|
|
596
|
-
msg: this.getTruncatedMessage(serverError.msg),
|
|
597
|
-
traceback: this.getTruncatedStack(serverError.traceback),
|
|
598
|
-
sentry_event_id: this.sentryEventIds.get(key) || null,
|
|
599
|
-
error_count: count
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
});
|
|
603
|
-
this.errorCounts.clear();
|
|
604
|
-
this.errorDetails.clear();
|
|
605
|
-
return data;
|
|
606
|
-
}
|
|
607
|
-
getKey(serverError) {
|
|
608
|
-
const hashInput = [
|
|
609
|
-
serverError.consumer || "",
|
|
610
|
-
serverError.method.toUpperCase(),
|
|
611
|
-
serverError.path,
|
|
612
|
-
serverError.type,
|
|
613
|
-
serverError.msg.trim(),
|
|
614
|
-
serverError.traceback.trim()
|
|
615
|
-
].join("|");
|
|
616
|
-
return createHash("md5").update(hashInput).digest("hex");
|
|
617
|
-
}
|
|
618
|
-
getTruncatedMessage(msg) {
|
|
619
|
-
msg = msg.trim();
|
|
620
|
-
if (msg.length <= MAX_MSG_LENGTH) {
|
|
621
|
-
return msg;
|
|
622
|
-
}
|
|
623
|
-
const suffix = "... (truncated)";
|
|
624
|
-
const cutoff = MAX_MSG_LENGTH - suffix.length;
|
|
625
|
-
return msg.substring(0, cutoff) + suffix;
|
|
626
|
-
}
|
|
627
|
-
getTruncatedStack(stack) {
|
|
628
|
-
const suffix = "... (truncated) ...";
|
|
629
|
-
const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
|
|
630
|
-
const lines = stack.trim().split("\n");
|
|
631
|
-
const truncatedLines = [];
|
|
632
|
-
let length = 0;
|
|
633
|
-
for (const line of lines) {
|
|
634
|
-
if (length + line.length + 1 > cutoff) {
|
|
635
|
-
truncatedLines.push(suffix);
|
|
636
|
-
break;
|
|
637
|
-
}
|
|
638
|
-
truncatedLines.push(line);
|
|
639
|
-
length += line.length + 1;
|
|
640
|
-
}
|
|
641
|
-
return truncatedLines.join("\n");
|
|
642
|
-
}
|
|
643
|
-
captureSentryEventId(serverErrorKey) {
|
|
644
|
-
if (this.sentry && this.sentry.lastEventId) {
|
|
645
|
-
const eventId = this.sentry.lastEventId();
|
|
646
|
-
if (eventId) {
|
|
647
|
-
this.sentryEventIds.set(serverErrorKey, eventId);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
async tryImportSentry() {
|
|
652
|
-
try {
|
|
653
|
-
this.sentry = await import("@sentry/node");
|
|
654
|
-
} catch (e) {
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
};
|
|
658
|
-
__name(_ServerErrorCounter, "ServerErrorCounter");
|
|
659
|
-
var ServerErrorCounter = _ServerErrorCounter;
|
|
660
|
-
|
|
661
675
|
// src/common/validationErrorCounter.ts
|
|
662
676
|
import { createHash as createHash2 } from "crypto";
|
|
663
677
|
var _ValidationErrorCounter = class _ValidationErrorCounter {
|
|
@@ -731,6 +745,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
731
745
|
syncIntervalId;
|
|
732
746
|
startupData;
|
|
733
747
|
startupDataSent = false;
|
|
748
|
+
enabled = true;
|
|
734
749
|
requestCounter;
|
|
735
750
|
requestLogger;
|
|
736
751
|
validationErrorCounter;
|
|
@@ -767,12 +782,16 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
767
782
|
}
|
|
768
783
|
return _ApitallyClient.instance;
|
|
769
784
|
}
|
|
785
|
+
isEnabled() {
|
|
786
|
+
return this.enabled;
|
|
787
|
+
}
|
|
770
788
|
static async shutdown() {
|
|
771
789
|
if (_ApitallyClient.instance) {
|
|
772
790
|
await _ApitallyClient.instance.handleShutdown();
|
|
773
791
|
}
|
|
774
792
|
}
|
|
775
793
|
async handleShutdown() {
|
|
794
|
+
this.enabled = false;
|
|
776
795
|
this.stopSync();
|
|
777
796
|
await this.sendSyncData();
|
|
778
797
|
await this.sendLogData();
|
|
@@ -956,6 +975,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
956
975
|
if (error instanceof HTTPError) {
|
|
957
976
|
if (error.response.status === 404) {
|
|
958
977
|
this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);
|
|
978
|
+
this.enabled = false;
|
|
959
979
|
this.stopSync();
|
|
960
980
|
return true;
|
|
961
981
|
}
|
|
@@ -1003,6 +1023,10 @@ var useApitally = /* @__PURE__ */ __name((app, config) => {
|
|
|
1003
1023
|
}, "useApitally");
|
|
1004
1024
|
var getMiddleware = /* @__PURE__ */ __name((client) => {
|
|
1005
1025
|
return async (c, next) => {
|
|
1026
|
+
if (!client.isEnabled()) {
|
|
1027
|
+
await next();
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1006
1030
|
const startTime = performance.now();
|
|
1007
1031
|
await next();
|
|
1008
1032
|
let response;
|
|
@@ -1048,10 +1072,11 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
|
|
|
1048
1072
|
let requestBody;
|
|
1049
1073
|
let responseBody;
|
|
1050
1074
|
let newResponse2 = response;
|
|
1075
|
+
const responseContentType = c.res.headers.get("content-type");
|
|
1051
1076
|
if (client.requestLogger.config.logRequestBody) {
|
|
1052
1077
|
requestBody = Buffer.from(await c.req.arrayBuffer());
|
|
1053
1078
|
}
|
|
1054
|
-
if (client.requestLogger.config.logResponseBody) {
|
|
1079
|
+
if (client.requestLogger.config.logResponseBody && client.requestLogger.isSupportedContentType(responseContentType)) {
|
|
1055
1080
|
[responseBody, newResponse2] = await getResponseBody(response);
|
|
1056
1081
|
response = newResponse2;
|
|
1057
1082
|
}
|
|
@@ -1070,7 +1095,7 @@ var getMiddleware = /* @__PURE__ */ __name((client) => {
|
|
|
1070
1095
|
headers: convertHeaders(c.res.headers),
|
|
1071
1096
|
size: responseSize,
|
|
1072
1097
|
body: responseBody
|
|
1073
|
-
});
|
|
1098
|
+
}, c.error);
|
|
1074
1099
|
}
|
|
1075
1100
|
c.res = response;
|
|
1076
1101
|
};
|