Mastering Front‑End Monitoring: From Performance to Error Alerts
This article provides a comprehensive guide to front‑end monitoring, covering performance metrics, exception alerts, daily inspections, instrumentation methods, data collection, log storage, and practical code examples for building a robust monitoring system that improves stability, user experience, and business insight.
Background
Need for front‑end monitoring at DeWu to detect page errors, provide alerts, and achieve end‑to‑end visibility.
Monitoring Types
Performance monitoring (load time, API response, web‑vitals)
Exception alert monitoring (JS errors, Promise rejections, resource errors)
Daily inspection (pre‑launch checks for white screens, API errors)
Monitoring Goals
Stability: capture JavaScript errors, unhandled Promise rejections, XHR/Fetch failures, resource loading errors.
User experience: collect TTFB, FP, FCP, FMP, LCP, FID, long‑task durations.
Business statistics: PV, UV, page stay time.
Monitoring Process
Instrumentation (code, visual, or invisible tracking)
Data reporting to a log service
Analysis and aggregation
Visualization by dimension
Alerting based on thresholds
Instrumentation Methods
Code instrumentation – explicit SDK calls in business code, e.g. this.$track('eventName', {...}). Precise but tightly coupled.
Visual instrumentation – UI for creating and binding tracking points without code changes.
Invisible (no‑trace) instrumentation – automatically binds identifiers to every DOM event and uploads raw logs; full coverage but adds network overhead.
Log Storage
Logs are sent to Alibaba Cloud Log Service via HTTP endpoint:
http://${project}.${host}/logstores/${logStore}/trackError Monitoring
Global error listener captures resource and script errors:
window.addEventListener('error', function(event) {
// send error data
}, true);Promise Rejection Monitoring
window.addEventListener('unhandledrejection', function(event) {
// send promise error data
}, true);XHR / Fetch Interception
Override XMLHttpRequest.open and .send to record request details and response time, then report:
export default function injectXHR() {
const XMLHttpRequest = window.XMLHttpRequest;
const prevOpen = XMLHttpRequest.prototype.open;
const prevSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
if (!url.match(/logstores/) && !url.match(/sockjs/)) {
this.logData = { method, url, async, username, password };
}
return prevOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(body) {
if (this.logData) {
this.logData.body = body;
const startTime = Date.now();
const handler = type => event => {
const duration = Date.now() - startTime;
tracker.send({
type: 'xhr',
eventType: type,
pathname: this.logData.url,
status: `${this.status} ${this.statusText}`,
duration: `${duration}`,
response: this.response ? JSON.stringify(this.response) : '',
params: body || ''
});
};
this.addEventListener('load', handler('load'), false);
this.addEventListener('error', handler('error'), false);
this.addEventListener('abort', handler('abort'), false);
}
return prevSend.apply(this, arguments);
};
}Blank‑Screen Detection
Samples 20 points in the viewport; if the topmost element at a point is a wrapper (e.g., body, html, #root, #App) the point is counted as empty. When empty points exceed a threshold, a blank‑screen log is sent.
export default function computedBlankScreen() {
const wrapperSelectors = ['body', 'html', '#root', '#App'];
let emptyPoints = 0;
function isWrapper(element) {
const selector = getSelector(element);
if (wrapperSelectors.indexOf(selector) >= 0) {
emptyPoints++;
}
}
onload(() => {
for (let i = 0; i <= 9; i++) {
const xEl = document.elementFromPoint(window.innerWidth * i / 10, window.innerHeight / 2);
const yEl = document.elementFromPoint(window.innerHeight * i / 10, window.innerWidth / 2);
isWrapper(xEl);
isWrapper(yEl);
}
if (emptyPoints > 0) {
tracker.send({ type: 'blankScreen' });
}
});
}Long‑Task (Stutter) Detection
Uses PerformanceObserver to watch longtask entries and reports tasks longer than 100 ms during idle periods.
export default function longTask() {
new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
if (entry.duration > 100) {
requestIdleCallback(() => {
tracker.send({
type: 'longTask',
startTime: entry.startTime,
duration: entry.duration
});
});
}
});
}).observe({ entryTypes: ['longtask'] });
}Performance Metrics Collection
Collects web‑vital metrics via performance.timing and related APIs (TTFB, FP, FCP, FMP, LCP, FID, etc.) for later analysis.
PV and Stay‑Time Tracking
export function pv() {
const connection = navigator.connection;
tracker.send({
type: 'pv',
networkType: connection.effectiveType,
rtt: connection.rtt,
screen: `${window.screen.width}x${window.screen.height}`
});
const startTime = Date.now();
window.addEventListener('unload', () => {
const stayTime = Date.now() - startTime;
tracker.send({ type: 'stayTime', stayTime });
}, false);
}Implementation Example
A minimal project ( frontend-monitor) can be built with Webpack. The core monitoring script is imported in the page and automatically registers the listeners above. Example webpack.config.js and a test index.html with buttons that trigger JS errors, Promise errors, successful and failing XHR requests are provided in the original source.
References
https://juejin.cn/post/6939703198739333127
https://wicg.github.io/largest-contentful-paint/
MDN PerformanceObserver, Long Tasks API, PerformanceTiming, Navigator
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
DeWu Technology
A platform for sharing and discussing tech knowledge, guiding you toward the cloud of technology.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
