前端监控

1.为什要做前端监控


  • 更快发现问题和解决问题
  • 做产品的决策依据
  • 提升前端工程师的技术深度和广度,打造简历亮点
  • 为业务扩展提供了更多可能性

2.前端监控目标


2.1 稳定性(stability)

错误名称 备注
JS错误 JS执行错误或者promise异常
资源异常 script、link等资源加载异常
接口错误 ajax或fetch请求接口异常
白屏 页面空白

2.2 用户体验(experience)

错误名称 备注
加载时间 各个阶段的加载时间
TTFB(time to first byte)(首字节时间) 是指浏览器发起第一个请求到数据返回第一个字节所消耗的时间,这个时间包含了网络请求时间、后端处理时间
FP(First Paint)(首次绘制) 首次绘制包括了任何用户自定义的背景绘制,它是将第一个像素点绘制到屏幕的时刻
FCP(First Content Paint)(首次内容绘制) 首次内容绘制是浏览器将第一个DOM渲染到屏幕的时间,可以是任何文本、图像、SVG等的时间
FMP(First Meaningful paint)(首次有意义绘制) 首次有意义绘制是页面可用性的量度标准
FID(First Input Delay)(首次输入延迟) 用户首次和页面交互到页面响应交互的时间
卡顿 超过50ms的长任务

2.3 业务(business)

错误名称 备注
PV page view 即页面浏览量或点击量
UV 指访问某个站点的不同IP地址的人数
页面的停留时间 用户在每一个页面的停留时间

3.前端监控流程


  • 前端埋点
  • 数据上报
  • 分析和计算 将采集到的数据进行加工汇总
  • 可视化展示 将数据按各种维度进行展示
  • 监控报警 发现问题后按一定的条件触发报警


3.1 常见的埋点方案

3.1.1 代码埋点

  • 代码埋点,就是以嵌入代码的形式进行埋点,比如需要监控用户的点击事件,会选择在用户点击时,插入一段代码,保存这个监听行为或者直接将监听行为以某一种数据格式直接传递给服务器端
  • 优点是可以在任意时刻,精确的发送或保存所需要的数据信息
  • 缺点是工作量较大

3.1.2 可视化埋点

  • 通过可视化交互的手段,代替代码埋点
  • 将业务代码和埋点代码分离,提供一个可视化交互的页面,输入为业务代码,通过这个可视化系统,可以在业务代码中自定义的增加埋点事件等等,最后输出的代码耦合了业务代码和埋点代码
  • 可视化埋点其实是用系统来代替手工插入埋点代码

3.1.3 无痕埋点

  • 前端的任意一个事件都被绑定一个标识,所有的事件都别记录下来
  • 通过定期上传记录文件,配合文件解析,解析出来我们想要的数据,并生成可视化报告供专业人员分析
  • 无痕埋点的优点是采集全量数据,不会出现漏埋和误埋等现象
  • 缺点是给数据传输和服务器增加压力,也无法灵活定制数据结构

4.编写监控采集脚本


4.1 开通日志服务

4.2 监控错误

4.2.1 错误分类

  • JS错误
    • JS错误
    • Promise异常
  • 资源异常
    • 监听error

4.2.2 数据结构设计

  1. jsError
{
  "title": "前端监控系统",//页面标题
  "url": "http://localhost:8080/",//页面URL
  "timestamp": "1590815288710",//访问时间戳
  "userAgent": "Chrome",//用户浏览器类型
  "kind": "stability",//大类
  "type": "error",//小类
  "errorType": "jsError",//错误类型
  "message": "Uncaught TypeError: Cannot set property 'error' of undefined",//类型详情
  "filename": "http://localhost:8080/",//访问的文件名
  "position": "0:0",//行列信息
  "stack": "btnClick (http://localhost:8080/:20:39)^HTMLInputElement.onclick (http://localhost:8080/:14:72)",//堆栈信息
  "selector": "HTML BODY #container .content INPUT"//选择器
}
  1. promiseError
{
  "title": "前端监控系统",//页面标题
  "url": "http://localhost:8080/",//页面URL
  "timestamp": "1590815290600",//访问时间戳
  "userAgent": "Chrome",//用户浏览器类型
  "kind": "stability",//大类
  "type": "error",//小类
  "errorType": "promiseError",//错误类型
  "message": "someVar is not defined",//类型详情
  "filename": "http://localhost:8080/",//访问的文件名
  "position": "24:29",//行列信息
  "stack": "http://localhost:8080/:24:29^new Promise (<anonymous>)^btnPromiseClick (http://localhost:8080/:23:13)^HTMLInputElement.onclick (http://localhost:8080/:15:86)",//堆栈信息
  "selector": "HTML BODY #container .content INPUT"//选择器
}

  1. resourceError
{
  "title": "前端监控系统",//页面标题
  "url": "http://localhost:8080/",//页面URL
  "timestamp": "1590816168643",//访问时间戳
  "userAgent": "Chrome",//用户浏览器类型
  "kind": "stability",//大类
  "type": "error",//小类
  "errorType": "resourceError",//错误类型
  "filename": "http://localhost:8080/error.js",//访问的文件名
  "tagName": "SCRIPT",//标签名
  "timeStamp": "76",//时间
  "selector": "HTML BODY SCRIPT"//选择器
}

4.2.3 实现
实现代码见项目

4.3.接口异常采集脚本

4.3.1 数据设计

{
  "title": "前端监控系统", //标题
  "url": "http://localhost:8080/", //url
  "timestamp": "1590817024490", //timestamp
  "userAgent": "Chrome", //浏览器版本
  "kind": "stability", //大类
  "type": "xhr", //小类
  "eventType": "load", //事件类型
  "pathname": "/success", //路径
  "status": "200-OK", //状态码
  "duration": "7", //持续时间
  "response": "{\"id\":1}", //响应内容
  "params": ""  //参数
}
{
  "title": "前端监控系统",
  "url": "http://localhost:8080/",
  "timestamp": "1590817025617",
  "userAgent": "Chrome",
  "kind": "stability",
  "type": "xhr",
  "eventType": "load",
  "pathname": "/error",
  "status": "500-Internal Server Error",
  "duration": "7",
  "response": "",
  "params": "name=aniu"
}

4.3.2 实现
实现代码见项目

4.4 白屏

  • 白屏就是页面上什么都没有

4.4.1 数据设计

{
  "title": "前端监控系统",
  "url": "http://localhost:8080/",
  "timestamp": "1590822618759",
  "userAgent": "chrome",
  "kind": "stability",      //大类
  "type": "blank",          //小类
  "emptyPoints": "0",       //空白点
  "screen": "2049x1152",    //分辨率
  "viewPoint": "2048x994",  //视口
  "selector": "HTML BODY #container" //选择器
}

4.4.2 实现

  • screen 返回当前window的screen对象,返回当前渲染窗口中和屏幕有关的属性
  • innerWidth 只读的 Window 属性 innerWidth 返回以像素为单位的窗口的内部宽度
  • innerHeight 窗口的内部高度(布局视口)的高度
  • layout_viewport
  • elementsFromPoint方法可以获取到当前视口内指定坐标处,由里到外排列的所有元素

实现代码见项目

4.5 加载时间

4.5.1 阶段含义

字段 含义
navigationStart 初始化页面,在同一个浏览器上下文中前一个页面unload的时间戳,如果没有前一个页面的unload,则与fetchStart值相等
redirectStart 第一个HTTP重定向发生的时间,有跳转且是同域的重定向,否则为0
redirectEnd 最后一个重定向完成时的时间,否则为0
fetchStart 浏览器准备好使用http请求获取文档的时间,这发生在检查缓存之前
domainLookupStart DNS域名开始查询的时间,如果有本地的缓存或keep-alive则时间为0
domainLookupEnd DNS域名结束查询的时间
connectStart TCP开始建立连接的时间,如果是持久连接,则与fetchStart值相等
secureConnectionStart https 连接开始的时间,如果不是安全连接则为0
connectEnd TCP完成握手的时间,如果是持久连接则与fetchStart值相等
requestStart HTTP请求读取真实文档开始的时间,包括从本地缓存读取
requestEnd HTTP请求读取真实文档结束的时间,包括从本地缓存读取
responseStart 返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的Unix毫秒时间戳
responseEnd 返回浏览器从服务器收到(或从本地缓存读取,或从本地资源读取)最后一个字节时的Unix毫秒时间戳
unloadEventStart 前一个页面的unload的时间戳 如果没有则为0
unloadEventEnd 与unloadEventStart相对应,返回的是unload函数执行完成的时间戳
domLoading 返回当前网页DOM结构开始解析时的时间戳,此时document.readyState变成loading,并将抛出readyStateChange事件
domInteractive 返回当前网页DOM结构结束解析、开始加载内嵌资源时时间戳,document.readyState 变成interactive,并将抛出readyStateChange事件(注意只是DOM树解析完成,这时候并没有开始加载网页内的资源)
domContentLoadedEventStart 网页domContentLoaded事件发生的时间
domContentLoadedEventEnd 网页domContentLoaded事件脚本执行完毕的时间,domReady的时间
domComplete DOM树解析完成,且资源也准备就绪的时间,document.readyState变成complete.并将抛出readystatechange事件
loadEventStart load 事件发送给文档,也即load回调函数开始执行的时间
loadEventEnd load回调函数执行完成的时间

4.5.2 阶段计算

字段 描述 计算方式 意义
unload 前一个页面卸载耗时 unloadEventEnd – unloadEventStart -
redirect 重定向耗时 redirectEnd – redirectStart 重定向的时间
appCache 缓存耗时 domainLookupStart – fetchStart 读取缓存的时间
dns DNS 解析耗时 domainLookupEnd – domainLookupStart 可观察域名解析服务是否正常
tcp TCP 连接耗时 connectEnd – connectStart 建立连接的耗时
ssl SSL 安全连接耗时 connectEnd – secureConnectionStart 反映数据安全连接建立耗时
ttfb Time to First Byte(TTFB)网络请求耗时 responseStart – requestStart TTFB是发出页面请求到接收到应答数据第一个字节所花费的毫秒数
response 响应数据传输耗时 responseEnd – responseStart 观察网络是否正常
dom DOM解析耗时 domInteractive – responseEnd 观察DOM结构是否合理,是否有JS阻塞页面解析
dcl DOMContentLoaded 事件耗时 domContentLoadedEventEnd – domContentLoadedEventStart 当 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,无需等待样式表、图像和子框架的完成加载
resources 资源加载耗时 domComplete – domContentLoadedEventEnd 可观察文档流是否过大
domReady DOM阶段渲染耗时 domContentLoadedEventEnd – fetchStart DOM树和页面资源加载完成时间,会触发domContentLoaded事件
首次渲染耗时 首次渲染耗时 responseEnd-fetchStart 加载文档到看到第一帧非空图像的时间,也叫白屏时间
首次可交互时间 首次可交互时间 domInteractive-fetchStart DOM树解析完成时间,此时document.readyState为interactive
首包时间耗时 首包时间 responseStart-domainLookupStart DNS解析到响应返回给浏览器第一个字节的时间
页面完全加载时间 页面完全加载时间 loadEventStart - fetchStart -
onLoad onLoad事件耗时 loadEventEnd – loadEventStart - -

4.5.3 数据结构

{
  "title": "前端监控系统",
  "url": "http://localhost:8080/",
  "timestamp": "1590828364183",
  "userAgent": "chrome",
  "kind": "experience",
  "type": "timing",
  "connectTime": "0",
  "ttfbTime": "1",
  "responseTime": "1",
  "parseDOMTime": "80",
  "domContentLoadedTime": "0",
  "timeToInteractive": "88",
  "loadTime": "89"
}

4.5.4 实现
实现代码见项目

4.6 性能指标

字段 描述 备注
FP First Paint(首次绘制) 包括了任何用户自定义的背景绘制,它是首先将像素绘制到屏幕的时刻
FCP First Content Paint(首次内容绘制) 是浏览器将第一个 DOM 渲染到屏幕的时间,可能是文本、图像、SVG等,这其实就是白屏时间
FMP First Meaningful Paint(首次有意义绘制) 页面有意义的内容渲染的时间
LCP (Largest Contentful Paint)(最大内容渲染) 代表在viewport中最大的页面元素加载的时间
DCL (DomContentLoaded)(DOM加载完成) 当 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,无需等待样式表、图像和子框架的完成加载
L (onLoad) 当依赖的资源全部加载完毕之后才会触发
TTI (Time to Interactive) 可交互时间 用于标记应用已进行视觉渲染并能可靠响应用户输入的时间点
FID First Input Delay(首次输入延迟) 用户首次和页面交互(单击链接,点击按钮等)到页面响应交互的时间

4.6.1 数据结构设计

  1. paint
{
  "title": "前端监控系统",
  "url": "http://localhost:8080/",
  "timestamp": "1590828364186",
  "userAgent": "chrome",
  "kind": "experience",
  "type": "paint",
  "firstPaint": "102",
  "firstContentPaint": "2130",
  "firstMeaningfulPaint": "2130",
  "largestContentfulPaint": "2130"
}
  1. firstInputDelay
{
  "title": "前端监控系统",
  "url": "http://localhost:8080/",
  "timestamp": "1590828477284",
  "userAgent": "chrome",
  "kind": "experience",
  "type": "firstInputDelay",
  "inputDelay": "3",
  "duration": "8",
  "startTime": "4812.344999983907",
  "selector": "HTML BODY #container .content H1"
}

4.6.2 实现
实现代码见项目

4.7 卡顿

  • 响应用户交互的响应时间如果大于100ms,用户就会感觉卡顿
    4.7.1 数据设计
{
  "title": "前端监控系统",
  "url": "http://localhost:8080/",
  "timestamp": "1590828656781",
  "userAgent": "chrome",
  "kind": "experience",
  "type": "longTask",
  "eventType": "mouseover",
  "startTime": "9331",
  "duration": "200",
  "selector": "HTML BODY #container .content"
}

4.7.2 实现
实现代码见项目

4.8 pv

  • netinfo
  • RTT(Round Trip Time)一个连接的往返时间,即数据发送时刻到接收到确认的时刻的差值
  • navigator.sendBeacon() 方法可用于通过HTTP将少量数据异步传输到Web服务器。

4.8.1 数据结构

{
  "title": "前端监控系统",
  "url": "http://localhost:8080/",
  "timestamp": "1590829304423",
  "userAgent": "chrome",
  "kind": "business",
  "type": "pv",
  "effectiveType": "4g",
  "rtt": "50",
  "screen": "2049x1152"
}

4.8.2 实现
实现代码见项目

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 背景 以往我们知道的监控都是服务端的监控,前端是少有被提及的,线上的页面什么时候挂掉,挂了多长时间,什么原因导致的...
    梦想成真213阅读 1,582评论 0 0
  • 前端埋点主要是为了服务运营人员采集用户行为数据,进行后续的数据分析工作。 前端监控和埋点能做什么 数据监控(用户行...
    猪蹄炖粥阅读 23,704评论 0 13
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,548评论 0 11
  • 彩排完,天已黑
    刘凯书法阅读 4,182评论 1 3
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 124,047评论 2 7