@vpalmisano/webrtcperf 4.2.0 → 4.3.2
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 +16 -1
- package/app.min.js +1 -1
- package/build/src/app.d.ts +13 -4
- package/build/src/app.js +170 -124
- package/build/src/app.js.map +1 -1
- package/build/src/config.d.ts +2 -91
- package/build/src/config.js +37 -29
- package/build/src/config.js.map +1 -1
- package/build/src/server.js +28 -10
- package/build/src/server.js.map +1 -1
- package/build/src/session.js +3 -2
- package/build/src/session.js.map +1 -1
- package/build/src/stats.d.ts +8 -21
- package/build/src/stats.js +67 -35
- package/build/src/stats.js.map +1 -1
- package/build/src/utils.d.ts +1 -1
- package/build/src/utils.js +9 -10
- package/build/src/utils.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +31 -28
- package/src/app.ts +184 -136
- package/src/config.ts +35 -28
- package/src/server.ts +33 -13
- package/src/session.ts +3 -1
- package/src/stats.ts +60 -27
- package/src/utils.ts +10 -12
package/build/src/stats.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
1
|
import * as events from 'events';
|
|
3
2
|
import { Stats as FastStats } from 'fast-stats';
|
|
4
3
|
import { Session } from './session';
|
|
@@ -9,13 +8,9 @@ export { FastStats };
|
|
|
9
8
|
declare class StatsWriter {
|
|
10
9
|
fname: string;
|
|
11
10
|
columns: string[];
|
|
12
|
-
private
|
|
11
|
+
private headerWritten;
|
|
13
12
|
constructor(fname: string | undefined, columns: string[]);
|
|
14
|
-
|
|
15
|
-
* push
|
|
16
|
-
* @param dataColumns
|
|
17
|
-
*/
|
|
18
|
-
push(dataColumns: string[]): Promise<void>;
|
|
13
|
+
push(dataColumns: string[], append?: boolean): Promise<void>;
|
|
19
14
|
}
|
|
20
15
|
export interface CollectedStats {
|
|
21
16
|
all: FastStats;
|
|
@@ -114,6 +109,7 @@ export declare class Stats extends events.EventEmitter {
|
|
|
114
109
|
nextSessionId: number;
|
|
115
110
|
statsWriter: StatsWriter | null;
|
|
116
111
|
detailedStatsWriter: StatsWriter | null;
|
|
112
|
+
detailedStatsSummaryWriter: StatsWriter | null;
|
|
117
113
|
private scheduler?;
|
|
118
114
|
private alertRules;
|
|
119
115
|
readonly alertRulesOutput: string;
|
|
@@ -128,17 +124,10 @@ export declare class Stats extends events.EventEmitter {
|
|
|
128
124
|
private alertTagsMetrics?;
|
|
129
125
|
private readonly customMetricsLabels;
|
|
130
126
|
collectedStats: Record<string, CollectedStats>;
|
|
131
|
-
collectedStatsConfig
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
};
|
|
136
|
-
externalCollectedStats: Map<string, {
|
|
137
|
-
addedTime: number;
|
|
138
|
-
externalStats: any;
|
|
139
|
-
config: any;
|
|
140
|
-
}>;
|
|
141
|
-
pushStatsInstance: axios.AxiosInstance | null;
|
|
127
|
+
private collectedStatsConfig;
|
|
128
|
+
private externalCollectedStats;
|
|
129
|
+
private pushStatsInstance;
|
|
130
|
+
private detailedStatsSummary;
|
|
142
131
|
private running;
|
|
143
132
|
/**
|
|
144
133
|
* Stats aggregator class.
|
|
@@ -199,6 +188,7 @@ export declare class Stats extends events.EventEmitter {
|
|
|
199
188
|
collectStats(now: number): Promise<void>;
|
|
200
189
|
writeStats(): Promise<void>;
|
|
201
190
|
writeDetailedStats(): Promise<void>;
|
|
191
|
+
writeDetailedStatsSummary(): Promise<void>;
|
|
202
192
|
/**
|
|
203
193
|
* addCollectedStats
|
|
204
194
|
* @param id
|
|
@@ -236,8 +226,5 @@ export declare class Stats extends events.EventEmitter {
|
|
|
236
226
|
* writeAlertRulesReport
|
|
237
227
|
*/
|
|
238
228
|
writeAlertRulesReport(): Promise<void>;
|
|
239
|
-
/**
|
|
240
|
-
* Stop the stats collector and the added Sessions.
|
|
241
|
-
*/
|
|
242
229
|
stop(): Promise<void>;
|
|
243
230
|
}
|
package/build/src/stats.js
CHANGED
|
@@ -38,7 +38,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.Stats = exports.FastStats = void 0;
|
|
40
40
|
const axios_1 = __importDefault(require("axios"));
|
|
41
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
42
41
|
const events = __importStar(require("events"));
|
|
43
42
|
const fast_stats_1 = require("fast-stats");
|
|
44
43
|
Object.defineProperty(exports, "FastStats", { enumerable: true, get: function () { return fast_stats_1.Stats; } });
|
|
@@ -53,6 +52,8 @@ const zlib = __importStar(require("zlib"));
|
|
|
53
52
|
const rtcstats_1 = require("./rtcstats");
|
|
54
53
|
const utils_1 = require("./utils");
|
|
55
54
|
const log = (0, utils_1.logger)('webrtcperf:stats');
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
56
|
+
const { default: chalk } = require('chalk-template');
|
|
56
57
|
function calculateFailAmountPercentile(stat, percentile = 95) {
|
|
57
58
|
return Math.round(stat.percentile(percentile));
|
|
58
59
|
}
|
|
@@ -62,21 +63,17 @@ function calculateFailAmountPercentile(stat, percentile = 95) {
|
|
|
62
63
|
class StatsWriter {
|
|
63
64
|
fname;
|
|
64
65
|
columns;
|
|
65
|
-
|
|
66
|
+
headerWritten = false;
|
|
66
67
|
constructor(fname = 'stats.log', columns) {
|
|
67
68
|
this.fname = fname;
|
|
68
69
|
this.columns = columns;
|
|
69
70
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
* @param dataColumns
|
|
73
|
-
*/
|
|
74
|
-
async push(dataColumns) {
|
|
75
|
-
if (!this._header_written) {
|
|
71
|
+
async push(dataColumns, append = true) {
|
|
72
|
+
if (!this.headerWritten || !append) {
|
|
76
73
|
const data = ['datetime', ...this.columns].join(',') + '\n';
|
|
77
74
|
await fs.promises.mkdir(path.dirname(this.fname), { recursive: true });
|
|
78
75
|
await fs.promises.writeFile(this.fname, data);
|
|
79
|
-
this.
|
|
76
|
+
this.headerWritten = true;
|
|
80
77
|
}
|
|
81
78
|
//
|
|
82
79
|
const data = [Date.now(), ...dataColumns].join(',') + '\n';
|
|
@@ -133,9 +130,9 @@ function formatStats(s, forWriter = false) {
|
|
|
133
130
|
* @param name
|
|
134
131
|
*/
|
|
135
132
|
function sprintfStatsTitle(name) {
|
|
136
|
-
return (0, sprintf_js_1.sprintf)(
|
|
133
|
+
return (0, sprintf_js_1.sprintf)(chalk `-- {bold %(name)s} %(fill)s\n`, {
|
|
137
134
|
name,
|
|
138
|
-
fill: '-'.repeat(
|
|
135
|
+
fill: '-'.repeat(110 - name.length - 4),
|
|
139
136
|
});
|
|
140
137
|
}
|
|
141
138
|
/**
|
|
@@ -143,7 +140,7 @@ function sprintfStatsTitle(name) {
|
|
|
143
140
|
*/
|
|
144
141
|
function sprintfStatsHeader() {
|
|
145
142
|
return (sprintfStatsTitle(new Date().toUTCString()) +
|
|
146
|
-
(0, sprintf_js_1.sprintf)(
|
|
143
|
+
(0, sprintf_js_1.sprintf)(chalk `{bold %(name)\' 30s} {bold %(length)\' 8s} {bold %(sum)\' 8s} {bold %(mean)\' 8s} {bold %(stddev)\' 8s} {bold %(p5)\' 8s} {bold %(p95)\' 8s} {bold %(min)\' 8s} {bold %(max)\' 8s}\n`, {
|
|
147
144
|
name: 'name',
|
|
148
145
|
length: 'count',
|
|
149
146
|
sum: 'sum',
|
|
@@ -166,15 +163,15 @@ function sprintfStats(name, stats, format = '.2f', unit = '', scale = 1, hideSum
|
|
|
166
163
|
scale = 1;
|
|
167
164
|
}
|
|
168
165
|
const statsData = formatStats(stats.all);
|
|
169
|
-
return (0, sprintf_js_1.sprintf)(
|
|
170
|
-
|
|
171
|
-
(hideSum ? ' ' :
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
166
|
+
return (0, sprintf_js_1.sprintf)(chalk `{red {bold %(name)\' 30s}}` +
|
|
167
|
+
chalk ` {bold %(length)\' 8d}` +
|
|
168
|
+
(hideSum ? ' ' : chalk ` {bold %(sum)\' 8${format}}`) +
|
|
169
|
+
chalk ` {bold %(mean)\' 8${format}}` +
|
|
170
|
+
chalk ` {bold %(stddev)\' 8${format}}` +
|
|
171
|
+
chalk ` {bold %(p5)\' 8${format}}` +
|
|
172
|
+
chalk ` {bold %(p95)\' 8${format}}` +
|
|
173
|
+
chalk ` {bold %(min)\' 8${format}}` +
|
|
174
|
+
chalk ` {bold %(max)\' 8${format}}%(unit)s\n`, {
|
|
178
175
|
name,
|
|
179
176
|
length: statsData.length,
|
|
180
177
|
sum: statsData.sum * scale,
|
|
@@ -184,7 +181,7 @@ function sprintfStats(name, stats, format = '.2f', unit = '', scale = 1, hideSum
|
|
|
184
181
|
p95: statsData.p95 * scale,
|
|
185
182
|
min: statsData.min * scale,
|
|
186
183
|
max: statsData.max * scale,
|
|
187
|
-
unit: unit ?
|
|
184
|
+
unit: unit ? chalk ` {red {bold ${unit}}}` : '',
|
|
188
185
|
});
|
|
189
186
|
}
|
|
190
187
|
const promPrefix = 'wst_';
|
|
@@ -227,6 +224,7 @@ class Stats extends events.EventEmitter {
|
|
|
227
224
|
nextSessionId;
|
|
228
225
|
statsWriter;
|
|
229
226
|
detailedStatsWriter;
|
|
227
|
+
detailedStatsSummaryWriter;
|
|
230
228
|
scheduler;
|
|
231
229
|
alertRules = null;
|
|
232
230
|
alertRulesOutput;
|
|
@@ -249,6 +247,7 @@ class Stats extends events.EventEmitter {
|
|
|
249
247
|
};
|
|
250
248
|
externalCollectedStats = new Map();
|
|
251
249
|
pushStatsInstance = null;
|
|
250
|
+
detailedStatsSummary = {};
|
|
252
251
|
running = false;
|
|
253
252
|
/**
|
|
254
253
|
* Stats aggregator class.
|
|
@@ -286,6 +285,7 @@ class Stats extends events.EventEmitter {
|
|
|
286
285
|
: {};
|
|
287
286
|
this.statsWriter = null;
|
|
288
287
|
this.detailedStatsWriter = null;
|
|
288
|
+
this.detailedStatsSummaryWriter = null;
|
|
289
289
|
if (alertRules.trim()) {
|
|
290
290
|
this.alertRules = json5_1.default.parse(alertRules);
|
|
291
291
|
log.debug(`using alertRules: ${JSON.stringify(this.alertRules, undefined, 2)}`);
|
|
@@ -404,6 +404,11 @@ class Stats extends events.EventEmitter {
|
|
|
404
404
|
'trackId',
|
|
405
405
|
...this.statsNames,
|
|
406
406
|
]);
|
|
407
|
+
this.detailedStatsSummaryWriter = new StatsWriter(this.detailedStatsPath.replace(/\.(.+)$/, '-summary.$1'), [
|
|
408
|
+
'participantName',
|
|
409
|
+
'trackId',
|
|
410
|
+
...this.statsNames,
|
|
411
|
+
]);
|
|
407
412
|
}
|
|
408
413
|
if (this.prometheusPushgateway) {
|
|
409
414
|
const register = new promClient.Registry();
|
|
@@ -587,7 +592,6 @@ class Stats extends events.EventEmitter {
|
|
|
587
592
|
}
|
|
588
593
|
else {
|
|
589
594
|
for (const [key, value] of Object.entries(obj)) {
|
|
590
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
591
595
|
if (typeof value === 'number' && isFinite(value)) {
|
|
592
596
|
collectedStats.all.push(value);
|
|
593
597
|
// Push host label.
|
|
@@ -728,18 +732,46 @@ class Stats extends events.EventEmitter {
|
|
|
728
732
|
stats = {};
|
|
729
733
|
participantTrackStats.set(label, stats);
|
|
730
734
|
}
|
|
731
|
-
stats[name] =
|
|
735
|
+
stats[name] = value;
|
|
732
736
|
});
|
|
733
737
|
});
|
|
734
738
|
for (const [label, trackStats] of participantTrackStats.entries()) {
|
|
735
739
|
const [participantName, trackId] = label.split(':', 2);
|
|
740
|
+
if (!this.detailedStatsSummary[label]) {
|
|
741
|
+
this.detailedStatsSummary[label] = {};
|
|
742
|
+
}
|
|
743
|
+
const summary = this.detailedStatsSummary[label];
|
|
736
744
|
const values = [participantName, trackId];
|
|
737
745
|
for (const name of this.statsNames) {
|
|
738
|
-
values.push(trackStats[name]
|
|
746
|
+
values.push(trackStats[name] !== undefined ? (0, utils_1.toPrecision)(trackStats[name], 6) : '');
|
|
747
|
+
// Update the summary stats.
|
|
748
|
+
if (!summary[name]) {
|
|
749
|
+
summary[name] = new fast_stats_1.Stats({ store_data: false });
|
|
750
|
+
}
|
|
751
|
+
const stat = summary[name];
|
|
752
|
+
if (trackStats[name] !== undefined) {
|
|
753
|
+
stat.push(trackStats[name]);
|
|
754
|
+
}
|
|
739
755
|
}
|
|
740
756
|
await this.detailedStatsWriter.push(values);
|
|
741
757
|
}
|
|
742
758
|
}
|
|
759
|
+
async writeDetailedStatsSummary() {
|
|
760
|
+
if (!this.detailedStatsSummaryWriter)
|
|
761
|
+
return;
|
|
762
|
+
let append = false;
|
|
763
|
+
for (const label of Object.keys(this.detailedStatsSummary)) {
|
|
764
|
+
const summary = this.detailedStatsSummary[label];
|
|
765
|
+
const [participantName, trackId] = label.split(':', 2);
|
|
766
|
+
const values = [participantName, trackId];
|
|
767
|
+
for (const name of this.statsNames) {
|
|
768
|
+
const stat = summary[name];
|
|
769
|
+
values.push(stat?.length > 0 ? (0, utils_1.toPrecision)(stat.amean(), 6) : '');
|
|
770
|
+
}
|
|
771
|
+
await this.detailedStatsSummaryWriter.push(values, append);
|
|
772
|
+
append = true;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
743
775
|
/**
|
|
744
776
|
* addCollectedStats
|
|
745
777
|
* @param id
|
|
@@ -1260,7 +1292,7 @@ class Stats extends events.EventEmitter {
|
|
|
1260
1292
|
});
|
|
1261
1293
|
}
|
|
1262
1294
|
else {
|
|
1263
|
-
out += (0, sprintf_js_1.sprintf)(
|
|
1295
|
+
out += (0, sprintf_js_1.sprintf)(chalk `{bold %(check)-${colSize}s} {bold %(total)-10s} {bold %(totalFailsTime)-15s} {bold %(totalFailsTimePerc)-15s} {bold %(failAmount)-15s}\n`, {
|
|
1264
1296
|
check: 'Condition',
|
|
1265
1297
|
total: 'Fails',
|
|
1266
1298
|
totalFailsTime: 'Fail time (s)',
|
|
@@ -1282,7 +1314,7 @@ class Stats extends events.EventEmitter {
|
|
|
1282
1314
|
});
|
|
1283
1315
|
}
|
|
1284
1316
|
else {
|
|
1285
|
-
out += (0, sprintf_js_1.sprintf)(
|
|
1317
|
+
out += (0, sprintf_js_1.sprintf)(chalk `{red {bold %(check)-${colSize}s}} {bold %(totalFails)-10s} {bold %(totalFailsTime)-15s} {bold %(totalFailsTimePerc)-15s} {bold %(failAmountPercentile)-15s}\n`, {
|
|
1286
1318
|
check: `${key} ${reportDesc}`,
|
|
1287
1319
|
totalFails,
|
|
1288
1320
|
totalFailsTime: Math.round(totalFailsTime),
|
|
@@ -1303,7 +1335,7 @@ class Stats extends events.EventEmitter {
|
|
|
1303
1335
|
}
|
|
1304
1336
|
else {
|
|
1305
1337
|
out += (0, sprintf_js_1.sprintf)(`%(fill)s\n`, { fill: '-'.repeat(colSize + 15) });
|
|
1306
|
-
out += (0, sprintf_js_1.sprintf)(
|
|
1338
|
+
out += (0, sprintf_js_1.sprintf)(chalk `{bold %(name)-${colSize}s} {bold %(failPerc)-15s}\n`, {
|
|
1307
1339
|
name: 'Tag',
|
|
1308
1340
|
failPerc: 'Fail %',
|
|
1309
1341
|
});
|
|
@@ -1318,7 +1350,7 @@ class Stats extends events.EventEmitter {
|
|
|
1318
1350
|
}
|
|
1319
1351
|
else {
|
|
1320
1352
|
const color = failPerc < 5 ? 'green' : failPerc < 25 ? 'yellowBright' : failPerc < 50 ? 'yellow' : 'red';
|
|
1321
|
-
out += (0, sprintf_js_1.sprintf)(
|
|
1353
|
+
out += (0, sprintf_js_1.sprintf)(chalk `{${color} {bold %(tag)-${colSize}s %(failPerc)-15s}}\n`, {
|
|
1322
1354
|
tag,
|
|
1323
1355
|
failPerc,
|
|
1324
1356
|
});
|
|
@@ -1365,17 +1397,13 @@ class Stats extends events.EventEmitter {
|
|
|
1365
1397
|
log.error(`writeAlertRulesReport error: ${err.stack}`);
|
|
1366
1398
|
}
|
|
1367
1399
|
}
|
|
1368
|
-
/**
|
|
1369
|
-
* Stop the stats collector and the added Sessions.
|
|
1370
|
-
*/
|
|
1371
1400
|
async stop() {
|
|
1372
|
-
if (!this.running)
|
|
1401
|
+
if (!this.running)
|
|
1373
1402
|
return;
|
|
1374
|
-
}
|
|
1375
1403
|
this.running = false;
|
|
1376
1404
|
log.debug('stop');
|
|
1377
1405
|
if (this.scheduler) {
|
|
1378
|
-
this.scheduler.stop();
|
|
1406
|
+
await this.scheduler.stop();
|
|
1379
1407
|
this.scheduler = undefined;
|
|
1380
1408
|
}
|
|
1381
1409
|
for (const session of this.sessions.values()) {
|
|
@@ -1388,7 +1416,11 @@ class Stats extends events.EventEmitter {
|
|
|
1388
1416
|
}
|
|
1389
1417
|
}
|
|
1390
1418
|
this.sessions.clear();
|
|
1419
|
+
await this.writeDetailedStatsSummary();
|
|
1391
1420
|
this.statsWriter = null;
|
|
1421
|
+
this.detailedStatsWriter = null;
|
|
1422
|
+
this.detailedStatsSummaryWriter = null;
|
|
1423
|
+
this.detailedStatsSummary = {};
|
|
1392
1424
|
// delete metrics
|
|
1393
1425
|
if (this.gateway) {
|
|
1394
1426
|
await this.deletePushgatewayStats();
|