Metrics per run side by side (#3439)

Adds a new page that show metrics (that exists as friendly names) side by side for all runs. Helpful to use to see the spread of the metrics.
This commit is contained in:
Peter Hedenskog 2021-08-19 20:37:54 +02:00 committed by GitHub
parent 13216a1de6
commit 1acaf332fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 142 additions and 8 deletions

View File

@ -342,7 +342,6 @@ class HTMLBuilder {
const pageRuns = this.pageRuns.filter(
run => !!get(pageInfo.data, [run.id, 'run'])
);
let rootPath = this.storageManager.rootPathFromUrl(url, daurlAlias);
let data = {
daurl: url,
@ -380,6 +379,7 @@ class HTMLBuilder {
headers: this.summary,
version: packageInfo.version,
timestamp: runTimestamp,
friendlyNames,
context: this.context,
pageRuns
};
@ -387,10 +387,18 @@ class HTMLBuilder {
for (const run of pageRuns) {
pugs[run.id] = renderer.renderTemplate(run.id, data);
}
data.pugs = pugs;
urlPageRenders.push(
this._renderUrlRunPage(url, parseInt(runIndex) + 1, data, daurlAlias)
);
// Do only once per URL
if (parseInt(runIndex) === 0) {
urlPageRenders.push(
this._renderMetricSummaryPage(url, 'metrics', data, daurlAlias)
);
}
}
}
@ -486,6 +494,16 @@ class HTMLBuilder {
);
}
async _renderMetricSummaryPage(url, name, locals, alias) {
log.debug('Render URL metric page %s', name);
return this.storageManager.writeHtmlForUrl(
renderer.renderTemplate('url/summary/metrics/index', locals),
name + '.html',
url,
alias
);
}
async _renderSummaryPage(name, locals) {
log.debug('Render summary page %s', name);

View File

@ -27,9 +27,12 @@ block content
each val, index in runPages
- value = Number(index) + 1
a(href='./' + value + '.html') #{value}
if (value !== Object.keys(runPages).length)
if (value === Object.keys(runPages).length)
|  -
|
a(href='metrics.html') (side by side)
else
|  -
|
if pageInfo.errors
.errors

View File

@ -0,0 +1,39 @@
extends ../layout.pug
block content
h1 Metrics per run
- const daTitle = daurlAlias ? daurlAlias : daurl
h5.url
a(href=daurl) #{decodeURIComponent(daTitle)}
include ../../includes/pageRunInfo
- const tools = ['browsertime', 'pagexray']
- const metrics = {};
- for (let tool of Object.keys(friendlyNames)) {
- if (tools.indexOf(tool) > -1) {
- metrics[tool] = friendlyNames[tool]
- }
- }
h3 Side by side
.responsive
table
tr
- let run = 1
th Metric
each page in runPages
th
b #{run}
- run++
each tool in Object.keys(metrics)
each metricType in Object.keys(metrics[tool])
each metric in Object.keys(metrics[tool][metricType])
- const friendly = metrics[tool][metricType][metric]
- const m = get (runPages[0], 'data.' + tool + '.run.' + (friendly.runPath || friendly.path), 'hepp')
if (m !== 'hepp')
tr
td
b #{friendly.name}
each page in runPages
td #{friendly.format(get (page, 'data.' + tool + '.run.' + (friendly.runPath || friendly.path)))}

View File

@ -1,5 +1,5 @@
'use strict';
const { noop, size, time, co2 } = require('./helpers');
const { noop, size, time, co2, httpErrors, decimals } = require('./helpers');
module.exports = {
browsertime: {
@ -7,128 +7,149 @@ module.exports = {
firstContentfulPaint: {
path: "statistics.timings.paintTiming['first-contentful-paint'].median",
summaryPath: "paintTiming['first-contentful-paint']",
runPath: "timings.paintTiming['first-contentful-paint']",
name: 'First Contentful Paint',
format: time.ms
},
largestContentfulPaint: {
path: 'statistics.timings.largestContentfulPaint.renderTime.median',
summaryPath: 'timings.largestContentfulPaint',
runPath: 'timings.largestContentfulPaint.renderTime',
name: 'Largest Contentful Paint',
format: time.ms
},
totalBlockingTime: {
path: 'statistics.cpu.longTasks.totalBlockingTime.median',
summaryPath: 'cpu.longTasks.totalBlockingTime',
runPath: 'cpu.longTasks.totalBlockingTime',
name: 'Total Blocking Time',
format: time.ms
},
cumulativeLayoutShift: {
path: 'statistics.pageinfo.cumulativeLayoutShift.median',
runPath: 'pageinfo.cumulativeLayoutShift',
summaryPath: 'pageinfo.cumulativeLayoutShift',
name: 'Cumulative Layout Shift',
format: noop
format: decimals
}
},
timings: {
firstPaint: {
path: 'statistics.timings.firstPaint.median',
summaryPath: 'firstPaint',
runPath: 'timings.firstPaint',
name: 'First Paint',
format: time.ms
},
firstContentfulPaint: {
path: "statistics.timings.paintTiming['first-contentful-paint'].median",
summaryPath: "paintTiming['first-contentful-paint']",
runPath: "timings.paintTiming['first-contentful-paint']",
name: 'First Contentful Paint',
format: time.ms
},
largestContentfulPaint: {
path: 'statistics.timings.largestContentfulPaint.renderTime.median',
summaryPath: 'timings.largestContentfulPaint',
runPath: 'timings.largestContentfulPaint.renderTime',
name: 'Largest Contentful Paint',
format: time.ms
},
loadEventEnd: {
path: 'statistics.timings.loadEventEnd.median',
summaryPath: 'loadEventEnd',
runPath: 'timings.loadEventEnd',
name: 'Load Event End',
format: time.ms
},
fullyLoaded: {
path: 'statistics.timings.fullyLoaded.median',
summaryPath: 'timings.fullyLoaded',
runPath: 'timings.fullyLoaded',
name: 'Fully Loaded',
format: time.ms
},
serverResponseTime: {
path: 'statistics.timings.pageTimings.serverResponseTime.median',
summaryPath: 'pageTimings.serverResponseTime',
runPath: 'timings.pageTimings.serverResponseTime',
name: 'Server Response Time',
format: time.ms
},
backEndTime: {
path: 'statistics.timings.pageTimings.backEndTime.median',
summaryPath: 'pageTimings.backEndTime',
runPath: 'timings.pageTimings.backEndTime',
name: 'TTFB',
format: time.ms
},
pageLoadTime: {
path: 'statistics.timings.pageTimings.pageLoadTime.median',
summaryPath: 'pageTimings.pageLoadTime',
runPath: 'timings.pageTimings.pageLoadTime',
name: 'Page Load Time',
format: time.ms
},
FirstVisualChange: {
path: 'statistics.visualMetrics.FirstVisualChange.median',
summaryPath: 'visualMetrics.FirstVisualChange',
runPath: 'visualMetrics.FirstVisualChange',
name: 'First Visual Change',
format: time.ms
},
LastVisualChange: {
path: 'statistics.visualMetrics.LastVisualChange.median',
name: 'Last Visual Change',
summaryPath: 'visualMetrics.LastVisualChange',
runPath: 'visualMetrics.LastVisualChange',
name: 'Last Visual Change',
format: time.ms
},
SpeedIndex: {
path: 'statistics.visualMetrics.SpeedIndex.median',
summaryPath: 'visualMetrics.SpeedIndex',
runPath: 'visualMetrics.SpeedIndex',
name: 'Speed Index',
format: time.ms
},
ContentfulSpeedIndex: {
path: 'statistics.visualMetrics.ContentfulSpeedIndex.median',
summaryPath: 'visualMetrics.ContentfulSpeedIndex',
runPath: 'visualMetrics.ContentfulSpeedIndex',
name: 'Contentful Speed Index',
format: time.ms
},
PerceptualSpeedIndex: {
path: 'statistics.visualMetrics.PerceptualSpeedIndex.median',
summaryPath: 'visualMetrics.PerceptualSpeedIndex',
runPath: 'visualMetrics.PerceptualSpeedIndex',
name: 'Perceptual Speed Index',
format: time.ms
},
VisualReadiness: {
path: 'statistics.visualMetrics.VisualReadiness.median',
summaryPath: 'visualMetrics.VisualReadiness',
runPath: 'visualMetrics.VisualReadiness',
name: 'Visual Readiness',
format: time.ms
},
VisualComplete95: {
path: 'statistics.visualMetrics.VisualComplete95.median',
summaryPath: 'visualMetrics.VisualComplete95',
runPath: 'visualMetrics.VisualComplete95',
name: 'Visual Complete 95',
format: time.ms
},
VisualComplete99: {
path: 'statistics.visualMetrics.VisualComplete99.median',
summaryPath: 'visualMetrics.VisualComplete99',
runPath: 'visualMetrics.VisualComplete99',
name: 'Visual Complete 99',
format: time.ms
},
VisualComplete: {
path: 'statistics.visualMetrics.VisualComplete.median',
summaryPath: 'visualMetrics.VisualComplete',
runPath: 'visualMetrics.VisualComplete',
name: 'Visual Complete',
format: time.ms
}
@ -137,33 +158,61 @@ module.exports = {
totalBlockingTime: {
path: 'statistics.cpu.longTasks.totalBlockingTime.median',
summaryPath: 'cpu.longTasks.totalBlockingTime',
runPath: 'cpu.longTasks.totalBlockingTime',
name: 'Total Blocking Time',
format: time.ms
},
maxPotentialFid: {
path: 'statistics.cpu.longTasks.maxPotentialFid.median',
summaryPath: 'cpu.longTasks.maxPotentialFid',
runPath: 'cpu.longTasks.maxPotentialFid',
name: 'Max Potential FID',
format: time.ms
},
longTasks: {
path: 'statistics.cpu.longTasks.tasks.median',
summaryPath: 'cpu.longTasks.tasks',
runPath: 'cpu.longTasks.tasks',
name: 'Number of Long Tasks',
format: noop
},
longTasksTotalDuration: {
path: 'statistics.cpu.longTasks.totalDuration.median',
summaryPath: 'cpu.longTasks.totalDuration',
runPath: 'cpu.longTasks.totalDuration',
name: 'Total Duration of Long Tasks',
format: time.ms
}
},
browser: {
cpuBenchmark: {
path: 'statistics.browser.cpuBenchmark.median',
summaryPath: 'browser.cpuBenchmark',
runPath: 'browser.cpuBenchmark',
name: 'CPU benchmark score',
format: time.ms
}
},
pageinfo: {
cumulativeLayoutShift: {
path: 'statistics.pageinfo.cumulativeLayoutShift.median',
summaryPath: 'pageinfo.cumulativeLayoutShift',
runPath: 'pageinfo.cumulativeLayoutShift',
name: 'Cumulative Layout Shift',
format: decimals
},
domElements: {
path: 'statistics.pageinfo.domElements.median',
summaryPath: 'pageinfo.domElements',
runPath: 'pageinfo.domElements',
name: 'DOM elements',
format: noop
},
documentHeight: {
path: 'statistics.pageinfo.documentHeight.median',
summaryPath: 'pageinfo.documentHeight',
runPath: 'pageinfo.documentHeight',
name: 'Document height',
format: noop
}
}
@ -196,7 +245,11 @@ module.exports = {
name: 'Font Requests',
format: noop
},
httpErrors: { path: 'responseCodes', name: 'HTTP Errors', format: noop }
httpErrors: {
path: 'responseCodes',
name: 'HTTP Errors',
format: httpErrors
}
},
transferSize: {
total: {

View File

@ -0,0 +1,8 @@
'use strict';
module.exports = function(decimals) {
let number = Number(decimals).toFixed(3);
if (number === '0.000') {
return 0;
} else return number;
};

View File

@ -0,0 +1,11 @@
'use strict';
module.exports = function(httpCodes) {
let data = '';
for (let code of Object.keys(httpCodes)) {
if (Number(code) > 399) {
data += `${code}: ${httpCodes[code]} `;
}
}
return data === '' ? '0' : data;
};

View File

@ -12,5 +12,7 @@ module.exports = {
shortAsset: require('./shortAsset'),
co2: require('./co2'),
noop: require('./noop'),
percent: require('./percent')
percent: require('./percent'),
httpErrors: require('./httpErrors'),
decimals: require('./decimals')
};