前端日志記錄的核心在于捕獲錯誤、格式化日志信息并安全上報。1.使用window.onError、try…catch和unhandledrejection捕獲全局錯誤、特定代碼塊錯誤及promise rejection;2.通過formatlog定義日志格式,包含時間戳、日志級別、用戶信息、瀏覽器信息等;3.采用fetch或image beacon方式上報日志數據;4.處理敏感數據需脫敏、設置白名單、傳輸加密、服務器端過濾及獲取用戶授權;5.避免日志量過大應控制日志級別、采樣、批量上報、本地存儲及壓縮日志;6.利用performance api監控性能指標,并將其與日志關聯分析問題,也可借助sentry等工具實現自動化監控。
前端日志記錄,簡單來說,就是把你在瀏覽器里遇到的問題,用代碼記錄下來,然后傳給服務器,方便你或者你的團隊排查bug。
實現前端日志記錄,核心在于捕獲錯誤、格式化日志信息、以及安全可靠地上報日志。
解決方案
-
錯誤捕獲:
立即學習“前端免費學習筆記(深入)”;
-
window.onerror: 這個是全局的錯誤捕獲,任何未被try…catch捕獲的錯誤都會被這里捕獲。 你可以拿到錯誤信息、文件名、行號等。
window.onerror = function(message, source, lineno, colno, error) { console.error('全局錯誤捕獲:', message, source, lineno, colno, error); // 在這里可以進行日志上報 return true; // 阻止錯誤繼續向上冒泡,避免瀏覽器默認行為 };
-
try…catch: 針對特定代碼塊,可以更精確地捕獲錯誤。
try { // 可能會出錯的代碼 JSON.parse(someInvalidJson); } catch (e) { console.error('JSON解析錯誤:', e); // 在這里可以進行日志上報 }
-
Promise rejection: 未處理的Promise rejection也會導致問題。
window.addEventListener('unhandledrejection', function(event) { console.error('未處理的Promise rejection:', event.reason, event.promise); // 在這里可以進行日志上報 });
-
-
日志格式化:
-
你需要定義一個日志格式,包含時間戳、日志級別(info, warn, error等)、用戶信息(如果已登錄)、瀏覽器信息、頁面URL、錯誤信息等等。
function formatLog(level, message, data = {}) { return { timestamp: new Date().toISOString(), level: level, userAgent: navigator.userAgent, url: window.location.href, message: message, ...data // 其他自定義數據 }; } // 示例 const errorLog = formatLog('error', '用戶點擊按鈕失敗', { buttonId: 'myButton', userId: '123' }); console.log(errorLog);
-
-
日志上報:
-
fetch 或 XMLHttpRequest: 選擇一個你喜歡的方式,把日志數據發送到服務器。
async function sendLog(logData) { try { const response = await fetch('/api/logs', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(logData) }); if (!response.ok) { console.error('日志上報失敗:', response.status); } } catch (error) { console.error('日志上報發生異常:', error); } } // 使用示例 sendLog(errorLog);
-
Image Beacon: 一種更輕量級的上報方式,通過創建一個Image對象,并設置src屬性來發送數據。 這種方式不會阻塞頁面加載,但數據量有限。
function sendLogWithImage(logData) { const img = new Image(); img.src = `/api/logs?data=${encodeURIComponent(JSON.stringify(logData))}`; // 注意URL長度限制 } // 使用示例 sendLogWithImage(errorLog);
-
如何處理敏感數據,避免用戶信息泄露?
在日志記錄中處理敏感數據是個大問題。 絕對不能直接上傳用戶的密碼、信用卡信息等。 以下是一些建議:
-
數據脫敏: 對敏感數據進行脫敏處理。 例如,只記錄用戶ID,而不是用戶名和密碼。 對手機號、身份證號等進行部分遮蔽。
-
白名單/黑名單: 只允許記錄特定類型的日志,或者禁止記錄某些類型的日志。 例如,可以禁止記錄包含特定關鍵詞(如“password”)的日志。
-
傳輸加密: 使用https協議進行數據傳輸,確保數據在傳輸過程中不被竊取。
-
服務器端處理: 在服務器端對接收到的日志數據進行進一步的清洗和過濾,確保敏感數據不被存儲。
-
用戶授權: 在某些情況下,可能需要征得用戶的同意才能記錄他們的行為。 例如,如果需要記錄用戶的點擊流,應該明確告知用戶,并提供退出選項。
如何避免日志量過大,影響性能?
大量的日志會顯著影響前端性能,并增加服務器的存儲壓力。 可以考慮以下策略:
-
日志級別控制: 只記錄重要的日志,例如錯誤日志和警告日志。 可以根據環境(開發環境、測試環境、生產環境)調整日志級別。
-
采樣: 只記錄一部分日志。 例如,可以只記錄1%的錯誤日志。
-
批量上報: 不要每產生一條日志就立即上報,而是將日志緩存起來,達到一定數量或時間間隔后再批量上報。 可以使用requestIdleCallback在瀏覽器空閑時執行上報操作。
-
本地存儲: 將日志先存儲在本地,例如使用localStorage或IndexedDB,然后在合適的時機上報。 這樣可以避免網絡不穩定導致日志丟失。
-
日志壓縮: 在上報日志之前,對日志數據進行壓縮,例如使用gzip算法。
如何監控前端性能指標,并將性能數據與日志關聯?
除了錯誤日志,前端性能指標也是非常重要的信息。 可以使用Performance API來收集性能數據,例如頁面加載時間、首屏渲染時間、資源加載時間等。
-
Performance API: Performance API提供了豐富的性能指標。
const performance = window.performance; if (performance) { const timing = performance.timing; const loadTime = timing.loadEventEnd - timing.navigationStart; console.log('頁面加載時間:', loadTime); // 更多指標... }
-
與日志關聯: 將性能數據與日志關聯起來,可以更方便地分析問題。 例如,可以在錯誤日志中包含頁面加載時間等信息。
-
監控工具: 使用專業的前端監控工具,例如Sentry、Fundebug等。 這些工具可以自動收集性能數據和錯誤日志,并提供強大的分析功能。 很多工具也支持自定義指標上報。