前端监听SDK(上报埋点数据)

news/2024/11/28 5:35:03/

1、使用方式

<head><script>window.pineapple || (pineapple = {});pineapple.param = {"src": "http://127.0.0.1:3001/pa.gif","token": "dsadasd2323dsad23dsada",};</script><script src="js/pineapple.js"></script>
</head>

2、上报SDK封装

使用image的形式进行接口数据传输

(function(window) {'use strict';/*** https://developer.mozilla.org/zh-CN/docs/Web/API/Window/performance*/var performance = window.performance || window.webkitPerformance || window.msPerformance || window.mozPerformance || {};performance.now = (function() {return performance.now    ||performance.webkitNow     ||performance.msNow         ||performance.oNow          ||performance.mozNow        ||function() { return new Date().getTime(); };})();/*** 默认属性*/var defaults = {performance: performance,   // performance对象ajaxs: [],                  //ajax监控//可自定义的参数param: {rate: 0.5,              //随机采样率src: 'http://127.0.0.1:3001/pa.gif'                 //请求发送数据}};if(window.pineapple.param) {for(var key in window.pineapple.param) {defaults.param[key] = window.pineapple.param[key];}}var pineapple = defaults;var firstScreenHeight = window.innerHeight;         //第一屏高度var doc = window.document;// 定义的错误类型码var ERROR_RUNTIME = 1var ERROR_SCRIPT = 2var ERROR_STYLE = 3var ERROR_IMAGE = 4var ERROR_AUDIO = 5var ERROR_VIDEO = 6var ERROR_PROMISE = 7var LOAD_ERROR_TYPE = {SCRIPT: ERROR_SCRIPT,LINK: ERROR_STYLE,IMG: ERROR_IMAGE,AUDIO: ERROR_AUDIO,VIDEO: ERROR_VIDEO};/*** 上报错误* @param  {Object} errorLog    错误日志*/function handleError (errorLog) {// console.log(errorLog);pineapple.sendError(errorLog);}/*** 监控资源异常* https://github.com/BetterJS/badjs-report*/window.addEventListener("error", function(event) {var errorTarget = event.target// 过滤 target 为 window 的异常if (errorTarget !== window && errorTarget.nodeName && LOAD_ERROR_TYPE[errorTarget.nodeName.toUpperCase()]) {handleError(formatLoadError(errorTarget))} else {handleError(formatRuntimerError(event.message, event.filename, event.lineno, event.colno, event.error))}}, true);/*** 监控未处理的Promise错误* 当 Promise 被 reject 且没有 reject 处理器时触发*/window.addEventListener("unhandledrejection", function(event) {// console.log('Unhandled Rejection at:', event.promise, 'reason:', event.reason);handleError({type: ERROR_PROMISE,desc: event.reason,stack: 'no stack'});}, true);/*** 生成 laod 错误日志* 需要加载资源的元素* @param  {Object} errorTarget*/function formatLoadError (errorTarget) {return {type: LOAD_ERROR_TYPE[errorTarget.nodeName.toUpperCase()],desc: errorTarget.baseURI + '@' + (errorTarget.src || errorTarget.href),stack: 'no stack'};}/*** 生成 runtime 错误日志* @param {String}  message      错误信息* @param {String}  filename     出错文件的URL* @param {Long}    lineno       出错代码的行号* @param {Long}    colno        出错代码的列号* @param {Object}  error        错误信息Object* https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Error*/function formatRuntimerError (message, filename, lineno, colno, error) {return {type: ERROR_RUNTIME,desc: message + ' at ' + filename + ':' + lineno + ':' + colno,stack: error && error.stack ? error.stack.replace(/\n/gi, "") : 'no stack'      // IE <9, has no error stack};}/*** ajax监控* https://github.com/HubSpot/pace*/var _XMLHttpRequest = window.XMLHttpRequest;        //保存原生的XMLHttpRequest//覆盖XMLHttpRequestwindow.XMLHttpRequest = function(flags) {var req;req = new _XMLHttpRequest(flags);   //调用原生的XMLHttpRequestmonitorXHR(req);                    //埋入我们的“间谍”return req;};var monitorXHR = function(req) {req.ajax = {};//var _change = req.onreadystatechange;req.addEventListener('readystatechange', function() {if(this.readyState == 4) {req.ajax.end = pineapple.now();     //埋点if ((req.status >= 200 && req.status < 300) || req.status == 304 ) {    //请求成功req.ajax.endBytes = _kb(req.responseText.length * 2);               //KB//console.log('响应数据:'+ req.ajax.endBytes);//响应数据大小}else {     //请求失败req.ajax.endBytes = 0;}req.ajax.interval = req.ajax.end - req.ajax.start;pineapple.ajaxs.push(req.ajax);//console.log('ajax响应时间:'+req.ajax.interval);}}, false);// “间谍”又对open方法埋入了间谍var _open = req.open;req.open = function(type, url, async) {req.ajax.type = type;       //埋点req.ajax.url = url;         //埋点return _open.apply(req, arguments);};var _send = req.send;req.send = function(data) {req.ajax.start = pineapple.now();   //埋点var bytes = 0;                      //发送数据大小if(data) {req.ajax.startBytes = _kb(JSON.stringify(data).length * 2 );}return _send.apply(req, arguments);};};/*** 计算KB值* http://stackoverflow.com/questions/1248302/javascript-object-size*/function _kb(bytes) {return _rounded(bytes / 1024, 2);       //四舍五入2位小数}/*** 四舍五入*/function _rounded(number, decimal) {return parseFloat(number.toFixed(decimal));}/*** 给所有在首屏的图片绑定load事件,计算载入时间* TODO 忽略了异步加载* CSS背景图 是显示的在param参数中设置backgroundImages图片路径数组加载*/var imgLoadTime = 0;function _setCurrent() {var current = Date.now();current > imgLoadTime && (imgLoadTime = current);}doc.addEventListener('DOMContentLoaded', function() {var imgs = doc.querySelectorAll('img');imgs = [].slice.call(doc.querySelectorAll('img'));if(imgs) {imgs.forEach(function(img) {if(img.getBoundingClientRect().top > firstScreenHeight) {return;}//	    	var image = new Image();//      	image.src = img.getAttribute('src');if(img.complete) {_setCurrent();}//绑定载入时间img.addEventListener('load', function() {_setCurrent();}, false);});}//在CSS中设置了BackgroundImage背景if(pineapple.param.backgroundImages) {pineapple.param.backgroundImages.forEach(function(url) {var image = new Image();image.src = url;if(image.complete) {_setCurrent();}image.onload = function() {_setCurrent();};});}}, false);/*** 递归的将数字四舍五入小数点后两位*/function handleNumber(obj) {var type = typeof obj;if(type === "object" && type !== null) {for(var key in obj) {obj[key] = handleNumber(obj[key]);}}if(type === "number") {return _rounded(obj, 2);}return obj;}window.addEventListener('load', function() {setTimeout(function() {var time = pineapple.getTimes();var data = handleNumber({ ajaxs:pineapple.ajaxs, dpi:pineapple.dpi(), time:time, network:pineapple.network() });console.log("data", data);pineapple.send(data);}, 500);});/*** 打印特性 key:value格式*/pineapple.print = function(obj, left, right, filter) {var list = [], left = left || '', right = right || '';for(var key in obj) {if(filter) {if(filter(obj[key]))list.push(left + key + ':' + obj[key] + right);}else {list.push(left + key + ':' + obj[key] + right);}}return list;};/*** 请求时间统计* 需在window.onload中调用* https://github.com/addyosmani/timing.js*/pineapple.getTimes = function() {var timing = performance.timing;if (timing === undefined) {return false;}var api = {};//存在timing对象if (timing) {// All times are relative times to the start time within the// 白屏时间,也就是开始解析DOM耗时var firstPaint = 0;// Chrome chrome.loadTimes()已废弃// if (window.chrome && window.chrome.loadTimes) {// 	var chromeLoad = window.chrome.loadTimes();// 	// Convert to ms// 	firstPaint = chromeLoad.firstPaintTime * 1000;// 	api.firstPaintTime = firstPaint - (chromeLoad.startLoadTime * 1000);// }// IEif (typeof timing.msFirstPaint === 'number') {firstPaint = timing.msFirstPaint;api.firstPaintTime = firstPaint - timing.fetchStart;}else {api.firstPaintTime = currentTime - timing.fetchStart;}// Firefox// This will use the first times after MozAfterPaint fires//else if (window.performance.timing.fetchStart && typeof InstallTrigger !== 'undefined') {//    api.firstPaint = window.performance.timing.fetchStart;//    api.firstPaintTime = mozFirstPaintTime - window.performance.timing.fetchStart;//}/*** http://javascript.ruanyifeng.com/bom/performance.html* 加载总时间* 这几乎代表了用户等待页面可用的时间* loadEventEnd(加载结束)-navigationStart(导航开始)*/api.loadTime = timing.loadEventEnd - timing.navigationStart;/*** Unload事件耗时*/api.unloadEventTime = timing.unloadEventEnd - timing.unloadEventStart;/*** 执行 onload 回调函数的时间* 是否太多不必要的操作都放到 onload 回调函数里执行了,考虑过延迟加载、按需加载的策略么?*/api.loadEventTime = timing.loadEventEnd - timing.loadEventStart;/*** 用户可操作时间*/api.domReadyTime = timing.domContentLoadedEventEnd - timing.fetchStart;/*** 首屏时间* 用户在没有滚动时候看到的内容渲染完成并且可以交互的时间* 记录载入时间最长的图片*/if(imgLoadTime == 0) {api.firstScreen = api.domReadyTime;}else {api.firstScreen = imgLoadTime - timing.fetchStart;}/*** 解析 DOM 树结构的时间* 期间要加载内嵌资源* 反省下你的 DOM 树嵌套是不是太多了*/api.parseDomTime = timing.domComplete - timing.domInteractive;/*** 请求完毕至DOM加载耗时*/api.initDomTreeTime = timing.domInteractive - timing.responseEnd;/*** 准备新页面时间耗时*/api.readyStart = timing.fetchStart - timing.navigationStart;/*** 重定向的时间* 拒绝重定向!比如,http://example.com/ 就不该写成 http://example.com*/api.redirectTime = timing.redirectEnd - timing.redirectStart;/*** DNS缓存耗时*/api.appcacheTime = timing.domainLookupStart - timing.fetchStart;/*** DNS查询耗时* DNS 预加载做了么?页面内是不是使用了太多不同的域名导致域名查询的时间太长?* 可使用 HTML5 Prefetch 预查询 DNS ,见:[HTML5 prefetch](http://segmentfault.com/a/1190000000633364)*/api.lookupDomainTime = timing.domainLookupEnd - timing.domainLookupStart;/*** SSL连接耗时*/var sslTime = timing.secureConnectionStart;api.connectSslTime = sslTime > 0 ? (timing.connectEnd - sslTime) : 0;/*** TCP连接耗时*/api.connectTime = timing.connectEnd - timing.connectStart;/*** 内容加载完成的时间* 页面内容经过 gzip 压缩了么,静态资源 css/js 等压缩了么?*/api.requestTime = timing.responseEnd - timing.requestStart;/*** 请求文档* 开始请求文档到开始接收文档*/api.requestDocumentTime = timing.responseStart - timing.requestStart;/*** 接收文档(内容传输耗时)* 开始接收文档到文档接收完成*/api.responseDocumentTime = timing.responseEnd - timing.responseStart;/*** 读取页面第一个字节的时间* 这可以理解为用户拿到你的资源占用的时间,加异地机房了么,加CDN 处理了么?加带宽了么?加 CPU 运算速度了么?* TTFB 即 Time To First Byte 的意思* 维基百科:https://en.wikipedia.org/wiki/Time_To_First_Byte*/api.TTFB = timing.responseStart - timing.fetchStart;}return api;};/*** 与performance中的不同,仅仅是做时间间隔记录* https://github.com/nicjansma/usertiming.js*/var marks = {};pineapple.mark = function(markName) {var now = performance.now();marks[markName] = {startTime: Date.now(),start: now,duration: 0};};/*** 计算两个时间段之间的时间间隔*/pineapple.measure = function(startName, endName) {var start = 0, end = 0;if(startName in marks) {start = marks[startName].start;}if(endName in marks) {end = marks[endName].start;}return {startTime: Date.now(),start: start,end: end,duration: (end - start)};};/*** 标记时间* Date.now() 会受系统程序执行阻塞的影响不同* performance.now() 的时间是以恒定速率递增的,不受系统时间的影响(系统时间可被人为或软件调整)*/pineapple.now = function() {return performance.now();};/*** 网络状态* https://github.com/daniellmb/downlinkMax* http://stackoverflow.com/questions/5529718/how-to-detect-internet-speed-in-javascript*/pineapple.network = function() {//2.2--4.3安卓机才可使用var connection = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection,effectiveType = connection.effectiveType;if(effectiveType) {return {bandwidth: 0, type: effectiveType.toUpperCase()};}var types = "Unknown Ethernet WIFI 2G 3G 4G".split(" ");var info = {bandwidth: 0, type: ""};if(connection && connection.type) {info.type = types[connection.type];}return info;};/*** 分辨率*/pineapple.dpi = function() {return {width:window.screen.width, height:window.screen.height};};/*** 组装变量* https://github.com/appsignal/appsignal-frontend-monitoring*/function _paramify(obj) {obj.token = pineapple.param.token;return JSON.stringify(obj);}/*** 推送统计信息*/pineapple.send = function(data) {var ts = new Date().getTime().toString();//采集率if(pineapple.param.rate > Math.random(0, 1)) {var img = new Image(0, 0);img.src = pineapple.param.src +"?data=" + _paramify(data) + "&ts=" + ts;}};/*** 推送错误信息*/pineapple.sendError = function(data) {var ts = new Date().getTime().toString();var img = new Image(0, 0);img.src = pineapple.param.src +"?error=" + _paramify(data) + "&ts=" + ts;};var currentTime = Date.now();       //这个脚本执行完后的时间 计算白屏时间window.pineapple = pineapple;
})(this);


http://www.ppmy.cn/news/1086769.html

相关文章

lv3 嵌入式开发-1linux介绍及环境配置

目录 1 UNIX、Linux和GNU简介 2 环境介绍 3 VMwareTools配置 4 vim配置&#xff1a; 5 网络配置 1 UNIX、Linux和GNU简介 什么是UNIX? unix是一个强大的多用户、多任务操作系统&#xff0c;支持多种处理器架构 中文名 尤尼斯 外文名 UNIX 本质 操作系统 类型 分…

系统架构设计师考试论文:论软件架构风格与应用

软件体系结构风格是描述某一特定应用领域中系统组织方式的惯用模式。体系结构风格定义一个系统家族&#xff0c;即一个体系结构定义一个词汇表和一纽约束。词汇表中包含一些构件和连接件类型&#xff0c;而这组约束指出系统是如何将这些构件和连接件组合起来的。体系结构风格反…

调整网络的工作流程

最近需要调整网络&#xff0c;涉及整个网络的Vlan修改&#xff0c;工作量其实不小。虽然不是一件很技术性的事情&#xff0c;但是如果没有准备&#xff0c;调整后可能会出现各式各样的怪问题&#xff0c;那手忙脚乱地影响了生产和办公就麻烦大了。   为了避免可能出现的问题&…

哈希表HashMap(基于vector和list)

C数据结构与算法实现&#xff08;目录&#xff09; 1 什么是HashMap&#xff1f; 我们这里要实现的HashMap接口不会超过标准库的版本&#xff08;是一个子集&#xff09;。 HashMap是一种键值对容器&#xff08;关联容器&#xff09;&#xff0c;又叫字典。 和其他容易一样…

win10安装vmware17 pro和centos7及配置

1.下载地址 https://www.bear20.com/pcwin/153/725878653.htmlhttps://www.ittel.cn/archives/12099.html #以下许可证 选择其一即可 4A4RR-813DK-M81A9-4U35H-06KND NZ4RR-FTK5H-H81C1-Q30QH-1V2LA JU090-6039P-08409-8J0QH-2YR7F 4Y09U-AJK97-089Z0-A3054-83KLA 4C21U-2KK9Q-…

根据需求生成一个Vue模块的类图示例

以下是一个Vue模块的类图示例&#xff1a; ------------------------ | VueModule | ------------------------ | -name: string | | -data: object | | -methods: object | | -computed: object | | -watchers: object | ---…

NPM 常用命令(二)

目录 1、npm bugs 1.1 配置 browser registry 2、npm cache 2.1 概要 2.2 详情 2.3 关于缓存设计的说明 2.4 配置 cache 3、 npm ci 3.1 描述 3.2 配置 install-strategy legacy-bundling global-style omit strict-peer-deps foreground-scripts ignore-s…

ArrayList、LinkedList、Collections.singletonList、Arrays.asList与ImmutableList.of

文章目录 ListArrayListLinkedListArrayList与LinkedList的区别快速构建list集合Collections.singletonListArrays.asListImmutableList.of Java集合类型有三种&#xff1a;set(集)、list(列表)和map(映射)&#xff0c;而List集合是很常用的一种集合类型&#xff0c; List 我…