@vpalmisano/webrtcperf 4.2.2 → 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/src/stats.ts CHANGED
@@ -32,23 +32,19 @@ function calculateFailAmountPercentile(stat: FastStats, percentile = 95): number
32
32
  class StatsWriter {
33
33
  fname: string
34
34
  columns: string[]
35
- private _header_written = false
35
+ private headerWritten = false
36
36
 
37
37
  constructor(fname = 'stats.log', columns: string[]) {
38
38
  this.fname = fname
39
39
  this.columns = columns
40
40
  }
41
41
 
42
- /**
43
- * push
44
- * @param dataColumns
45
- */
46
- async push(dataColumns: string[]): Promise<void> {
47
- if (!this._header_written) {
42
+ async push(dataColumns: string[], append = true): Promise<void> {
43
+ if (!this.headerWritten || !append) {
48
44
  const data = ['datetime', ...this.columns].join(',') + '\n'
49
45
  await fs.promises.mkdir(path.dirname(this.fname), { recursive: true })
50
46
  await fs.promises.writeFile(this.fname, data)
51
- this._header_written = true
47
+ this.headerWritten = true
52
48
  }
53
49
  //
54
50
  const data = [Date.now(), ...dataColumns].join(',') + '\n'
@@ -330,6 +326,7 @@ export class Stats extends events.EventEmitter {
330
326
  nextSessionId: number
331
327
  statsWriter: StatsWriter | null
332
328
  detailedStatsWriter: StatsWriter | null
329
+ detailedStatsSummaryWriter: StatsWriter | null
333
330
  private scheduler?: Scheduler
334
331
 
335
332
  private alertRules: Record<string, AlertRule> | null = null
@@ -386,18 +383,18 @@ export class Stats extends events.EventEmitter {
386
383
 
387
384
  collectedStats: Record<string, CollectedStats>
388
385
 
389
- collectedStatsConfig = {
386
+ private collectedStatsConfig = {
390
387
  url: '',
391
388
  pages: 0,
392
389
  startTime: 0,
393
390
  }
394
- externalCollectedStats = new Map<
391
+ private externalCollectedStats = new Map<
395
392
  string,
396
393
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
397
394
  { addedTime: number; externalStats: any; config: any }
398
395
  >()
399
- pushStatsInstance: axios.AxiosInstance | null = null
400
-
396
+ private pushStatsInstance: axios.AxiosInstance | null = null
397
+ private detailedStatsSummary: Record<string, Record<string, FastStats>> = {}
401
398
  private running = false
402
399
 
403
400
  /**
@@ -485,6 +482,7 @@ export class Stats extends events.EventEmitter {
485
482
 
486
483
  this.statsWriter = null
487
484
  this.detailedStatsWriter = null
485
+ this.detailedStatsSummaryWriter = null
488
486
  if (alertRules.trim()) {
489
487
  this.alertRules = json5.parse(alertRules)
490
488
  log.debug(`using alertRules: ${JSON.stringify(this.alertRules, undefined, 2)}`)
@@ -615,6 +613,11 @@ export class Stats extends events.EventEmitter {
615
613
  'trackId',
616
614
  ...this.statsNames,
617
615
  ])
616
+ this.detailedStatsSummaryWriter = new StatsWriter(this.detailedStatsPath.replace(/\.(.+)$/, '-summary.$1'), [
617
+ 'participantName',
618
+ 'trackId',
619
+ ...this.statsNames,
620
+ ])
618
621
  }
619
622
 
620
623
  if (this.prometheusPushgateway) {
@@ -821,8 +824,7 @@ export class Stats extends events.EventEmitter {
821
824
  collectedStats.all.push(obj)
822
825
  } else {
823
826
  for (const [key, value] of Object.entries(obj)) {
824
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
825
- if (typeof value === 'number' && isFinite(value as any)) {
827
+ if (typeof value === 'number' && isFinite(value)) {
826
828
  collectedStats.all.push(value)
827
829
  // Push host label.
828
830
  const { trackId, hostName, participantName } = parseRtStatKey(key)
@@ -955,7 +957,7 @@ export class Stats extends events.EventEmitter {
955
957
 
956
958
  async writeDetailedStats() {
957
959
  if (!this.detailedStatsWriter) return
958
- const participantTrackStats = new Map<string, Record<string, string>>()
960
+ const participantTrackStats = new Map<string, Record<string, number>>()
959
961
  Object.entries(this.collectedStats).forEach(([name, stats]) => {
960
962
  Object.entries(stats.byParticipantAndTrack).forEach(([label, value]) => {
961
963
  let stats = participantTrackStats.get(label)
@@ -963,19 +965,47 @@ export class Stats extends events.EventEmitter {
963
965
  stats = {}
964
966
  participantTrackStats.set(label, stats)
965
967
  }
966
- stats[name] = toPrecision(value, 6)
968
+ stats[name] = value
967
969
  })
968
970
  })
969
971
  for (const [label, trackStats] of participantTrackStats.entries()) {
970
972
  const [participantName, trackId] = label.split(':', 2)
973
+ if (!this.detailedStatsSummary[label]) {
974
+ this.detailedStatsSummary[label] = {}
975
+ }
976
+ const summary = this.detailedStatsSummary[label]
971
977
  const values = [participantName, trackId]
972
978
  for (const name of this.statsNames) {
973
- values.push(trackStats[name] ?? '')
979
+ values.push(trackStats[name] !== undefined ? toPrecision(trackStats[name], 6) : '')
980
+ // Update the summary stats.
981
+ if (!summary[name]) {
982
+ summary[name] = new FastStats({ store_data: false })
983
+ }
984
+ const stat = summary[name]
985
+ if (trackStats[name] !== undefined) {
986
+ stat.push(trackStats[name])
987
+ }
974
988
  }
975
989
  await this.detailedStatsWriter.push(values)
976
990
  }
977
991
  }
978
992
 
993
+ async writeDetailedStatsSummary() {
994
+ if (!this.detailedStatsSummaryWriter) return
995
+ let append = false
996
+ for (const label of Object.keys(this.detailedStatsSummary)) {
997
+ const summary = this.detailedStatsSummary[label]
998
+ const [participantName, trackId] = label.split(':', 2)
999
+ const values = [participantName, trackId]
1000
+ for (const name of this.statsNames) {
1001
+ const stat = summary[name]
1002
+ values.push(stat?.length > 0 ? toPrecision(stat.amean(), 6) : '')
1003
+ }
1004
+ await this.detailedStatsSummaryWriter.push(values, append)
1005
+ append = true
1006
+ }
1007
+ }
1008
+
979
1009
  /**
980
1010
  * addCollectedStats
981
1011
  * @param id
@@ -1652,17 +1682,13 @@ export class Stats extends events.EventEmitter {
1652
1682
  }
1653
1683
  }
1654
1684
 
1655
- /**
1656
- * Stop the stats collector and the added Sessions.
1657
- */
1658
- async stop(): Promise<void> {
1659
- if (!this.running) {
1660
- return
1661
- }
1685
+ async stop() {
1686
+ if (!this.running) return
1662
1687
  this.running = false
1663
1688
  log.debug('stop')
1689
+
1664
1690
  if (this.scheduler) {
1665
- this.scheduler.stop()
1691
+ await this.scheduler.stop()
1666
1692
  this.scheduler = undefined
1667
1693
  }
1668
1694
 
@@ -1676,7 +1702,12 @@ export class Stats extends events.EventEmitter {
1676
1702
  }
1677
1703
  this.sessions.clear()
1678
1704
 
1705
+ await this.writeDetailedStatsSummary()
1706
+
1679
1707
  this.statsWriter = null
1708
+ this.detailedStatsWriter = null
1709
+ this.detailedStatsSummaryWriter = null
1710
+ this.detailedStatsSummary = {}
1680
1711
 
1681
1712
  // delete metrics
1682
1713
  if (this.gateway) {
package/src/utils.ts CHANGED
@@ -291,7 +291,6 @@ export async function randomActivateAudio(
291
291
  pages = pages.concat(sessionPages)
292
292
  }
293
293
  }
294
- // Remove pages with no audio tracks.
295
294
  for (const [i, page] of pages.entries()) {
296
295
  if (!page) {
297
296
  continue
@@ -307,15 +306,8 @@ export async function randomActivateAudio(
307
306
  }
308
307
  }
309
308
  const pagesWithAudio: Page[] = pages.filter(p => !!p)
310
- //
311
309
  const index = Math.floor(Math.random() * pagesWithAudio.length)
312
310
  const enable = Math.round(100 * Math.random()) <= randomAudioProbability
313
- log.debug('randomActivateAudio %j', {
314
- pages: pagesWithAudio.length,
315
- randomAudioProbability,
316
- index,
317
- enable,
318
- })
319
311
  for (const [i, page] of pagesWithAudio.entries()) {
320
312
  try {
321
313
  if (i === index) {
@@ -613,7 +605,8 @@ SIGNALS.forEach(event =>
613
605
  export async function checkChromeExecutable(): Promise<string> {
614
606
  // eslint-disable-next-line @typescript-eslint/no-require-imports
615
607
  const { loadConfig } = require('./config')
616
- const config = await loadConfig()
608
+ const configs = await loadConfig()
609
+ const config = configs[0]
617
610
  const cacheDir = path.join(os.homedir(), '.webrtcperf/chrome')
618
611
 
619
612
  const fixSemVer = (v: string) => v.split('.').slice(0, 3).join('.')
@@ -806,21 +799,26 @@ export class Scheduler {
806
799
  log.debug(`[${this.name}-scheduler] constructor interval=${this.interval}ms`)
807
800
  }
808
801
 
809
- start(): void {
802
+ start() {
810
803
  log.debug(`[${this.name}-scheduler] start`)
811
804
  this.running = true
812
805
  this.scheduleNext()
813
806
  }
814
807
 
815
- stop(): void {
808
+ async stop() {
816
809
  log.debug(`[${this.name}-scheduler] stop`)
817
810
  this.running = false
818
811
  if (this.statsTimeoutId) {
819
812
  clearTimeout(this.statsTimeoutId)
820
813
  }
814
+ try {
815
+ await this.callback(Date.now())
816
+ } catch (err) {
817
+ log.error(`[${this.name}-scheduler] stop callback error: ${(err as Error).stack}`, err)
818
+ }
821
819
  }
822
820
 
823
- private scheduleNext(): void {
821
+ private scheduleNext() {
824
822
  if (!this.running) {
825
823
  return
826
824
  }