apitally 0.10.0 → 0.11.1
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 +1 -2
- package/dist/common/client.cjs +408 -12
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.d.cts +8 -1
- package/dist/common/client.d.ts +8 -1
- package/dist/common/client.js +404 -8
- package/dist/common/client.js.map +1 -1
- package/dist/common/consumerRegistry.d.cts +4 -0
- package/dist/common/consumerRegistry.d.ts +4 -0
- package/dist/common/requestCounter.d.cts +4 -0
- package/dist/common/requestCounter.d.ts +4 -0
- package/dist/common/requestLogger.cjs +429 -0
- package/dist/common/requestLogger.cjs.map +1 -0
- package/dist/common/requestLogger.d.cts +64 -0
- package/dist/common/requestLogger.d.ts +64 -0
- package/dist/common/requestLogger.js +405 -0
- package/dist/common/requestLogger.js.map +1 -0
- package/dist/common/serverErrorCounter.d.cts +4 -0
- package/dist/common/serverErrorCounter.d.ts +4 -0
- package/dist/common/tempGzipFile.cjs +93 -0
- package/dist/common/tempGzipFile.cjs.map +1 -0
- package/dist/common/tempGzipFile.d.cts +17 -0
- package/dist/common/tempGzipFile.d.ts +17 -0
- package/dist/common/tempGzipFile.js +74 -0
- package/dist/common/tempGzipFile.js.map +1 -0
- package/dist/common/types.cjs.map +1 -1
- package/dist/common/types.d.cts +5 -0
- package/dist/common/types.d.ts +5 -0
- package/dist/common/validationErrorCounter.d.cts +4 -0
- package/dist/common/validationErrorCounter.d.ts +4 -0
- package/dist/express/index.cjs +510 -34
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.d.cts +4 -0
- package/dist/express/index.d.ts +4 -0
- package/dist/express/index.js +506 -30
- package/dist/express/index.js.map +1 -1
- package/dist/express/middleware.cjs +510 -34
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.d.cts +4 -0
- package/dist/express/middleware.d.ts +4 -0
- package/dist/express/middleware.js +506 -30
- package/dist/express/middleware.js.map +1 -1
- package/dist/fastify/index.cjs +501 -27
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.d.cts +4 -0
- package/dist/fastify/index.d.ts +4 -0
- package/dist/fastify/index.js +497 -23
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.cjs +501 -27
- package/dist/fastify/plugin.cjs.map +1 -1
- package/dist/fastify/plugin.d.cts +4 -0
- package/dist/fastify/plugin.d.ts +4 -0
- package/dist/fastify/plugin.js +497 -23
- package/dist/fastify/plugin.js.map +1 -1
- package/dist/hono/index.cjs +470 -15
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.d.cts +4 -0
- package/dist/hono/index.d.ts +4 -0
- package/dist/hono/index.js +466 -11
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.cjs +470 -15
- package/dist/hono/middleware.cjs.map +1 -1
- package/dist/hono/middleware.d.cts +4 -0
- package/dist/hono/middleware.d.ts +4 -0
- package/dist/hono/middleware.js +466 -11
- package/dist/hono/middleware.js.map +1 -1
- package/dist/koa/index.cjs +485 -15
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.d.cts +4 -0
- package/dist/koa/index.d.ts +4 -0
- package/dist/koa/index.js +481 -11
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.cjs +485 -15
- package/dist/koa/middleware.cjs.map +1 -1
- package/dist/koa/middleware.d.cts +4 -0
- package/dist/koa/middleware.d.ts +4 -0
- package/dist/koa/middleware.js +481 -11
- package/dist/koa/middleware.js.map +1 -1
- package/dist/nestjs/index.cjs +510 -34
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +4 -0
- package/dist/nestjs/index.d.ts +4 -0
- package/dist/nestjs/index.js +506 -30
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -93,9 +93,8 @@ const { useApitally } = require("apitally/nestjs");
|
|
|
93
93
|
const { AppModule } = require("./app.module");
|
|
94
94
|
|
|
95
95
|
const app = await NestFactory.create(AppModule);
|
|
96
|
-
const expressInstance = app.getHttpAdapter().getInstance();
|
|
97
96
|
|
|
98
|
-
useApitally(
|
|
97
|
+
useApitally(app, {
|
|
99
98
|
clientId: "your-client-id",
|
|
100
99
|
env: "dev", // or "prod" etc.
|
|
101
100
|
});
|
package/dist/common/client.cjs
CHANGED
|
@@ -36,7 +36,7 @@ __export(client_exports, {
|
|
|
36
36
|
ApitallyClient: () => ApitallyClient
|
|
37
37
|
});
|
|
38
38
|
module.exports = __toCommonJS(client_exports);
|
|
39
|
-
var
|
|
39
|
+
var import_crypto5 = require("crypto");
|
|
40
40
|
var import_fetch_retry = __toESM(require("fetch-retry"), 1);
|
|
41
41
|
|
|
42
42
|
// src/common/consumerRegistry.ts
|
|
@@ -191,8 +191,350 @@ var _RequestCounter = class _RequestCounter {
|
|
|
191
191
|
__name(_RequestCounter, "RequestCounter");
|
|
192
192
|
var RequestCounter = _RequestCounter;
|
|
193
193
|
|
|
194
|
-
// src/common/
|
|
194
|
+
// src/common/requestLogger.ts
|
|
195
|
+
var import_buffer2 = require("buffer");
|
|
196
|
+
var import_crypto2 = require("crypto");
|
|
197
|
+
var import_fs2 = require("fs");
|
|
198
|
+
var import_os2 = require("os");
|
|
199
|
+
var import_path2 = require("path");
|
|
200
|
+
|
|
201
|
+
// src/common/tempGzipFile.ts
|
|
202
|
+
var import_buffer = require("buffer");
|
|
195
203
|
var import_crypto = require("crypto");
|
|
204
|
+
var import_fs = require("fs");
|
|
205
|
+
var import_os = require("os");
|
|
206
|
+
var import_path = require("path");
|
|
207
|
+
var import_zlib = require("zlib");
|
|
208
|
+
var _TempGzipFile = class _TempGzipFile {
|
|
209
|
+
uuid;
|
|
210
|
+
filePath;
|
|
211
|
+
gzip;
|
|
212
|
+
writeStream;
|
|
213
|
+
readyPromise;
|
|
214
|
+
constructor() {
|
|
215
|
+
this.uuid = (0, import_crypto.randomUUID)();
|
|
216
|
+
this.filePath = (0, import_path.join)((0, import_os.tmpdir)(), `apitally-${this.uuid}.gz`);
|
|
217
|
+
this.writeStream = (0, import_fs.createWriteStream)(this.filePath);
|
|
218
|
+
this.readyPromise = new Promise((resolve, reject) => {
|
|
219
|
+
this.writeStream.once("ready", resolve);
|
|
220
|
+
this.writeStream.once("error", reject);
|
|
221
|
+
});
|
|
222
|
+
this.gzip = (0, import_zlib.createGzip)();
|
|
223
|
+
this.gzip.pipe(this.writeStream);
|
|
224
|
+
}
|
|
225
|
+
get size() {
|
|
226
|
+
return this.writeStream.bytesWritten;
|
|
227
|
+
}
|
|
228
|
+
async writeLine(data) {
|
|
229
|
+
await this.readyPromise;
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
231
|
+
this.gzip.write(import_buffer.Buffer.concat([
|
|
232
|
+
data,
|
|
233
|
+
import_buffer.Buffer.from("\n")
|
|
234
|
+
]), (error) => {
|
|
235
|
+
if (error) {
|
|
236
|
+
reject(error);
|
|
237
|
+
} else {
|
|
238
|
+
resolve();
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async getContent() {
|
|
244
|
+
return new Promise((resolve, reject) => {
|
|
245
|
+
(0, import_fs.readFile)(this.filePath, (error, data) => {
|
|
246
|
+
if (error) {
|
|
247
|
+
reject(error);
|
|
248
|
+
} else {
|
|
249
|
+
resolve(data);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
async close() {
|
|
255
|
+
return new Promise((resolve) => {
|
|
256
|
+
this.gzip.end(() => {
|
|
257
|
+
resolve();
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
async delete() {
|
|
262
|
+
await this.close();
|
|
263
|
+
(0, import_fs.unlinkSync)(this.filePath);
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
__name(_TempGzipFile, "TempGzipFile");
|
|
267
|
+
var TempGzipFile = _TempGzipFile;
|
|
268
|
+
|
|
269
|
+
// src/common/requestLogger.ts
|
|
270
|
+
var MAX_BODY_SIZE = 5e4;
|
|
271
|
+
var MAX_FILE_SIZE = 1e6;
|
|
272
|
+
var MAX_FILES = 50;
|
|
273
|
+
var MAX_PENDING_WRITES = 100;
|
|
274
|
+
var BODY_TOO_LARGE = import_buffer2.Buffer.from("<body too large>");
|
|
275
|
+
var BODY_MASKED = import_buffer2.Buffer.from("<masked>");
|
|
276
|
+
var MASKED = "******";
|
|
277
|
+
var ALLOWED_CONTENT_TYPES = [
|
|
278
|
+
"application/json",
|
|
279
|
+
"text/plain"
|
|
280
|
+
];
|
|
281
|
+
var EXCLUDE_PATH_PATTERNS = [
|
|
282
|
+
/\/_?healthz?$/i,
|
|
283
|
+
/\/_?health[_-]?checks?$/i,
|
|
284
|
+
/\/_?heart[_-]?beats?$/i,
|
|
285
|
+
/\/ping$/i,
|
|
286
|
+
/\/ready$/i,
|
|
287
|
+
/\/live$/i
|
|
288
|
+
];
|
|
289
|
+
var EXCLUDE_USER_AGENT_PATTERNS = [
|
|
290
|
+
/health[-_ ]?check/i,
|
|
291
|
+
/microsoft-azure-application-lb/i,
|
|
292
|
+
/googlehc/i,
|
|
293
|
+
/kube-probe/i
|
|
294
|
+
];
|
|
295
|
+
var MASK_QUERY_PARAM_PATTERNS = [
|
|
296
|
+
/auth/i,
|
|
297
|
+
/api-?key/i,
|
|
298
|
+
/secret/i,
|
|
299
|
+
/token/i,
|
|
300
|
+
/password/i,
|
|
301
|
+
/pwd/i
|
|
302
|
+
];
|
|
303
|
+
var MASK_HEADER_PATTERNS = [
|
|
304
|
+
/auth/i,
|
|
305
|
+
/api-?key/i,
|
|
306
|
+
/secret/i,
|
|
307
|
+
/token/i,
|
|
308
|
+
/cookie/i
|
|
309
|
+
];
|
|
310
|
+
var DEFAULT_CONFIG = {
|
|
311
|
+
enabled: false,
|
|
312
|
+
logQueryParams: true,
|
|
313
|
+
logRequestHeaders: false,
|
|
314
|
+
logRequestBody: false,
|
|
315
|
+
logResponseHeaders: true,
|
|
316
|
+
logResponseBody: false,
|
|
317
|
+
maskQueryParams: [],
|
|
318
|
+
maskHeaders: [],
|
|
319
|
+
excludePaths: []
|
|
320
|
+
};
|
|
321
|
+
var _RequestLogger = class _RequestLogger {
|
|
322
|
+
config;
|
|
323
|
+
enabled;
|
|
324
|
+
suspendUntil = null;
|
|
325
|
+
pendingWrites = [];
|
|
326
|
+
currentFile = null;
|
|
327
|
+
files = [];
|
|
328
|
+
maintainIntervalId;
|
|
329
|
+
constructor(config) {
|
|
330
|
+
this.config = {
|
|
331
|
+
...DEFAULT_CONFIG,
|
|
332
|
+
...config
|
|
333
|
+
};
|
|
334
|
+
this.enabled = this.config.enabled && checkWritableFs();
|
|
335
|
+
if (this.enabled) {
|
|
336
|
+
this.maintainIntervalId = setInterval(() => {
|
|
337
|
+
this.maintain();
|
|
338
|
+
}, 1e3);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
shouldExcludePath(urlPath) {
|
|
342
|
+
const patterns = [
|
|
343
|
+
...this.config.excludePaths,
|
|
344
|
+
...EXCLUDE_PATH_PATTERNS
|
|
345
|
+
];
|
|
346
|
+
return matchPatterns(urlPath, patterns);
|
|
347
|
+
}
|
|
348
|
+
shouldExcludeUserAgent(userAgent) {
|
|
349
|
+
return userAgent ? matchPatterns(userAgent, EXCLUDE_USER_AGENT_PATTERNS) : false;
|
|
350
|
+
}
|
|
351
|
+
shouldMaskQueryParam(name) {
|
|
352
|
+
const patterns = [
|
|
353
|
+
...this.config.maskQueryParams,
|
|
354
|
+
...MASK_QUERY_PARAM_PATTERNS
|
|
355
|
+
];
|
|
356
|
+
return matchPatterns(name, patterns);
|
|
357
|
+
}
|
|
358
|
+
shouldMaskHeader(name) {
|
|
359
|
+
const patterns = [
|
|
360
|
+
...this.config.maskHeaders,
|
|
361
|
+
...MASK_HEADER_PATTERNS
|
|
362
|
+
];
|
|
363
|
+
return matchPatterns(name, patterns);
|
|
364
|
+
}
|
|
365
|
+
hasSupportedContentType(headers) {
|
|
366
|
+
var _a2;
|
|
367
|
+
const contentType = (_a2 = headers.find(([k]) => k.toLowerCase() === "content-type")) == null ? void 0 : _a2[1];
|
|
368
|
+
return contentType !== void 0 && ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t));
|
|
369
|
+
}
|
|
370
|
+
maskQueryParams(search) {
|
|
371
|
+
const params = new URLSearchParams(search);
|
|
372
|
+
for (const [key] of params) {
|
|
373
|
+
if (this.shouldMaskQueryParam(key)) {
|
|
374
|
+
params.set(key, MASKED);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return params.toString();
|
|
378
|
+
}
|
|
379
|
+
maskHeaders(headers) {
|
|
380
|
+
return headers.map(([k, v]) => [
|
|
381
|
+
k,
|
|
382
|
+
this.shouldMaskHeader(k) ? MASKED : v
|
|
383
|
+
]);
|
|
384
|
+
}
|
|
385
|
+
logRequest(request, response) {
|
|
386
|
+
var _a2, _b, _c;
|
|
387
|
+
if (!this.enabled || this.suspendUntil !== null) return;
|
|
388
|
+
const url = new URL(request.url);
|
|
389
|
+
const path = request.path ?? url.pathname;
|
|
390
|
+
const userAgent = (_a2 = request.headers.find(([k]) => k.toLowerCase() === "user-agent")) == null ? void 0 : _a2[1];
|
|
391
|
+
if (this.shouldExcludePath(path) || this.shouldExcludeUserAgent(userAgent) || (((_c = (_b = this.config).excludeCallback) == null ? void 0 : _c.call(_b, request, response)) ?? false)) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
url.search = this.config.logQueryParams ? this.maskQueryParams(url.search) : "";
|
|
395
|
+
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
|
+
if (!this.config.logRequestBody || !this.hasSupportedContentType(request.headers)) {
|
|
399
|
+
request.body = void 0;
|
|
400
|
+
} else if (request.body) {
|
|
401
|
+
if (request.body.length > MAX_BODY_SIZE) {
|
|
402
|
+
request.body = BODY_TOO_LARGE;
|
|
403
|
+
} else if (this.config.maskRequestBodyCallback) {
|
|
404
|
+
try {
|
|
405
|
+
request.body = this.config.maskRequestBodyCallback(request) ?? BODY_MASKED;
|
|
406
|
+
if (request.body.length > MAX_BODY_SIZE) {
|
|
407
|
+
request.body = BODY_TOO_LARGE;
|
|
408
|
+
}
|
|
409
|
+
} catch {
|
|
410
|
+
request.body = void 0;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (!this.config.logResponseBody || !this.hasSupportedContentType(response.headers)) {
|
|
415
|
+
response.body = void 0;
|
|
416
|
+
} else if (response.body) {
|
|
417
|
+
if (response.body.length > MAX_BODY_SIZE) {
|
|
418
|
+
response.body = BODY_TOO_LARGE;
|
|
419
|
+
} else if (this.config.maskResponseBodyCallback) {
|
|
420
|
+
try {
|
|
421
|
+
response.body = this.config.maskResponseBodyCallback(request, response) ?? BODY_MASKED;
|
|
422
|
+
if (response.body.length > MAX_BODY_SIZE) {
|
|
423
|
+
response.body = BODY_TOO_LARGE;
|
|
424
|
+
}
|
|
425
|
+
} catch {
|
|
426
|
+
response.body = void 0;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const item = {
|
|
431
|
+
uuid: (0, import_crypto2.randomUUID)(),
|
|
432
|
+
request: skipEmptyValues(request),
|
|
433
|
+
response: skipEmptyValues(response)
|
|
434
|
+
};
|
|
435
|
+
[
|
|
436
|
+
item.request.body,
|
|
437
|
+
item.response.body
|
|
438
|
+
].forEach((body) => {
|
|
439
|
+
if (body) {
|
|
440
|
+
body.toJSON = function() {
|
|
441
|
+
return this.toString("base64");
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
this.pendingWrites.push(JSON.stringify(item));
|
|
446
|
+
if (this.pendingWrites.length > MAX_PENDING_WRITES) {
|
|
447
|
+
this.pendingWrites.shift();
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async writeToFile() {
|
|
451
|
+
if (!this.enabled || this.pendingWrites.length === 0) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (!this.currentFile) {
|
|
455
|
+
this.currentFile = new TempGzipFile();
|
|
456
|
+
}
|
|
457
|
+
while (this.pendingWrites.length > 0) {
|
|
458
|
+
const item = this.pendingWrites.shift();
|
|
459
|
+
if (item) {
|
|
460
|
+
await this.currentFile.writeLine(import_buffer2.Buffer.from(item));
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
getFile() {
|
|
465
|
+
return this.files.shift();
|
|
466
|
+
}
|
|
467
|
+
retryFileLater(file) {
|
|
468
|
+
this.files.unshift(file);
|
|
469
|
+
}
|
|
470
|
+
async rotateFile() {
|
|
471
|
+
if (this.currentFile) {
|
|
472
|
+
await this.currentFile.close();
|
|
473
|
+
this.files.push(this.currentFile);
|
|
474
|
+
this.currentFile = null;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
async maintain() {
|
|
478
|
+
await this.writeToFile();
|
|
479
|
+
if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {
|
|
480
|
+
await this.rotateFile();
|
|
481
|
+
}
|
|
482
|
+
while (this.files.length > MAX_FILES) {
|
|
483
|
+
const file = this.files.shift();
|
|
484
|
+
file == null ? void 0 : file.delete();
|
|
485
|
+
}
|
|
486
|
+
if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {
|
|
487
|
+
this.suspendUntil = null;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
async clear() {
|
|
491
|
+
this.pendingWrites = [];
|
|
492
|
+
await this.rotateFile();
|
|
493
|
+
this.files.forEach((file) => {
|
|
494
|
+
file.delete();
|
|
495
|
+
});
|
|
496
|
+
this.files = [];
|
|
497
|
+
}
|
|
498
|
+
async close() {
|
|
499
|
+
this.enabled = false;
|
|
500
|
+
await this.clear();
|
|
501
|
+
if (this.maintainIntervalId) {
|
|
502
|
+
clearInterval(this.maintainIntervalId);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
__name(_RequestLogger, "RequestLogger");
|
|
507
|
+
var RequestLogger = _RequestLogger;
|
|
508
|
+
function matchPatterns(value, patterns) {
|
|
509
|
+
return patterns.some((pattern) => {
|
|
510
|
+
return pattern.test(value);
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
__name(matchPatterns, "matchPatterns");
|
|
514
|
+
function skipEmptyValues(data) {
|
|
515
|
+
return Object.fromEntries(Object.entries(data).filter(([_, v]) => {
|
|
516
|
+
if (v == null || Number.isNaN(v)) return false;
|
|
517
|
+
if (Array.isArray(v) || import_buffer2.Buffer.isBuffer(v) || typeof v === "string") {
|
|
518
|
+
return v.length > 0;
|
|
519
|
+
}
|
|
520
|
+
return true;
|
|
521
|
+
}));
|
|
522
|
+
}
|
|
523
|
+
__name(skipEmptyValues, "skipEmptyValues");
|
|
524
|
+
function checkWritableFs() {
|
|
525
|
+
try {
|
|
526
|
+
const testPath = (0, import_path2.join)((0, import_os2.tmpdir)(), `apitally-${(0, import_crypto2.randomUUID)()}`);
|
|
527
|
+
(0, import_fs2.writeFileSync)(testPath, "test");
|
|
528
|
+
(0, import_fs2.unlinkSync)(testPath);
|
|
529
|
+
return true;
|
|
530
|
+
} catch (error) {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
__name(checkWritableFs, "checkWritableFs");
|
|
535
|
+
|
|
536
|
+
// src/common/serverErrorCounter.ts
|
|
537
|
+
var import_crypto3 = require("crypto");
|
|
196
538
|
var MAX_MSG_LENGTH = 2048;
|
|
197
539
|
var MAX_STACKTRACE_LENGTH = 65536;
|
|
198
540
|
var _ServerErrorCounter = class _ServerErrorCounter {
|
|
@@ -244,7 +586,7 @@ var _ServerErrorCounter = class _ServerErrorCounter {
|
|
|
244
586
|
serverError.msg.trim(),
|
|
245
587
|
serverError.traceback.trim()
|
|
246
588
|
].join("|");
|
|
247
|
-
return (0,
|
|
589
|
+
return (0, import_crypto3.createHash)("md5").update(hashInput).digest("hex");
|
|
248
590
|
}
|
|
249
591
|
getTruncatedMessage(msg) {
|
|
250
592
|
msg = msg.trim();
|
|
@@ -290,7 +632,7 @@ __name(_ServerErrorCounter, "ServerErrorCounter");
|
|
|
290
632
|
var ServerErrorCounter = _ServerErrorCounter;
|
|
291
633
|
|
|
292
634
|
// src/common/validationErrorCounter.ts
|
|
293
|
-
var
|
|
635
|
+
var import_crypto4 = require("crypto");
|
|
294
636
|
var _ValidationErrorCounter = class _ValidationErrorCounter {
|
|
295
637
|
errorCounts;
|
|
296
638
|
errorDetails;
|
|
@@ -334,7 +676,7 @@ var _ValidationErrorCounter = class _ValidationErrorCounter {
|
|
|
334
676
|
validationError.msg.trim(),
|
|
335
677
|
validationError.type
|
|
336
678
|
].join("|");
|
|
337
|
-
return (0,
|
|
679
|
+
return (0, import_crypto4.createHash)("md5").update(hashInput).digest("hex");
|
|
338
680
|
}
|
|
339
681
|
};
|
|
340
682
|
__name(_ValidationErrorCounter, "ValidationErrorCounter");
|
|
@@ -363,11 +705,12 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
363
705
|
startupData;
|
|
364
706
|
startupDataSent = false;
|
|
365
707
|
requestCounter;
|
|
708
|
+
requestLogger;
|
|
366
709
|
validationErrorCounter;
|
|
367
710
|
serverErrorCounter;
|
|
368
711
|
consumerRegistry;
|
|
369
712
|
logger;
|
|
370
|
-
constructor({ clientId, env = "dev", logger }) {
|
|
713
|
+
constructor({ clientId, env = "dev", requestLoggingConfig, logger }) {
|
|
371
714
|
if (_ApitallyClient.instance) {
|
|
372
715
|
throw new Error("Apitally client is already initialized");
|
|
373
716
|
}
|
|
@@ -380,9 +723,10 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
380
723
|
_ApitallyClient.instance = this;
|
|
381
724
|
this.clientId = clientId;
|
|
382
725
|
this.env = env;
|
|
383
|
-
this.instanceUuid = (0,
|
|
726
|
+
this.instanceUuid = (0, import_crypto5.randomUUID)();
|
|
384
727
|
this.syncDataQueue = [];
|
|
385
728
|
this.requestCounter = new RequestCounter();
|
|
729
|
+
this.requestLogger = new RequestLogger(requestLoggingConfig);
|
|
386
730
|
this.validationErrorCounter = new ValidationErrorCounter();
|
|
387
731
|
this.serverErrorCounter = new ServerErrorCounter();
|
|
388
732
|
this.consumerRegistry = new ConsumerRegistry();
|
|
@@ -404,6 +748,8 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
404
748
|
async handleShutdown() {
|
|
405
749
|
this.stopSync();
|
|
406
750
|
await this.sendSyncData();
|
|
751
|
+
await this.sendLogData();
|
|
752
|
+
await this.requestLogger.close();
|
|
407
753
|
_ApitallyClient.instance = void 0;
|
|
408
754
|
}
|
|
409
755
|
getHubUrlPrefix() {
|
|
@@ -450,7 +796,8 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
450
796
|
async sync() {
|
|
451
797
|
try {
|
|
452
798
|
const promises = [
|
|
453
|
-
this.sendSyncData()
|
|
799
|
+
this.sendSyncData(),
|
|
800
|
+
this.sendLogData()
|
|
454
801
|
];
|
|
455
802
|
if (!this.startupDataSent) {
|
|
456
803
|
promises.push(this.sendStartupData());
|
|
@@ -478,7 +825,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
478
825
|
this.logger.debug("Sending startup data to Apitally Hub");
|
|
479
826
|
const payload = {
|
|
480
827
|
instance_uuid: this.instanceUuid,
|
|
481
|
-
message_uuid: (0,
|
|
828
|
+
message_uuid: (0, import_crypto5.randomUUID)(),
|
|
482
829
|
...this.startupData
|
|
483
830
|
};
|
|
484
831
|
try {
|
|
@@ -500,7 +847,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
500
847
|
const newPayload = {
|
|
501
848
|
time_offset: 0,
|
|
502
849
|
instance_uuid: this.instanceUuid,
|
|
503
|
-
message_uuid: (0,
|
|
850
|
+
message_uuid: (0, import_crypto5.randomUUID)(),
|
|
504
851
|
requests: this.requestCounter.getAndResetRequests(),
|
|
505
852
|
validation_errors: this.validationErrorCounter.getAndResetValidationErrors(),
|
|
506
853
|
server_errors: this.serverErrorCounter.getAndResetServerErrors(),
|
|
@@ -519,8 +866,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
519
866
|
const timeOffset = Date.now() - time;
|
|
520
867
|
if (timeOffset <= MAX_QUEUE_TIME) {
|
|
521
868
|
if (i > 0) {
|
|
522
|
-
|
|
523
|
-
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
869
|
+
await this.randomDelay();
|
|
524
870
|
}
|
|
525
871
|
payload.time_offset = timeOffset / 1e3;
|
|
526
872
|
await this.sendData("sync", payload);
|
|
@@ -539,6 +885,52 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
539
885
|
}
|
|
540
886
|
}
|
|
541
887
|
}
|
|
888
|
+
async sendLogData() {
|
|
889
|
+
this.logger.debug("Sending request log data to Apitally Hub");
|
|
890
|
+
await this.requestLogger.rotateFile();
|
|
891
|
+
const fetchWithRetry = (0, import_fetch_retry.default)(fetch, {
|
|
892
|
+
retries: 3,
|
|
893
|
+
retryDelay: 1e3,
|
|
894
|
+
retryOn: [
|
|
895
|
+
408,
|
|
896
|
+
429,
|
|
897
|
+
500,
|
|
898
|
+
502,
|
|
899
|
+
503,
|
|
900
|
+
504
|
|
901
|
+
]
|
|
902
|
+
});
|
|
903
|
+
let i = 0;
|
|
904
|
+
let logFile;
|
|
905
|
+
while (logFile = this.requestLogger.getFile()) {
|
|
906
|
+
if (i > 0) {
|
|
907
|
+
await this.randomDelay();
|
|
908
|
+
}
|
|
909
|
+
try {
|
|
910
|
+
const response = await fetchWithRetry(`${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`, {
|
|
911
|
+
method: "POST",
|
|
912
|
+
body: await logFile.getContent()
|
|
913
|
+
});
|
|
914
|
+
if (response.status === 402 && response.headers.has("Retry-After")) {
|
|
915
|
+
const retryAfter = parseInt(response.headers.get("Retry-After") ?? "0");
|
|
916
|
+
if (retryAfter > 0) {
|
|
917
|
+
this.requestLogger.suspendUntil = Date.now() + retryAfter * 1e3;
|
|
918
|
+
this.requestLogger.clear();
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
if (!response.ok) {
|
|
923
|
+
throw new HTTPError(response);
|
|
924
|
+
}
|
|
925
|
+
logFile.delete();
|
|
926
|
+
} catch (error) {
|
|
927
|
+
this.requestLogger.retryFileLater(logFile);
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
i++;
|
|
931
|
+
if (i >= 10) break;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
542
934
|
handleHubError(error) {
|
|
543
935
|
if (error instanceof HTTPError) {
|
|
544
936
|
if (error.response.status === 404) {
|
|
@@ -553,6 +945,10 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
553
945
|
}
|
|
554
946
|
return false;
|
|
555
947
|
}
|
|
948
|
+
async randomDelay() {
|
|
949
|
+
const delay = 100 + Math.random() * 200;
|
|
950
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
951
|
+
}
|
|
556
952
|
};
|
|
557
953
|
__name(_ApitallyClient, "ApitallyClient");
|
|
558
954
|
__publicField(_ApitallyClient, "instance");
|