-
Notifications
You must be signed in to change notification settings - Fork 26k
/
collect-stats.js
148 lines (128 loc) · 4.27 KB
/
collect-stats.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
const path = require('path')
const fs = require('fs-extra')
const getPort = require('get-port')
const fetch = require('node-fetch')
const glob = require('../util/glob')
const gzipSize = require('gzip-size')
const logger = require('../util/logger')
const { spawn } = require('../util/exec')
const { parse: urlParse } = require('url')
const benchmarkUrl = require('./benchmark-url')
const { statsAppDir, diffingDir, benchTitle } = require('../constants')
module.exports = async function collectStats(
runConfig = {},
statsConfig = {},
fromDiff = false
) {
const stats = {
[benchTitle]: {},
}
const orderedStats = {
[benchTitle]: {},
}
const curDir = fromDiff ? diffingDir : statsAppDir
const hasPagesToFetch =
Array.isArray(runConfig.pagesToFetch) && runConfig.pagesToFetch.length > 0
const hasPagesToBench =
Array.isArray(runConfig.pagesToBench) && runConfig.pagesToBench.length > 0
if (
!fromDiff &&
statsConfig.appStartCommand &&
(hasPagesToFetch || hasPagesToBench)
) {
const port = await getPort()
const child = spawn(statsConfig.appStartCommand, {
cwd: curDir,
env: {
PORT: port,
},
stdio: 'pipe',
})
let exitCode = null
let logStderr = true
child.stdout.on('data', (data) => process.stdout.write(data))
child.stderr.on('data', (data) => logStderr && process.stderr.write(data))
child.on('exit', (code) => {
exitCode = code
})
// give app a second to start up
await new Promise((resolve) => setTimeout(() => resolve(), 1500))
if (exitCode !== null) {
throw new Error(
`Failed to run \`${statsConfig.appStartCommand}\` process exited with code ${exitCode}`
)
}
if (hasPagesToFetch) {
const fetchedPagesDir = path.join(curDir, 'fetched-pages')
await fs.mkdirp(fetchedPagesDir)
for (let url of runConfig.pagesToFetch) {
url = url.replace('$PORT', port)
const { pathname } = urlParse(url)
try {
const res = await fetch(url)
if (!res.ok) {
throw new Error(`Failed to fetch ${url} got status: ${res.status}`)
}
const responseText = (await res.text()).trim()
let fileName = pathname === '/' ? '/index' : pathname
if (fileName.endsWith('/')) fileName = fileName.slice(0, -1)
logger(
`Writing file to ${path.join(fetchedPagesDir, `${fileName}.html`)}`
)
await fs.writeFile(
path.join(fetchedPagesDir, `${fileName}.html`),
responseText,
'utf8'
)
} catch (err) {
logger.error(err)
}
}
}
if (hasPagesToBench) {
// disable stderr so we don't clobber logs while benchmarking
// any pages that create logs
logStderr = false
for (let url of runConfig.pagesToBench) {
url = url.replace('$PORT', port)
logger(`Benchmarking ${url}`)
const results = await benchmarkUrl(url, runConfig.benchOptions)
logger(`Finished benchmarking ${url}`)
const { pathname: key } = urlParse(url)
stats[benchTitle][`${key} failed reqs`] = results.failedRequests
stats[benchTitle][`${key} total time (seconds)`] = results.totalTime
stats[benchTitle][`${key} avg req/sec`] = results.avgReqPerSec
}
}
child.kill()
}
for (const fileGroup of runConfig.filesToTrack) {
const { name, globs } = fileGroup
const groupStats = {}
const curFiles = new Set()
for (const pattern of globs) {
const results = await glob(pattern, { cwd: curDir, nodir: true })
results.forEach((result) => curFiles.add(result))
}
for (const file of curFiles) {
const fileKey = path.basename(file)
const absPath = path.join(curDir, file)
try {
const fileInfo = await fs.stat(absPath)
groupStats[fileKey] = fileInfo.size
groupStats[`${fileKey} gzip`] = await gzipSize.file(absPath)
} catch (err) {
logger.error('Failed to get file stats', err)
}
}
stats[name] = groupStats
}
for (const fileGroup of runConfig.filesToTrack) {
const { name } = fileGroup
orderedStats[name] = stats[name]
}
if (stats[benchTitle]) {
orderedStats[benchTitle] = stats[benchTitle]
}
return orderedStats
}