前端应用性能监控apm系统

467 阅读2分钟
  1. 目的

    衡量站点体验,留住用户,错误监控可以第一时间发现并修复问题。

  2. 功能

    • 监控错误异常
    • 异常issue分配处理人,处理状态显示
    • 解决情况显示
    • 异常报警可配置和提醒
    • 分析占比,趋势
  3. 特点

    • 非浸入式接入SDK(接入简单)
    • 异常问题记录详细
    • 采样可配置(功能:JS错误,请求监控,静态资源监控,页面加载性能)
  4. 衡量web体验指标

    • 站点体验指标
      • LCP (内容加载时间)2.5s内
      • FID (可交互时间) 100ms内
      • CLS (加载时体验) 0.1内
    • 站点错误指标
      • 边缘操作导致的故障,需监控Javascript错误、静态资源错误、请求错误,以及数量,错误率,影响用户数,影响用户比例等指标,存留错误,已解决错误,指派处理人。
  5. 实现

    • 实现指标

      • RUM(Real User Monitoring)指标,如FP,TTI,FMP,FID,MPFID
      • Navigation Timing 各阶段师表,如DNS,TCP,DOM解析等阶段时间
      • JS错误 分为运行时异常和静态资源异常
      • 请求状态码
    • 实现方法

      首先认识两个API:

      • window.performance

        Web Performance API 允许网页访问某些函数来测量网页和 Web 应用程序的性能,包括 Navigation Timing API 和高分辨率时间数据。

        performance.getEntries()可得到entry list performance.timing包括了页面相关的性能信息

      • PerformanceObserver

        • 打印事件时间
            const observer = new PerformanceObserver(function (list) {
            const perfEntries = list.getEntries().forEach((entry) => {
                // Full duration
                const inputDuration = entry.duration;
                // Input delay (before processing event)
                const inputDelay = entry.processingStart - entry.startTime;
                // Synchronous event processing time (between start and end dispatch).
                const inputSyncProcessingTime = entry.processingEnd - entry.processingStart;
                console.log(inputDelay,inputDelay,inputSyncProcessingTime)
            });
            });
            // Register observer for event.
            observer.observe({ entryTypes: ["event"] });
        

        随便找个网站点几下input框,打印如下: 截屏2022-07-24 15.45.06.png

        • 监测first-input
            // Keep track of whether (and when) the page was first hidden, see:
            // https://github.com/w3c/page-visibility/issues/29
            // NOTE: ideally this check would be performed in the document <head>
            // to avoid cases where the visibility state changes before this code runs.
            let firstHiddenTime = document.visibilityState === 'hidden' ? 0 : Infinity;
            document.addEventListener('visibilitychange', (event) => {
            firstHiddenTime = Math.min(firstHiddenTime, event.timeStamp);
            }, {once: true});
        
            // Sends the passed data to an analytics endpoint. This code
            // uses `/analytics`; you can replace it with your own URL.
            function sendToAnalytics(data) {
            const body = JSON.stringify(data);
            // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
            console.log(body)
            }
        
            // Use a try/catch instead of feature detecting `first-input`
            // support, since some browsers throw when using the new `type` option.
            // https://bugs.webkit.org/show_bug.cgi?id=209216
            try {
            function onFirstInputEntry(entry) {
                // Only report FID if the page wasn't hidden prior to
                // the entry being dispatched. This typically happens when a
                // page is loaded in a background tab.
                if (entry.startTime < firstHiddenTime) {
                const fid = entry.processingStart - entry.startTime;
        
                // Report the FID value to an analytics endpoint.
                sendToAnalytics({fid});
                }
            }
        
            // Create a PerformanceObserver that calls `onFirstInputEntry` for each entry.
            const po = new PerformanceObserver((entryList) => {
                entryList.getEntries().forEach(onFirstInputEntry);
            });
        
            // Observe entries of type `first-input`, including buffered entries,
            // i.e. entries that occurred before calling `observe()` below.
            po.observe({
                type: 'first-input',
                buffered: true,
            });
            } catch (e) {
            // Do nothing if the browser doesn't support this API.
            }
        

        继续测试: 截屏2022-07-24 15.58.19.png

      • RUM

        • 比如FID,和上面demo一样,通过PerformanceObserver监听first-input事件,通过 Event Timing API计算得到,其它类似。
            // Create the Performance Observer instance.
        
                const observer = new PerformanceObserver((list) => {
        
                for (const entry of list.getEntries()) {
        
                    const FID = entry.processingStart - entry.startTime;
        
                    console.log('FID:', FID);
        
                }
        
                });
        
        
        
                // Start observing first-input entries.
        
                observer.observe({
        
                type: 'first-input',
        
                buffered: true,
        
            });
        
      • Navigation Timing

        • 直接通过window.performance的相应值计算得到。比如加载时间
            function onLoad() {
        
                var now = new Date().getTime();
        
                var page_load_time = now - performance.timing.navigationStart;
        
                console.log("User-perceived page loading time: " + page_load_time);
        
            }
        
      • JS 错误

        • 通过window.onerror 监听js运行时错误,unhandledrejection监听promise rejections异步错误
      • 请求状态码,覆盖window.fetch和XMLHttpRequest对象来实现监听

  6. 参考文献

mp.weixin.qq.com/s/18jSRceR8… developer.mozilla.org/en-US/docs/…