saijs / sai.js Goto Github PK
View Code? Open in Web Editor NEW通用前端监控采集脚本
Home Page: http://spmjs.io/docs/sai/
通用前端监控采集脚本
Home Page: http://spmjs.io/docs/sai/
避免 define cmd module 的定义中抛出异常,seajs 的函数调用链出现无限递归。
monitor.log(productLine, product, errorCode)
已经没有在实际使用,取消监控日志的发送。
这个用的是哪个?
包括 #17 中提到的页面 ID,还有其他可能需要用到的非通用数据,比如需要跟服务端 Session 关联的 cookie/SessionID 信息,这些都可以有最佳实践,但每个场景的需要都不相同,不应该内置。
因此考虑提供事件发布机制,用户在需要时,可以扩展自定义数据。
seajs.use("monitor", function(monitor){
monitor.on("jserror", function(data){
data.pageid = "{PAGE_ID}";
data.cookieid = "{COOKIE_ID}";
});
monitor.boot();
});
<meta name="system-name" content="$!systemUtil.hostInfo.name" />
monitor.on("*", function(meta){
var content = $("meta[name=system-name]").attr("content");
var sysName = content.split(/[\-\.]/)[0];
meta.sys = systemName;
});
path(ref)
部分浏览器可以通过间接手段拿到列号信息,这部分对应后续的 source map 非常有用。
预留提供列号字段。
stacktrace 可能会出现换行符,导致日志换行,影响数据处理。
收银台等特殊系统对页面性能有较高要求,而且本身的代码性能不佳,可能会在加在页面最底部 use 的 monitor 脚本之后才加载完成并执行,因此考虑将启动脚本改造如下:
function _use_monitor(){
if(!window.seajs){return;}
seajs.use("$", function($){
$(function(){
// 命中率:[0,1]: 实际对应采样率:[0%,100%]
// 注意:sens_rate 跟 sens_rate 是有关联的。
// 实际设置的内容时,应该参考以下算法:
// 敏感信息监控实际采样率 = sens_rate * jserr_rate;
var jserr_rate = $MONITOR_JSERROR_RATE;
var sens_rate = $MONITOR_SENSINFO_RATE;
/**
* 随机采样命中算法。
* @param {Nuber} rate, 采样率,[0,1] 区间的数值。
* @return {Boolean}
*/
function hit(rate){
return 0 === Math.floor(Math.random() / rate);
}
if(!hit(jserr_rate)){return;}
seajs.use(["monitor/2.1.0/monitor", "sensinfo/1.2.0/sensinfo"],
function(monitor, sensinfo){
if(!monitor || !monitor.boot){return;}
monitor.boot(); // 启动监控。
if(!hit(sens_rate) || !sensinfo){return;}
try{
var html = (document.documentElement || document.body).innerHTML;
sensinfo.scan(html, {
"*": function(cardType, privacy_card, context) {
monitor.log(cardType+"="+privacy_card+"```"+context, "sens");
}
});
}catch(ex){}
});
});
});
}
if(window._monitor_autoload !== false){
_use_monitor();
}
对于收银台这种可以在前面设置 var _monitor_autoload = false;
并在适当的时机 _use_monitor()
。
在 IE 浏览器中不同用户语言环境抛出的异常消息不同,虽然有将异常消息统一使用英文的提案,但目前来说,收集语种信息,对于识别异常消息非常有利。
lang = navigator.language || navigator.browserLanguage;
兼容模式对脚本引擎影响较大,因此考虑增加浏览器兼容模式信息。
IE 浏览器可以通过比对浏览器和渲染引擎版本得出是否为兼容模式的信息,但其他 Trident 引擎的非 IE 浏览器无法通过这个得知。
兼容模式信息在 clnt 字段之内的最后。考虑到兼容模式是非主流数据,因此只在兼容模式下添加兼容性信息。后续如果需要在 clnt 中附加其他信息再考虑是否补全。
//clnt=device/device_version|os|os_version|browser/browser_version|engine/engine_version|compatible
clnt=pc/-1|windows/6.1|ie/9.0|trident/5.0
clnt=pc/-1|windows/6.1|ie/9.0|trident/3.0|c
现在的 monitor.log 传参使用固定的参数格式,导致需要扩展参数比较困难。
经过思考决定让 log API 支持传入键值对的参数,可以根据键值指定扩展参数名。
同时兼容旧有传参方式。
/^file:\/\/\//
特殊的,WebApp 打包到本地的页面是 file 协议。 策略:打包到本地的页面,也通过将 monitor.js 打包到本地,并针对性处理的方式。/^\w:\\/
例如:C:\windows\xxx
/^chrome:\/\//
Firefox 扩展/^chrome-extension:\/\//
Chrome 扩展/^safari-extension:\/\//
Safari 扩展/^https?:\/\/userscripts.org\//
笼统的:
特殊的:
仓库现在的是很早之前的项目代码与实际使用的不尽相同。
本仓库代码规划为 3个阶段:
通过 CMS 平台发布 monitor 脚本,需要 3个 CMS 区域:
放置到 seajs 之前:
<script type="text/javascript">
(function(){function k(a){return(a=String(a).match(l))?a[0]:""}function f(a,m,c,f,g){if(!g&&arguments.callee.caller){for(var b=arguments.callee.caller,d=[];b.arguments&&(b.arguments.callee&&b.arguments.callee.caller)&&!(b=b.arguments.callee.caller,d.push("at "+k(b)),b.caller===b););g=d.join("\n")}b={profile:"jserror",msg:a||"",file:m||"",line:c||0,num:f||"",stack:g||"",lost:h.join(",")};e._DATAS.push(b);return b}if(!window.monitor){var e=window.monitor={};e._DATAS=[];var h=[],d={};e.lost=function(a){d.hasOwnProperty(a)||(d[a]=!0,h.push(a))};e.log=function(a,d){if(a){var c=d||"log";3===arguments.length&&(c="product",a=Array.prototype.join.call(arguments,"|"));c={profile:c,seed:String(a)};e._DATAS.push(c);return c}};var l=/^function\b[^\)]+\)/;e.error=function(a){if(a instanceof Error)return f(a.message||a.description,a.fileName,a.lineNumber||a.line,a.number,a.stack||a.stacktrace)};window.onerror=function(a,d,c){f(a,d,c);return!1}}})();
</script>
## 前端监控采样率:[0,1] === [0%,100%]
#set($MONITOR_JS_RATE=$velocms2)
<script type="text/javascript">
if(window.seajs){
seajs.use("$", function($){
$(function(){
// 命中率:[0,1]: 实际对应采样率:[0%,100%]
var rate = $MONITOR_JS_RATE;
/**
* 随机采样命中算法。
* @param {Nuber} rate, 采样率,[0,1] 区间的数值。
* @return {Boolean}
*/
function hit(rate){
return 0 === Math.floor(Math.random() / rate);
}
if(!hit(rate)){return;}
seajs.use(["sai/2.0.0/sai", "sai/2.0.0/privacy"],
function(Sai, privacy){
if(!Sai || !Sai.boot){return;}
// 启动监控。
Sai.boot();
if(!privacy){return;}
var html = (document.documentElement || document.body).innerHTML;
privacy.scan(html);
});
});
});
}
</script>
[34569]
开头,可以减少 50% 的随机数和时间戳造成的误判。提供某种机制,用以支持可以使用 GA 的事件监控来处理 JavaScript 异常的数据。
例如
monitor.on("jserror", function(meta){
_gaq.push(['_trackEvent', meta.message, 'jserror', meta.file + ":" + meta.line]);
return false; // 取消默认的日志监控行为。
});
注:据说 GA 有 500 个事件的限制。
取消 seer 这种头尾拆分的代码组织方式,合并整个模块代码。
并尝试 spm umd 打包方式。
考虑到无线设备目前的网络情况,几年内可能不会有巨大的提升,为了能更好的支持无线场景,减少网络请求,考虑合并多个监控数据到同一条请求中发送。
对于异常监控来说,用户浏览器当前使用的渲染引擎版本,比浏览器实际的渲染引擎版本更有用。
代码中已经硬编码了地址:
var LOG_SERVER = protocol + "//log.example.com/m.gif";
然后发现其实只有on
函数,没有文档中写的off
和log
函数?
全站各个系统的部署方式多样,包括以下各个场景,及其各个场景的组合:
// 未避免业务代码中对 monitor API 调用出错的防护措施,只提供公开方法的防护。
(function(win){
if(!win.monitor){win.monitor = {};}
var METHODS = ["lost", "log", "error", "on", "off"];
for(var i=0,method,l=METHODS.length; i<l; i++){
method = METHODS[i];
if("function" !== typeof win.monitor[method]){
win.monitor[method] = function(){};
}
}
})(window);
<script src="sea.js,..."></script>
// 后置脚本同样做好上面的防护。
// 由于头部可能更新不同步,后置脚本的防护性甚至要做到更加全面。
// 包括需要用到前置脚本的所有私有属性、方法。
为了让同样前端监控脚本更通用,计划让 monitor.js 同时支持 CMD 和非 CMD
抛弃 v1 中的 JSON 传输模式,改用 URL 键值参数的方式进行传输。
由于 monitor 只部署了一套生产环境,之前 sai.js 发向其他环境的日志无法被 monitor 处理。
需要考虑将开发、测试、预发环境的数据发向生产环境的 日志服务器。
monitor 后置脚本加载完成之前捕获到的异常,未能发送到日志服务器。
发送到 kcart 服务器,数据仓库可以帮助实现秒级的实时分析及 UV 分析能力,日志存储能力也有所增加。
切换过程中会同步保留原始到 magentmng 系统的日志。
可选方案:
#23 新增了系统名的监控,但是只有处理后的系统统一名称,没有对应编号。
决定监控完整的系统名,包括机器编号。然后在数据分析时适当处理。
优点:
对于 JavaScript 来说,catch 到的异常信息比 window.onerror 捕获的异常要丰富、有用的多:
window.onerror | try/catch | |
---|---|---|
异常堆栈信息 | 无 | 有 |
异常位置准确性 | 低 | 高 |
异常信息准确性 | 低 | 高 |
对源码的影响 | 无 | 有 |
对业务逻辑的影响 | 无 | 有 |
总体来说
对于支付宝来说,业务逻辑中功能占的比重较大,catch 住异常,会导致本应该中断的逻辑会继续执行,并最终导致无法挽救的错误。尽管这个异常已经被监控到。
支付宝现有的监控方案主要通过 window.onerror 进行监控,另外还提供了 API 给业务代码中主动 catch 住的异常提供监控支持。
真正重要的是:发现有效异常并重现。
重现需要以下信息:
对于展现型业务来说,catch 住异常也许是可以接受的。catch 异常的技术手段可以参考以下方案:
目前各浏览器的实现都是:
而实际上,这种本地化和差异化可以说并非有必要,甚至是有害的。这导致 JavaScript 异常很难被统一进行统计,尤其是针对国际化市场的网站。
是否可以推进 w3c 组织来规范化 JavaScript 异常,让每个异常都是统一一致的。
发现 2.2.0 发布过程后,遇到 tradeexprod 系统下 IE 用户卡死的情况,是由于 tradeexprod 系统的头部太旧造成。
boot()
方法主要为了支持采样监控情况。
新的策略:将采样机制前置,如果采样未命中,则不加载监控后置脚本。
如果监控前置脚本准备妥当,后置脚本加载完成,则启动监控。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.