当前位置: 首页 > news >正文

前端小食堂 | Day16 - 前端监控の天眼通

👁️ 今日天眼:错误追踪与性能透视

1. 错误监控の捕虫网
// 🐞 全局错误捕获  
window.addEventListener('error', (e) => {  
  sendToServer({  
    type: 'JS_ERROR',  
    message: e.message,  
    stack: e.error?.stack,  
    filename: e.filename,  
    lineno: e.lineno  
  });  
});  

// 🌩️ Promise未捕获异常  
window.addEventListener('unhandledrejection', (e) => {  
  trackError({  
    type: 'PROMISE_REJECTION',  
    reason: e.reason?.message || String(e.reason)  
  });  
});  

// 🕸️ Vue组件错误边界  
app.config.errorHandler = (err, vm, info) => {  
  console.error('🔥 组件崩溃:', err, `触发位置: ${info}`);  
  sentry.captureException(err); // 接入Sentry  
};  

🔔 核心配置

  • 接入 Sentry/LogRocket 等专业工具
  • 自动记录用户操作路径
  • 生产环境开启 SourceMap 映射

2. 性能分析の时光机
// 🚀 关键性能指标采集  
const perfData = {  
  FP: performance.getEntriesByName('first-paint')[0]?.startTime,  
  FCP: performance.getEntriesByName('first-contentful-paint')[0]?.startTime,  
  LCP: performance.getEntriesByName('largest-contentful-paint')[0]?.startTime,  
  FID: performance.getEntriesByName('first-input-delay')[0]?.duration,  
};  

// 🧪 Performance Observer 监听  
const observer = new PerformanceObserver((list) => {  
  const entries = list.getEntries();  
  entries.forEach(entry => {  
    console.log(`📊 [${entry.name}]: ${entry.startTime.toFixed(2)}ms`);  
  });  
});  
observer.observe({ entryTypes: ['navigation', 'resource', 'paint'] });  

// 📈 资源加载统计  
const resources = performance.getEntriesByType('resource');  
const slowResources = resources.filter(r => r.duration > 1000);  

3. 用户体验温度计
// 😠 用户行为异常检测  
let rageClickCount = 0;  
useEventListener('click', (e) => {  
  if (e.target.closest('.error-message')) {  
    rageClickCount++;  
    if (rageClickCount > 3) {  
      trackEvent('RAGE_CLICK', { element: e.target.tagName });  
    }  
  }  
}, { passive: true });  

// ⏳ 长任务监控  
const longTasks = [];  
new PerformanceObserver(list => {  
  list.getEntries().forEach(entry => {  
    if (entry.duration > 50) {  
      longTasks.push(entry);  
      console.warn(`⚠️ 长任务阻塞 ${entry.duration.toFixed(2)}ms`);  
    }  
  });  
}).observe({ type: 'longtask', buffered: true });  

// 🌐 网络请求统计  
axios.interceptors.response.use(null, (error) => {  
  trackApiError(error.config.url, error.response?.status);  
  return Promise.reject(error);  
});  

❄️ 冷知识:Console 魔法咒语

// 🔍 精准调试定位  
console.log('%c🔥 关键数据:', 'color: #ff4757;', data); // 彩色日志  
console.table(dataList); // 表格展示  
console.trace('调用堆栈追踪'); // 堆栈跟踪  

// 🕵️ 条件式日志  
const debug = import.meta.env.DEV;  
const smartLog = debug ? console.log : () => {};  
smartLog('开发环境专属日志');  

// 🎯 性能标记  
performance.mark('searchStart');  
// ... 搜索逻辑 ...  
performance.mark('searchEnd');  
performance.measure('搜索耗时', 'searchStart', 'searchEnd');  

🌟 实验室天眼系统

实现简易监控 SDK

class MiniMonitor {  
  constructor() {  
    this.errors = [];  
    this.performance = {};  
    this.init();  
  }  

  init() {  
    // 错误监听  
    window.addEventListener('error', this.captureError.bind(this));  

    // 性能采集  
    window.addEventListener('load', () => {  
      this.performance = {  
        FP: performance.getEntriesByName('first-paint')[0]?.startTime,  
        FCP: performance.getEntriesByName('first-contentful-paint')[0]?.startTime,  
        LoadTime: performance.timing.loadEventEnd - performance.timing.navigationStart  
      };  
    });  

    // 心跳检测  
    setInterval(() => this.sendData(), 10000);  
  }  

  captureError(e) {  
    this.errors.push({  
      type: e.error ? 'JS_ERROR' : 'RESOURCE_ERROR',  
      message: e.message || e.target.src,  
      timestamp: Date.now()  
    });  
  }  

  sendData() {  
    navigator.sendBeacon('/api/monitor', {  
      errors: this.errors,  
      performance: this.performance  
    });  
    this.errors = [];  
  }  
}  

// 使用示例  
const monitor = new MiniMonitor();  

明日秘境:《前端安全の金钟罩——XSS/CSRF攻防战》 🛡️
(留言告诉我你遇到过最诡异的线上bug,本天眼师为你隔空诊断!🔭)


🛎️ 本日避坑指南

  1. 监控代码性能反噬
// ❌ 高频率无节制的日志  
window.addEventListener('mousemove', trackMouse);  

// ✅ 使用防抖 + 抽样  
const sampledTrack = sampleRate(  
  debounce(trackMouse, 300),  
  0.3 // 30%抽样率  
);  
  1. 敏感数据泄露
// 🚨 避免记录用户隐私  
const safeError = {  
  ...error,  
  message: error.message.replace(/password:.*/, '***')  
};  

// 🛡️ 生产环境屏蔽敏感日志  
if (process.env.NODE_ENV === 'production') {  
  console.log = () => {};  
}  
  1. SourceMap 安全
# 构建后自动上传SourceMap到监控平台  
sentry-cli releases --org myorg files myapp@1.0 upload-sourcemaps ./dist --url-prefix '~/static/js/'  
# 删除本地SourceMap  
rm ./dist/*.map  
  1. 错误分类策略
- `FATAL` : 导致页面崩溃  
- `ERROR` : 功能不可用  
- `WARN`  : 降级体验  
- `INFO`  : 用户行为记录  

🔮 监控指标速查表

指标全称健康阈值测量方式
FPFirst Paint<1sperformance.getEntriesByName('first-paint')
FCPFirst Contentful Paint<1.5sperformance.getEntriesByName('first-contentful-paint')
LCPLargest Contentful Paint<2.5sPerformanceObserver
FIDFirst Input Delay<100msPerformanceObserver
CLSCumulative Layout Shift<0.1LayoutShift API
TTFBTime to First Byte<800msperformance.timing.responseStart - navigationStart

相关文章:

  • 【leetcode100】全排列Ⅱ
  • 不像人做的题————十四届蓝桥杯省赛真题解析(上)A,B,C,D题解析
  • VSCode通过SSH远程登录Windows服务器
  • 《SQL编程思想》中的 MySQL 建表语句和测试数据
  • C++友元
  • 如何让ai问答机器人通人性?
  • 在离线情况下如何使用 Python 翻译文本
  • Windows-PyQt5安装+PyCharm配置QtDesigner + QtUIC
  • lanqiaoOJ 1180:斐波那契数列 ← 矩阵快速幂
  • 【接口封装】——22、读写文件
  • Vuex 核心功能与组件通信
  • ThreadLocal(线程本地存储)
  • C++进阶——map和set的使用
  • SpringBoot项目部署到宝塔面板的详细过程
  • 关于解决新版本spring项目请求测试接口返回406的问题
  • 当AI学会“察言观色“:多模态情绪识别的魔幻现实主义之旅
  • BGP路由属性和选路
  • 左叶子之和 找左下角的值 路径总和
  • Ollama+OpenWebUI本地部署大模型
  • 2025-03-15 Python深度学习2——Numpy库
  • 山东一景区怕游客赶不到海撒三千斤蛤蜊:给游客提供情绪价值
  • 美国季度GDP时隔三年再现负增长,特朗普政府关税政策对美国经济负面影响或将持续
  • 美乌签署协议建立美乌重建投资基金
  • 八成盈利,2024年沪市主板公司实现净利润4.35万亿元
  • 深入贯彻中央八项规定精神学习教育中央指导组派驻地方和单位名单公布
  • 我国首部《人工智能气象应用服务办法》今天发布