With Web App Performance Monitoring
Maor Frankel
Real Users!
background: #story;
Real Time User Monitoring (RUM)
Real Data, Real Users, Real Time
"This is the time it takes the page to load. It begins when the navigation begins and ends when the webpage has completed loading in the user’s browser"
pageLoadTime = loadEventStart - navigationStart
Leverage our existing systems
"The High Resolution Time standard defines a Performance interface that supports client-side latency measurements within applications. "
const then = performance.now();
console.log(then) // 3157728.1249999944
(function doSomething() {
for(let i=0 ; i < 10000 ; i++){
///DO SOMETHING...
}
})()
const now = performance.now();
console.log(now) // 3158311.935000005
console.log((now - then)) // 583.8100000107661
Good
performance.mark('doSomething-start')
function doSomething() {
for(let i=0 ; i < 10000 ; i++){
///DO SOMETHING...
}
}
performance.mark('doSomething-end')
performance.measure('doSomething', 'doSomething-start', 'doSomething-end')
let marks = performance.getEntriesByName('doSomething', 'mark')
console.info(`${marks[1].startTime - marks[0].startTime}`) // 583.8100000107661
Better
<!doctype html>
<html>
<head lang="en">
<meta charset="UTF-8">
<base href='/'/>
<title>Outbrain - Amplify</title>
<script>
performance.mark('page-load-start');
</script>
<script>performance.mark('scripts-start');</script>
<script src="https://u.outbrain.com/static/vendor.87b3e412.js"></script>
<script src="https://u.outbrain.com/static/app.10f8627e.js"></script>
<script>performance.mark('scripts-end');</script>
setDatasource(dataSource) {
this.showGridLoadingOverlay()
performance.mark('reports-start')
}
whenGridRenderComplete() {
performance.mark('reports-end')
this.hideGridLoadingOverlay()
}
performance.measure('ob_css', 'css-start', 'css-end');
performance.measure('ob_scripts', 'scripts-start', 'scripts-end');
performance.measure('ob_total_page', 'total-page-start', 'reports-end');
const measures = performance.getEntriesByType('measure');
.filter(msr => msr.name.includes('ob_'))
.map(msr => {
return {
name: msr.name,
duration: parseInt(msr.duration),
speed: connection ? connection.effectiveType : ''
}
});
//Fall back to http post
navigator.sendBeacon('/performance-benchmark', { measures });
this.app.post('/performance-benchmark', this.performanceBenchmark.observe);
async observe(req: express.Request, res: express.Response) {
const events: BenchmarkEvent[] = this.parseEvents(req.body);
this.metrics[`${event.name}_country`].observe(
{
app: event.app,
browser: event.browser,
speed: event.speed,
country,
},
event.duration
)
})
return res.sendStatus(200);
}
Putting
it all together
Tracking
Memory Leaks
console.log(performance.memory);
// Would show, for example
{
jsHeapSizeLimit: 767557632,
totalJSHeapSize: 58054528,
usedJSHeapSize: 42930044
}
Performance.memory
const MAX_MEMORY_LIMIT = 1000 * 1048576; // 1000MB
setInterval(() => {
if(performance.memory.usedJsHeadSize > MAX_MEMORY_LIMIT){
//fire alert
}
}, 60000*30);
Performance.memory
http://tinyurl.com/y4y4b64j
@Mr_Frankel
@MrFrank