前端日志监控系统备忘

一、前端错误的捕获

在 JavaScript 日志系统中,捕获错误的范围应该全面,涵盖前端应用中可能出现的各类问题,包括语法错误、运行时错误、资源加载错误以及用户行为异常等。以下是不同类型错误的捕获方法:

window.onerror: 可捕获常规错误(例如语法错误,变量未定义、函数调用错误等)、计时器的错误,但不能捕获资源加载错误、promise的错误

window.addEventListener('error',fn,true):dom2级事件,跟上面一样,但是可以捕获到资源加载错误,需将事件监听器的 useCapture 参数设为 true

// 使用捕获阶段捕获资源加载错误
window.addEventListener('error', function(event) {
    console.log('Error loading resource:', event.target);
}, true);

原因: 默认情况下,error 事件在事件传播的冒泡阶段触发,而浏览器的默认行为可能会使其无法触发。

unhandledrejection: 仅能捕获到Promise 的未处理拒绝(即没有使用.catch())、async代码中未显式抛出的错误(即没有throw,而是返回Promise.rect)

new Promise((_, reject) => reject(new Error('Promise Error')));
async function asyncError() {
return Promise.reject(new Error('Async Error'));
}
asyncError(); // 无法通过 window.onerror 捕获

try catch: 开发人员主动捕获特定业务场景中的错误,async内部代码块错误

performance.timing: 页面白屏或资源加载时间过长等问题

window.addEventListener('load', () => {
    const timing = performance.timing;
    const loadTime = timing.loadEventEnd - timing.navigationStart;
    if (loadTime > 3000) {
        console.warn('Page Load Slow:', loadTime);
        sendLog({ type: 'performance', loadTime });
    }
});

performance.memory: 内存泄露或占用过高(该api仅支持部分浏览器)

if (performance.memory) {
    setInterval(() => {
        const memoryUsage = performance.memory.usedJSHeapSize / 1024 / 1024;
        if (memoryUsage > 500) {
            console.warn('High Memory Usage:', memoryUsage);
            sendLog({ type: 'memory-warning', memoryUsage });
        }
    }, 5000);
}
 

二、日志系统的传输

1. new image().src = xxx : 发送简单的数据,例如点击次数等

2.navigator.sendBeacon():专门用于发送小量日志数据的 API,适合页面卸载时发送数据,且不会阻塞页面关闭。

优点

     性能优势sendBeacon 不会阻塞页面卸载过程,确保数据能够在页面跳转或关闭时被发送,而不影响页面的加载性能。

    可靠性:即使页面正在卸载,sendBeacon 也会尽量确保数据发送到服务器,因此它适用于发送需要持久化的数据(如日志、分析数据等)。

限制

     由于它的设计是为了发送小量数据,sendBeacon 发送的数据量相对较小(通常约为 64 KB);

     无响应回调::与 XMLHttpRequest 或 fetch 不同,sendBeacon 不返回一个 Promise 或回调,服务器的响应对用户而言没有任何影响。

3.XMLHttpRequestfetch:用于将日志数据发送到服务器。对于大多数日志数据传输,fetch 更为常用,因为它基于 Promise,更灵活且更现代。

三、日志系统的优化

1. 数据分批发送

将日志数据缓存到本地,在达到一定数量或条件时再发送。

实现方法1

  • 使用内存中的队列存储日志数据。
  • 当队列长度达到阈值(如 10 条)或时间间隔到达(如 1 分钟)时批量发送。
const logQueue = [];
const MAX_LOGS = 10;
const FLUSH_INTERVAL = 60000; // 1 minute

function addLog(log) {
    logQueue.push(log);
    if (logQueue.length >= MAX_LOGS) {
        sendLogs();
    }
}

function sendLogs() {
    if (logQueue.length === 0) return;
    fetch('https://log-server.com/logs', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(logQueue)
    }).then(() => {
        logQueue.length = 0; // Clear queue
    }).catch(err => console.error('Failed to send logs:', err));
}
// Periodic flush
setInterval(sendLogs, FLUSH_INTERVAL);

实现方法2

  • 利用 IndexedDB 或 localStorage 缓存数据。
  • 监听 navigator.onLine 状态。在网络断开时暂存日志,网络恢复后再批量发送
function saveLogToIndexedDB(log) {
    const request = indexedDB.open('LogDB', 1);

    request.onsuccess = function(event) {
        const db = event.target.result;
        const transaction = db.transaction(['logs'], 'readwrite');
        const store = transaction.objectStore('logs');
        store.add(log);
    };

    request.onupgradeneeded = function(event) {
        const db = event.target.result;
        db.createObjectStore('logs', { autoIncrement: true });
    };
}
window.addEventListener('online', sendLogs);

function sendLogs() {
    if (navigator.onLine) {
        // Read from localStorage and send
    }
}

2. 数据压缩后发送

 使用 JSON 压缩库(如 pako)对数据进行压缩,然后服务端解压数据

import pako from 'pako';
function compressLogs(logData) {
    const compressed = pako.gzip(JSON.stringify(logData));
    return compressed;
}
function sendLogsCompressed(logs) {
    const compressedLogs = compressLogs(logs);
    fetch('https://log-server.com/logs', {
        method: 'POST',
        headers: { 'Content-Encoding': 'gzip', 'Content-Type': 'application/json' },
        body: compressedLogs
    }).catch(err => console.error('Failed to send logs:', err));
}

3. 利用web worker避免阻塞主线程

通过 Web Worker 在后台处理日志收集和发送,避免阻塞主线程,主线程通过 postMessage 向 Worker 发送日志。

注意: Web Worker 运行在不同的线程中,因此它无法直接访问 window 对象及其相关的 Web API(如 sessionStoragelocalStorage 、XMLHttpRequest、navigator.sendBeacon等),只能使用fetch请求。

四、前端日志监控框架与平台 

  • Sentry:一个广泛使用的开源错误跟踪平台,支持 JavaScript 和其他前端框架的错误监控。
  • LogRocket:一个前端日志记录和会话回放平台,除了错误监控,还能记录用户的交互和性能数据。
  • Raygun:提供错误追踪、性能监控和用户行为分析的商业服务,支持前端和后端的日志管理
posted @ 2024-12-09 18:27  我是格鲁特  阅读(13)  评论(0编辑  收藏  举报