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/dist/common/client.js
CHANGED
|
@@ -4,7 +4,7 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
|
|
6
6
|
// src/common/client.ts
|
|
7
|
-
import { randomUUID } from "crypto";
|
|
7
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
8
8
|
import fetchRetry from "fetch-retry";
|
|
9
9
|
|
|
10
10
|
// src/common/consumerRegistry.ts
|
|
@@ -159,6 +159,348 @@ var _RequestCounter = class _RequestCounter {
|
|
|
159
159
|
__name(_RequestCounter, "RequestCounter");
|
|
160
160
|
var RequestCounter = _RequestCounter;
|
|
161
161
|
|
|
162
|
+
// src/common/requestLogger.ts
|
|
163
|
+
import { Buffer as Buffer3 } from "buffer";
|
|
164
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
165
|
+
import { unlinkSync as unlinkSync2, writeFileSync } from "fs";
|
|
166
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
167
|
+
import { join as join2 } from "path";
|
|
168
|
+
|
|
169
|
+
// src/common/tempGzipFile.ts
|
|
170
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
171
|
+
import { randomUUID } from "crypto";
|
|
172
|
+
import { createWriteStream, readFile, unlinkSync } from "fs";
|
|
173
|
+
import { tmpdir } from "os";
|
|
174
|
+
import { join } from "path";
|
|
175
|
+
import { createGzip } from "zlib";
|
|
176
|
+
var _TempGzipFile = class _TempGzipFile {
|
|
177
|
+
uuid;
|
|
178
|
+
filePath;
|
|
179
|
+
gzip;
|
|
180
|
+
writeStream;
|
|
181
|
+
readyPromise;
|
|
182
|
+
constructor() {
|
|
183
|
+
this.uuid = randomUUID();
|
|
184
|
+
this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);
|
|
185
|
+
this.writeStream = createWriteStream(this.filePath);
|
|
186
|
+
this.readyPromise = new Promise((resolve, reject) => {
|
|
187
|
+
this.writeStream.once("ready", resolve);
|
|
188
|
+
this.writeStream.once("error", reject);
|
|
189
|
+
});
|
|
190
|
+
this.gzip = createGzip();
|
|
191
|
+
this.gzip.pipe(this.writeStream);
|
|
192
|
+
}
|
|
193
|
+
get size() {
|
|
194
|
+
return this.writeStream.bytesWritten;
|
|
195
|
+
}
|
|
196
|
+
async writeLine(data) {
|
|
197
|
+
await this.readyPromise;
|
|
198
|
+
return new Promise((resolve, reject) => {
|
|
199
|
+
this.gzip.write(Buffer2.concat([
|
|
200
|
+
data,
|
|
201
|
+
Buffer2.from("\n")
|
|
202
|
+
]), (error) => {
|
|
203
|
+
if (error) {
|
|
204
|
+
reject(error);
|
|
205
|
+
} else {
|
|
206
|
+
resolve();
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
async getContent() {
|
|
212
|
+
return new Promise((resolve, reject) => {
|
|
213
|
+
readFile(this.filePath, (error, data) => {
|
|
214
|
+
if (error) {
|
|
215
|
+
reject(error);
|
|
216
|
+
} else {
|
|
217
|
+
resolve(data);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
async close() {
|
|
223
|
+
return new Promise((resolve) => {
|
|
224
|
+
this.gzip.end(() => {
|
|
225
|
+
resolve();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
async delete() {
|
|
230
|
+
await this.close();
|
|
231
|
+
unlinkSync(this.filePath);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
__name(_TempGzipFile, "TempGzipFile");
|
|
235
|
+
var TempGzipFile = _TempGzipFile;
|
|
236
|
+
|
|
237
|
+
// src/common/requestLogger.ts
|
|
238
|
+
var MAX_BODY_SIZE = 5e4;
|
|
239
|
+
var MAX_FILE_SIZE = 1e6;
|
|
240
|
+
var MAX_FILES = 50;
|
|
241
|
+
var MAX_PENDING_WRITES = 100;
|
|
242
|
+
var BODY_TOO_LARGE = Buffer3.from("<body too large>");
|
|
243
|
+
var BODY_MASKED = Buffer3.from("<masked>");
|
|
244
|
+
var MASKED = "******";
|
|
245
|
+
var ALLOWED_CONTENT_TYPES = [
|
|
246
|
+
"application/json",
|
|
247
|
+
"text/plain"
|
|
248
|
+
];
|
|
249
|
+
var EXCLUDE_PATH_PATTERNS = [
|
|
250
|
+
/\/_?healthz?$/i,
|
|
251
|
+
/\/_?health[_-]?checks?$/i,
|
|
252
|
+
/\/_?heart[_-]?beats?$/i,
|
|
253
|
+
/\/ping$/i,
|
|
254
|
+
/\/ready$/i,
|
|
255
|
+
/\/live$/i
|
|
256
|
+
];
|
|
257
|
+
var EXCLUDE_USER_AGENT_PATTERNS = [
|
|
258
|
+
/health[-_ ]?check/i,
|
|
259
|
+
/microsoft-azure-application-lb/i,
|
|
260
|
+
/googlehc/i,
|
|
261
|
+
/kube-probe/i
|
|
262
|
+
];
|
|
263
|
+
var MASK_QUERY_PARAM_PATTERNS = [
|
|
264
|
+
/auth/i,
|
|
265
|
+
/api-?key/i,
|
|
266
|
+
/secret/i,
|
|
267
|
+
/token/i,
|
|
268
|
+
/password/i,
|
|
269
|
+
/pwd/i
|
|
270
|
+
];
|
|
271
|
+
var MASK_HEADER_PATTERNS = [
|
|
272
|
+
/auth/i,
|
|
273
|
+
/api-?key/i,
|
|
274
|
+
/secret/i,
|
|
275
|
+
/token/i,
|
|
276
|
+
/cookie/i
|
|
277
|
+
];
|
|
278
|
+
var DEFAULT_CONFIG = {
|
|
279
|
+
enabled: false,
|
|
280
|
+
logQueryParams: true,
|
|
281
|
+
logRequestHeaders: false,
|
|
282
|
+
logRequestBody: false,
|
|
283
|
+
logResponseHeaders: true,
|
|
284
|
+
logResponseBody: false,
|
|
285
|
+
maskQueryParams: [],
|
|
286
|
+
maskHeaders: [],
|
|
287
|
+
excludePaths: []
|
|
288
|
+
};
|
|
289
|
+
var _RequestLogger = class _RequestLogger {
|
|
290
|
+
config;
|
|
291
|
+
enabled;
|
|
292
|
+
suspendUntil = null;
|
|
293
|
+
pendingWrites = [];
|
|
294
|
+
currentFile = null;
|
|
295
|
+
files = [];
|
|
296
|
+
maintainIntervalId;
|
|
297
|
+
constructor(config) {
|
|
298
|
+
this.config = {
|
|
299
|
+
...DEFAULT_CONFIG,
|
|
300
|
+
...config
|
|
301
|
+
};
|
|
302
|
+
this.enabled = this.config.enabled && checkWritableFs();
|
|
303
|
+
if (this.enabled) {
|
|
304
|
+
this.maintainIntervalId = setInterval(() => {
|
|
305
|
+
this.maintain();
|
|
306
|
+
}, 1e3);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
shouldExcludePath(urlPath) {
|
|
310
|
+
const patterns = [
|
|
311
|
+
...this.config.excludePaths,
|
|
312
|
+
...EXCLUDE_PATH_PATTERNS
|
|
313
|
+
];
|
|
314
|
+
return matchPatterns(urlPath, patterns);
|
|
315
|
+
}
|
|
316
|
+
shouldExcludeUserAgent(userAgent) {
|
|
317
|
+
return userAgent ? matchPatterns(userAgent, EXCLUDE_USER_AGENT_PATTERNS) : false;
|
|
318
|
+
}
|
|
319
|
+
shouldMaskQueryParam(name) {
|
|
320
|
+
const patterns = [
|
|
321
|
+
...this.config.maskQueryParams,
|
|
322
|
+
...MASK_QUERY_PARAM_PATTERNS
|
|
323
|
+
];
|
|
324
|
+
return matchPatterns(name, patterns);
|
|
325
|
+
}
|
|
326
|
+
shouldMaskHeader(name) {
|
|
327
|
+
const patterns = [
|
|
328
|
+
...this.config.maskHeaders,
|
|
329
|
+
...MASK_HEADER_PATTERNS
|
|
330
|
+
];
|
|
331
|
+
return matchPatterns(name, patterns);
|
|
332
|
+
}
|
|
333
|
+
hasSupportedContentType(headers) {
|
|
334
|
+
var _a2;
|
|
335
|
+
const contentType = (_a2 = headers.find(([k]) => k.toLowerCase() === "content-type")) == null ? void 0 : _a2[1];
|
|
336
|
+
return contentType !== void 0 && ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t));
|
|
337
|
+
}
|
|
338
|
+
maskQueryParams(search) {
|
|
339
|
+
const params = new URLSearchParams(search);
|
|
340
|
+
for (const [key] of params) {
|
|
341
|
+
if (this.shouldMaskQueryParam(key)) {
|
|
342
|
+
params.set(key, MASKED);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return params.toString();
|
|
346
|
+
}
|
|
347
|
+
maskHeaders(headers) {
|
|
348
|
+
return headers.map(([k, v]) => [
|
|
349
|
+
k,
|
|
350
|
+
this.shouldMaskHeader(k) ? MASKED : v
|
|
351
|
+
]);
|
|
352
|
+
}
|
|
353
|
+
logRequest(request, response) {
|
|
354
|
+
var _a2, _b, _c;
|
|
355
|
+
if (!this.enabled || this.suspendUntil !== null) return;
|
|
356
|
+
const url = new URL(request.url);
|
|
357
|
+
const path = request.path ?? url.pathname;
|
|
358
|
+
const userAgent = (_a2 = request.headers.find(([k]) => k.toLowerCase() === "user-agent")) == null ? void 0 : _a2[1];
|
|
359
|
+
if (this.shouldExcludePath(path) || this.shouldExcludeUserAgent(userAgent) || (((_c = (_b = this.config).excludeCallback) == null ? void 0 : _c.call(_b, request, response)) ?? false)) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
url.search = this.config.logQueryParams ? this.maskQueryParams(url.search) : "";
|
|
363
|
+
request.url = url.toString();
|
|
364
|
+
request.headers = this.config.logRequestHeaders ? this.maskHeaders(request.headers) : [];
|
|
365
|
+
response.headers = this.config.logResponseHeaders ? this.maskHeaders(response.headers) : [];
|
|
366
|
+
if (!this.config.logRequestBody || !this.hasSupportedContentType(request.headers)) {
|
|
367
|
+
request.body = void 0;
|
|
368
|
+
} else if (request.body) {
|
|
369
|
+
if (request.body.length > MAX_BODY_SIZE) {
|
|
370
|
+
request.body = BODY_TOO_LARGE;
|
|
371
|
+
} else if (this.config.maskRequestBodyCallback) {
|
|
372
|
+
try {
|
|
373
|
+
request.body = this.config.maskRequestBodyCallback(request) ?? BODY_MASKED;
|
|
374
|
+
if (request.body.length > MAX_BODY_SIZE) {
|
|
375
|
+
request.body = BODY_TOO_LARGE;
|
|
376
|
+
}
|
|
377
|
+
} catch {
|
|
378
|
+
request.body = void 0;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (!this.config.logResponseBody || !this.hasSupportedContentType(response.headers)) {
|
|
383
|
+
response.body = void 0;
|
|
384
|
+
} else if (response.body) {
|
|
385
|
+
if (response.body.length > MAX_BODY_SIZE) {
|
|
386
|
+
response.body = BODY_TOO_LARGE;
|
|
387
|
+
} else if (this.config.maskResponseBodyCallback) {
|
|
388
|
+
try {
|
|
389
|
+
response.body = this.config.maskResponseBodyCallback(request, response) ?? BODY_MASKED;
|
|
390
|
+
if (response.body.length > MAX_BODY_SIZE) {
|
|
391
|
+
response.body = BODY_TOO_LARGE;
|
|
392
|
+
}
|
|
393
|
+
} catch {
|
|
394
|
+
response.body = void 0;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const item = {
|
|
399
|
+
uuid: randomUUID2(),
|
|
400
|
+
request: skipEmptyValues(request),
|
|
401
|
+
response: skipEmptyValues(response)
|
|
402
|
+
};
|
|
403
|
+
[
|
|
404
|
+
item.request.body,
|
|
405
|
+
item.response.body
|
|
406
|
+
].forEach((body) => {
|
|
407
|
+
if (body) {
|
|
408
|
+
body.toJSON = function() {
|
|
409
|
+
return this.toString("base64");
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
this.pendingWrites.push(JSON.stringify(item));
|
|
414
|
+
if (this.pendingWrites.length > MAX_PENDING_WRITES) {
|
|
415
|
+
this.pendingWrites.shift();
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
async writeToFile() {
|
|
419
|
+
if (!this.enabled || this.pendingWrites.length === 0) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
if (!this.currentFile) {
|
|
423
|
+
this.currentFile = new TempGzipFile();
|
|
424
|
+
}
|
|
425
|
+
while (this.pendingWrites.length > 0) {
|
|
426
|
+
const item = this.pendingWrites.shift();
|
|
427
|
+
if (item) {
|
|
428
|
+
await this.currentFile.writeLine(Buffer3.from(item));
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
getFile() {
|
|
433
|
+
return this.files.shift();
|
|
434
|
+
}
|
|
435
|
+
retryFileLater(file) {
|
|
436
|
+
this.files.unshift(file);
|
|
437
|
+
}
|
|
438
|
+
async rotateFile() {
|
|
439
|
+
if (this.currentFile) {
|
|
440
|
+
await this.currentFile.close();
|
|
441
|
+
this.files.push(this.currentFile);
|
|
442
|
+
this.currentFile = null;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
async maintain() {
|
|
446
|
+
await this.writeToFile();
|
|
447
|
+
if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {
|
|
448
|
+
await this.rotateFile();
|
|
449
|
+
}
|
|
450
|
+
while (this.files.length > MAX_FILES) {
|
|
451
|
+
const file = this.files.shift();
|
|
452
|
+
file == null ? void 0 : file.delete();
|
|
453
|
+
}
|
|
454
|
+
if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {
|
|
455
|
+
this.suspendUntil = null;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
async clear() {
|
|
459
|
+
this.pendingWrites = [];
|
|
460
|
+
await this.rotateFile();
|
|
461
|
+
this.files.forEach((file) => {
|
|
462
|
+
file.delete();
|
|
463
|
+
});
|
|
464
|
+
this.files = [];
|
|
465
|
+
}
|
|
466
|
+
async close() {
|
|
467
|
+
this.enabled = false;
|
|
468
|
+
await this.clear();
|
|
469
|
+
if (this.maintainIntervalId) {
|
|
470
|
+
clearInterval(this.maintainIntervalId);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
__name(_RequestLogger, "RequestLogger");
|
|
475
|
+
var RequestLogger = _RequestLogger;
|
|
476
|
+
function matchPatterns(value, patterns) {
|
|
477
|
+
return patterns.some((pattern) => {
|
|
478
|
+
return pattern.test(value);
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
__name(matchPatterns, "matchPatterns");
|
|
482
|
+
function skipEmptyValues(data) {
|
|
483
|
+
return Object.fromEntries(Object.entries(data).filter(([_, v]) => {
|
|
484
|
+
if (v == null || Number.isNaN(v)) return false;
|
|
485
|
+
if (Array.isArray(v) || Buffer3.isBuffer(v) || typeof v === "string") {
|
|
486
|
+
return v.length > 0;
|
|
487
|
+
}
|
|
488
|
+
return true;
|
|
489
|
+
}));
|
|
490
|
+
}
|
|
491
|
+
__name(skipEmptyValues, "skipEmptyValues");
|
|
492
|
+
function checkWritableFs() {
|
|
493
|
+
try {
|
|
494
|
+
const testPath = join2(tmpdir2(), `apitally-${randomUUID2()}`);
|
|
495
|
+
writeFileSync(testPath, "test");
|
|
496
|
+
unlinkSync2(testPath);
|
|
497
|
+
return true;
|
|
498
|
+
} catch (error) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
__name(checkWritableFs, "checkWritableFs");
|
|
503
|
+
|
|
162
504
|
// src/common/serverErrorCounter.ts
|
|
163
505
|
import { createHash } from "crypto";
|
|
164
506
|
var MAX_MSG_LENGTH = 2048;
|
|
@@ -331,11 +673,12 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
331
673
|
startupData;
|
|
332
674
|
startupDataSent = false;
|
|
333
675
|
requestCounter;
|
|
676
|
+
requestLogger;
|
|
334
677
|
validationErrorCounter;
|
|
335
678
|
serverErrorCounter;
|
|
336
679
|
consumerRegistry;
|
|
337
680
|
logger;
|
|
338
|
-
constructor({ clientId, env = "dev", logger }) {
|
|
681
|
+
constructor({ clientId, env = "dev", requestLoggingConfig, logger }) {
|
|
339
682
|
if (_ApitallyClient.instance) {
|
|
340
683
|
throw new Error("Apitally client is already initialized");
|
|
341
684
|
}
|
|
@@ -348,9 +691,10 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
348
691
|
_ApitallyClient.instance = this;
|
|
349
692
|
this.clientId = clientId;
|
|
350
693
|
this.env = env;
|
|
351
|
-
this.instanceUuid =
|
|
694
|
+
this.instanceUuid = randomUUID3();
|
|
352
695
|
this.syncDataQueue = [];
|
|
353
696
|
this.requestCounter = new RequestCounter();
|
|
697
|
+
this.requestLogger = new RequestLogger(requestLoggingConfig);
|
|
354
698
|
this.validationErrorCounter = new ValidationErrorCounter();
|
|
355
699
|
this.serverErrorCounter = new ServerErrorCounter();
|
|
356
700
|
this.consumerRegistry = new ConsumerRegistry();
|
|
@@ -372,6 +716,8 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
372
716
|
async handleShutdown() {
|
|
373
717
|
this.stopSync();
|
|
374
718
|
await this.sendSyncData();
|
|
719
|
+
await this.sendLogData();
|
|
720
|
+
await this.requestLogger.close();
|
|
375
721
|
_ApitallyClient.instance = void 0;
|
|
376
722
|
}
|
|
377
723
|
getHubUrlPrefix() {
|
|
@@ -418,7 +764,8 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
418
764
|
async sync() {
|
|
419
765
|
try {
|
|
420
766
|
const promises = [
|
|
421
|
-
this.sendSyncData()
|
|
767
|
+
this.sendSyncData(),
|
|
768
|
+
this.sendLogData()
|
|
422
769
|
];
|
|
423
770
|
if (!this.startupDataSent) {
|
|
424
771
|
promises.push(this.sendStartupData());
|
|
@@ -446,7 +793,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
446
793
|
this.logger.debug("Sending startup data to Apitally Hub");
|
|
447
794
|
const payload = {
|
|
448
795
|
instance_uuid: this.instanceUuid,
|
|
449
|
-
message_uuid:
|
|
796
|
+
message_uuid: randomUUID3(),
|
|
450
797
|
...this.startupData
|
|
451
798
|
};
|
|
452
799
|
try {
|
|
@@ -468,7 +815,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
468
815
|
const newPayload = {
|
|
469
816
|
time_offset: 0,
|
|
470
817
|
instance_uuid: this.instanceUuid,
|
|
471
|
-
message_uuid:
|
|
818
|
+
message_uuid: randomUUID3(),
|
|
472
819
|
requests: this.requestCounter.getAndResetRequests(),
|
|
473
820
|
validation_errors: this.validationErrorCounter.getAndResetValidationErrors(),
|
|
474
821
|
server_errors: this.serverErrorCounter.getAndResetServerErrors(),
|
|
@@ -487,8 +834,7 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
487
834
|
const timeOffset = Date.now() - time;
|
|
488
835
|
if (timeOffset <= MAX_QUEUE_TIME) {
|
|
489
836
|
if (i > 0) {
|
|
490
|
-
|
|
491
|
-
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
837
|
+
await this.randomDelay();
|
|
492
838
|
}
|
|
493
839
|
payload.time_offset = timeOffset / 1e3;
|
|
494
840
|
await this.sendData("sync", payload);
|
|
@@ -507,6 +853,52 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
507
853
|
}
|
|
508
854
|
}
|
|
509
855
|
}
|
|
856
|
+
async sendLogData() {
|
|
857
|
+
this.logger.debug("Sending request log data to Apitally Hub");
|
|
858
|
+
await this.requestLogger.rotateFile();
|
|
859
|
+
const fetchWithRetry = fetchRetry(fetch, {
|
|
860
|
+
retries: 3,
|
|
861
|
+
retryDelay: 1e3,
|
|
862
|
+
retryOn: [
|
|
863
|
+
408,
|
|
864
|
+
429,
|
|
865
|
+
500,
|
|
866
|
+
502,
|
|
867
|
+
503,
|
|
868
|
+
504
|
|
869
|
+
]
|
|
870
|
+
});
|
|
871
|
+
let i = 0;
|
|
872
|
+
let logFile;
|
|
873
|
+
while (logFile = this.requestLogger.getFile()) {
|
|
874
|
+
if (i > 0) {
|
|
875
|
+
await this.randomDelay();
|
|
876
|
+
}
|
|
877
|
+
try {
|
|
878
|
+
const response = await fetchWithRetry(`${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`, {
|
|
879
|
+
method: "POST",
|
|
880
|
+
body: await logFile.getContent()
|
|
881
|
+
});
|
|
882
|
+
if (response.status === 402 && response.headers.has("Retry-After")) {
|
|
883
|
+
const retryAfter = parseInt(response.headers.get("Retry-After") ?? "0");
|
|
884
|
+
if (retryAfter > 0) {
|
|
885
|
+
this.requestLogger.suspendUntil = Date.now() + retryAfter * 1e3;
|
|
886
|
+
this.requestLogger.clear();
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
if (!response.ok) {
|
|
891
|
+
throw new HTTPError(response);
|
|
892
|
+
}
|
|
893
|
+
logFile.delete();
|
|
894
|
+
} catch (error) {
|
|
895
|
+
this.requestLogger.retryFileLater(logFile);
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
i++;
|
|
899
|
+
if (i >= 10) break;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
510
902
|
handleHubError(error) {
|
|
511
903
|
if (error instanceof HTTPError) {
|
|
512
904
|
if (error.response.status === 404) {
|
|
@@ -521,6 +913,10 @@ var _ApitallyClient = class _ApitallyClient {
|
|
|
521
913
|
}
|
|
522
914
|
return false;
|
|
523
915
|
}
|
|
916
|
+
async randomDelay() {
|
|
917
|
+
const delay = 100 + Math.random() * 200;
|
|
918
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
919
|
+
}
|
|
524
920
|
};
|
|
525
921
|
__name(_ApitallyClient, "ApitallyClient");
|
|
526
922
|
__publicField(_ApitallyClient, "instance");
|