@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.
@@ -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 _header_written;
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
- url: string;
133
- pages: number;
134
- startTime: number;
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
  }
@@ -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
- _header_written = false;
66
+ headerWritten = false;
66
67
  constructor(fname = 'stats.log', columns) {
67
68
  this.fname = fname;
68
69
  this.columns = columns;
69
70
  }
70
- /**
71
- * push
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._header_written = true;
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)((0, chalk_1.default) `-- {bold %(name)s} %(fill)s\n`, {
133
+ return (0, sprintf_js_1.sprintf)(chalk `-- {bold %(name)s} %(fill)s\n`, {
137
134
  name,
138
- fill: '-'.repeat(100 - name.length - 4),
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)((0, chalk_1.default) `{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`, {
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)((0, chalk_1.default) `{red {bold %(name)\' 30s}}` +
170
- (0, chalk_1.default) ` {bold %(length)\' 8d}` +
171
- (hideSum ? ' ' : (0, chalk_1.default) ` {bold %(sum)\' 8${format}}`) +
172
- (0, chalk_1.default) ` {bold %(mean)\' 8${format}}` +
173
- (0, chalk_1.default) ` {bold %(stddev)\' 8${format}}` +
174
- (0, chalk_1.default) ` {bold %(p5)\' 8${format}}` +
175
- (0, chalk_1.default) ` {bold %(p95)\' 8${format}}` +
176
- (0, chalk_1.default) ` {bold %(min)\' 8${format}}` +
177
- (0, chalk_1.default) ` {bold %(max)\' 8${format}}%(unit)s\n`, {
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 ? (0, chalk_1.default) ` {red {bold ${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] = (0, utils_1.toPrecision)(value, 6);
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)((0, chalk_1.default) `{bold %(check)-${colSize}s} {bold %(total)-10s} {bold %(totalFailsTime)-15s} {bold %(totalFailsTimePerc)-15s} {bold %(failAmount)-15s}\n`, {
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)((0, chalk_1.default) `{red {bold %(check)-${colSize}s}} {bold %(totalFails)-10s} {bold %(totalFailsTime)-15s} {bold %(totalFailsTimePerc)-15s} {bold %(failAmountPercentile)-15s}\n`, {
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)((0, chalk_1.default) `{bold %(name)-${colSize}s} {bold %(failPerc)-15s}\n`, {
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)((0, chalk_1.default) `{${color} {bold %(tag)-${colSize}s %(failPerc)-15s}}\n`, {
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();