1:简历赋能
参与公司前端监控平台/监控SDK的架构设计和开发,为公司的业务赋能 独立设计和开发监控SDK,对前端页面的性能指标,错误信息 行为信息进行收集,采用合理的方式进行上报 内容:
2:为什么要自研做监控?为什么不用第三方的监控平台
-
定制化需求:自研监控系统可以根据团队的具体需求进行定制,捕捉特定的业务指标和异常情况。例如,某些特定的用户交互、性能指标、错误日志等,这些都可以通过自研监控系统实现精细化的监控。
-
数据隐私与安全:对于一些对数据隐私和安全要求高的企业,自研监控系统可以更好地控制数据的流向,确保敏感信息不会泄露到外部平台。
-
灵活性和扩展性:自研监控系统可以根据业务需求随时调整和扩展功能,而无需依赖第三方平台的更新和功能限制。
-
性能优化:通过自研监控系统,可以更加深入地了解应用的性能瓶颈和优化空间,从而提升整体应用的性能和用户体验。
-
业界有那些成熟的监控平台?
Sentry:主要用于错误监控和性能监控,可以帮助开发者快速发现和解决错误,支持多种编程语言和框架。
-
为什么不用第三方监控平台?
-
成本考虑:一些第三方监控平台收费较高,对于预算有限的团队,自研监控系统可以降低长期的使用成本。
-
依赖性问题:使用第三方监控平台意味着需要依赖外部服务,如果第三方平台出现故障或者停止服务,会对监控系统造成影响。
-
数据主权:对于一些敏感行业和企业,数据主权非常重要,企业希望完全掌控和管理自己的数据,而不希望数据被存储或处理在第三方平台上。
-
3:设计思路
一个完整的前端监控平台包括五个部分:数据采集与上报、数据分析和存储、数据展示 数据报警和监控
4:性能监控的收集
1:页面性能检测工具:Lighthouse chrome浏览器插件 2:[web-vitals](web-vitals - npm):[web-vitals - npm](web-vitals - npm) 官方指标标准**
指标 | 作用 | 标准 |
---|---|---|
FCP(First Contentful Paint) | 首次内容绘制时间 | 标准 ≤1s |
LCP(Largest Contentful Paint) | 最大内容绘制时间 | 标准 ≤2 秒 |
FID(first input delay) | 首次输入延迟,标准是用户触发后,到浏览器响应时间 | 标准 ≤100ms |
CLS(Cumulative Layout Shift) | 累积布局偏移 | 标准 ≤0.1 |
TTFB(Time to First Byte) | 页面发出请求,到接收第一个字节所花费的毫秒数(首字节时间) | 标准<= 100 毫秒 |
性能分析的,performance这个api的使用,和浏览器performance的定位
监测网页加载时长时关注的是以下5个过程 :
-
重定向时间 :获取此网页前重定向所花费的时间
-
DNS域名查找时间:查找此网页的 DNS 所花费的时间
-
TCP服务器链接时间:用户连接到您的服务器所需的时间
-
服务器响应时间:您的服务器响应用户请求所需的时间,其中包括从用户所在位置连接到您的服务器所需的网络时间
-
网页下载时间:下载网页所需的时间
-
// window.performance.timing 各字段说明 { navigationStart, // 同一个浏览器上下文中,上一个文档结束时的时间戳。如果没有上一个文档,这个值会和 fetchStart 相同。 unloadEventStart, // 上一个文档 unload 事件触发时的时间戳。如果没有上一个文档,为 0。 unloadEventEnd, // 上一个文档 unload 事件结束时的时间戳。如果没有上一个文档,为 0。 redirectStart, // 表示第一个 http 重定向开始时的时间戳。如果没有重定向或者有一个非同源的重定向,为 0。 redirectEnd, // 表示最后一个 http 重定向结束时的时间戳。如果没有重定向或者有一个非同源的重定向,为 0。 fetchStart, // 表示浏览器准备好使用 http 请求来获取文档的时间戳。这个时间点会在检查任何缓存之前。 domainLookupStart, // 域名查询开始的时间戳。如果使用了持久连接或者本地有缓存,这个值会和 fetchStart 相同。 domainLookupEnd, // 域名查询结束的时间戳。如果使用了持久连接或者本地有缓存,这个值会和 fetchStart 相同。 connectStart, // http 请求向服务器发送连接请求时的时间戳。如果使用了持久连接,这个值会和 fetchStart 相同。 connectEnd, // 浏览器和服务器之前建立连接的时间戳,所有握手和认证过程全部结束。如果使用了持久连接,这个值会和 fetchStart 相同。 secureConnectionStart, // 浏览器与服务器开始安全链接的握手时的时间戳。如果当前网页不要求安全连接,返回 0。 requestStart, // 浏览器向服务器发起 http 请求(或者读取本地缓存)时的时间戳,即获取 html 文档。 responseStart, // 浏览器从服务器接收到第一个字节时的时间戳。 responseEnd, // 浏览器从服务器接受到最后一个字节时的时间戳。 domLoading, // dom 结构开始解析的时间戳,document.readyState 的值为 loading。 domInteractive, // dom 结构解析结束,开始加载内嵌资源的时间戳,document.readyState 的状态为 interactive。 domContentLoadedEventStart, // DOMContentLoaded 事件触发时的时间戳,所有需要执行的脚本执行完毕。 domContentLoadedEventEnd, // DOMContentLoaded 事件结束时的时间戳 domComplete, // dom 文档完成解析的时间戳, document.readyState 的值为 complete。 loadEventStart, // load 事件触发的时间。 loadEventEnd; // load 时间结束时的时间。 }
FP、FCP、LCP、CLS、TTFB、FID 官方指标标准
指标 | 作用 | 标准 |
---|---|---|
FCP(First Contentful Paint) | 首次内容绘制时间 | 标准 ≤1s |
LCP(Largest Contentful Paint) | 最大内容绘制时间 | 标准 ≤2 秒 |
FID(first input delay) | 首次输入延迟,标准是用户触发后,到浏览器响应时间 | 标准 ≤100ms |
CLS(Cumulative Layout Shift) | 累积布局偏移 | 标准 ≤0.1 |
TTFB(Time to First Byte) | 页面发出请求,到接收第一个字节所花费的毫秒数(首字节时间) | 标准<= 100 毫秒 |
5:错误监控的收集
-
JS 代码运行错误、语法错误等
-
异步错误等
-
静态资源加载错误
-
接口请求报错
6:用户行为收集
// 创建用户行为类
class Behavior {
// maxBreadcrumbs控制上报用户行为的最大条数
maxBehaviors = 20;
// stack 存储用户行为
stack = [];
constructor() {}
// 添加用户行为栈
push(data) {
if (this.stack.length >= this.maxBehaviors) {
// 超出则删除第一条
this.stack.shift();
}
this.stack.push(data);
// 按照时间排序
this.stack.sort((a, b) => a.time - b.time);
}
}
let behavior = new Behavior();
// 添加一条页面跳转的行为,从home页面跳转到about页面
behavior.push({
type: "Route",
form: '/home',
to: '/about'
url: "http://localhost:9000/index.html",
time: "1668759320435"
});
// 添加一条用户点击行为
behavior.push({
type: "Click",
dom: "<button id='btn'>按钮</button>",
time: "1668759620485"
});
// 添加一条调用接口行为
behavior.push({
type: "Xhr",
url: "http://xxx.baidu.com/monitor/open/pushData",
time: "1668760485550"
});
// 上报用户行为
reportData({
uuid: "a6481683-6d2e-4bd8-bba1-64819d8cce8c",
stack: behavior.getStack()
});
7:数据上报
8:测试
sdk打包
webpack rollup
@babel/preset-env @rollup/plugin-babel @rollup/plugin-json rollup
跨域问题
window.addEventListener(
'error',
(error) => {
console.log('捕获到异常:', error);
},
true
);
// 当前页面加载其他域的资源,如https://www.test.com/index.js
<script src="https://www.test.com/index.js"></script>;
// 加载的https://www.test.com/index.js的代码
function fn() {
JSON.parse('');
}
fn();
报错信息
解决方法: 前端 script 加 crossorigin,后端配置 Access-Control-Allow-Origin
<script src="https://www.test.com/index.js" crossorigin></script>
如果不能修改服务端的请求头,可以考虑通过使用 try/catch 绕过,将错误抛出
<!doctype html>
<html>
<body>
<script src="https://www.test.com/index.js"></script>
<script>
window.addEventListener("error", error => {
console.log("捕获到异常:", error);
}, true );
try {
// 调用https://www.test.com/index.js中定义的fn方法
fn();
} catch (e) {
throw e;
}
</script>
</body>
</html>
其他
下面来介绍下上述字段的含义:
-
navigationStart:表示上一个文档卸载结束时的unix时间戳,如果没有上一个文档,则等于fetchStart。
-
unloadEventStart:表示前一个网页(与当前页面同域)unload的时间戳,如无前一个网页unloade或前一个网页与当前不同域,则为0。
-
unloadEventEnd: 返回前一个unload时间绑定的回调执行完毕的时间戳。
-
redirectStart:前一个Http重定向发送时的时间。有跳转且是同域名内重定向,否则为0。
-
redirectEnd:前一个Http重定向完成时的时间。有跳转且是同域名内重定向,否则为0。
-
fetchStart:浏览器准备使用http请求文档的时间,在检查本地缓存之前。
-
domainLookupStart/domainLookupEnd:DNS域名查询开始/结束的时间,如果使用本地缓存(则无需DNC查询)或持久链接,则和fetchStart一致。
-
connectStart:HTTP(TCP)开始或重新建立链接的时间,如果是持久链接,则和fetchStart一致。
-
connectEnd:HTTP(TCP)完成建立链接的时间(完成握手),如果是持久链接,则和fetchStart一致。
-
secureConnectionStart:Https链接开始的时间,如果不是安全链接则为0。
-
requestStart:http在建立链接之后,正式开始请求真实文档的时间,包括从本地读取缓存。
-
responseStart:http开始接收响应的时间(获取第一个字节),包括从本地读取缓存。
-
responseEnd:http响应接收完全的时间(最后一个字节),包括从本地读取缓存。
-
domLoading:开始解析渲染DOM树的时间。
-
domInteractive:完成解析DOM树的时间。
-
domContentLoadedEventStart:DOM解析完成后,页面内资源加载开始的时间。
-
domContentLoadedEventEnd:DOM解析完成后,网页内资源加载完成的时间(如js脚本加载执行完)
-
domComplete:DOM树解析完,资源也准备就绪。
-
loadEventStart:load事件发送给文档,即load函数开始执行时。
-
loadEventEnd:load函数执行完毕的时间。