GithubHelp home page GithubHelp logo

sai.js's People

Contributors

hotoo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sai.js's Issues

新增是否启用全局异常监控的开关

  • 有些情况,比如要嵌入到第三方网站的代码片段(如 Google 和阿里妈妈广告),只希望监控自身特定的脚本异常,不希望监控到这些第三方网站的异常。
  • 全局脚本异常监控会收到很多噪音的影响,为了提高异常的有效性,减少噪音,可能会关闭全局异常监控。

异常消息国际化与规范化

目前各浏览器的实现都是:

  • 根据用户设定的方言不同,抛出的 JavaScript 异常消息也会被本地化。
  • 不同浏览器对于同一个异常抛出的消息不同。

而实际上,这种本地化和差异化可以说并非有必要,甚至是有害的。这导致 JavaScript 异常很难被统一进行统计,尤其是针对国际化市场的网站。

是否可以推进 w3c 组织来规范化 JavaScript 异常,让每个异常都是统一一致的。

页内启动脚本改造

收银台等特殊系统对页面性能有较高要求,而且本身的代码性能不佳,可能会在加在页面最底部 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()

采样率调整

  • 敏感信息监控采样率保持 1%
  • 异常监控采样率 10%

全站全局监控脚本升级注意事项

全站各个系统的部署方式多样,包括以下各个场景,及其各个场景的组合:

  • 残缺:只引入前置脚本,或只引入后置脚本。
  • 老旧:引入的前置脚本和后置脚本版本不一致。
  • 重复:多长引入前置或后置脚本。

方案

  1. 前置脚本中按照现有方案部署。
  2. 并在全局头部文件中做前置脚本的公开方法做兼容,避免业务代码调用出错。
  3. 后置脚本同样做兼容,避免由于前置脚本公开方法和私有属性缺失或老旧造成的异常。

// 未避免业务代码中对 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>


// 后置脚本同样做好上面的防护。
// 由于头部可能更新不同步,后置脚本的防护性甚至要做到更加全面。
// 包括需要用到前置脚本的所有私有属性、方法。

考虑提供页面 ID 的配置

  • 在淘宝、ICBU,由于提供个性域名,同一个页面会存在多个 URL 地址。
  • 在支付宝,个人收款主页 下每个用户主页的 URL 地址也不相同,但使用的是同一份源码。

可选方案:

  • 前端方案:monitor.js 中提供设置页面 ID 的接口。
    • 简单:前端实现方案监控,可以保证后端更简单。
  • 后端方案:monitor-agent 中根据 URL 进行自动转换。
    • 目前支付宝个人收款主页就是用的这个方案。
    • monitor.js 保持简单。
    • 但日志分析会比较复杂,而且一旦有新的 URL 规则变化,不能提前自动处理。

使用 Google Analytics 分析异常数据

提供某种机制,用以支持可以使用 GA 的事件监控来处理 JavaScript 异常的数据。

例如

monitor.on("jserror", function(meta){
  _gaq.push(['_trackEvent', meta.message, 'jserror', meta.file + ":" + meta.line]);
  return false; // 取消默认的日志监控行为。
});

注:据说 GA 有 500 个事件的限制。

使用事件发布机制以支持扩展自定义数据

包括 #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();
});

删除 boot() 方法

boot() 方法主要为了支持采样监控情况。

新的策略:将采样机制前置,如果采样未命中,则不加载监控后置脚本。

如果监控前置脚本准备妥当,后置脚本加载完成,则启动监控。

增强:调整 monitor.log API,支持对象传参方式

现在的 monitor.log 传参使用固定的参数格式,导致需要扩展参数比较困难。

经过思考决定让 log API 支持传入键值对的参数,可以根据键值指定扩展参数名。
同时兼容旧有传参方式。

Fix: 排除客户端本地脚本抛出的异常

  • /^file:\/\/\// 特殊的,WebApp 打包到本地的页面是 file 协议。 策略:打包到本地的页面,也通过将 monitor.js 打包到本地,并针对性处理的方式。
  • /^\w:\\/ 例如:C:\windows\xxx
  • /^chrome:\/\// Firefox 扩展
  • /^chrome-extension:\/\// Chrome 扩展
  • /^safari-extension:\/\// Safari 扩展
  • 站外脚本
    • /^https?:\/\/userscripts.org\//

笼统的:

  • CDN 所在域的脚本异常。
  • 主站所在域的脚本异常。
  • 内部开发域的脚本异常。

特殊的:

  • WebApp file: 协议的本地脚本异常。

前端监控计划

4月份计划

  • 资源加载失败的监控技术方案:SeaJS, Loader, SCRIPT.
  • 确定资源加载失败造成的异常处理方案。

研究方向

  • 结合 SourceMap 的思路,展开异常相关源码。难点:异常所在列号。
  • 异常现场场景重现。

收集客户端语言信息

在 IE 浏览器中不同用户语言环境抛出的异常消息不同,虽然有将异常消息统一使用英文的提案,但目前来说,收集语种信息,对于识别异常消息非常有利。

lang = navigator.language || navigator.browserLanguage;

通用 catch 方案的思考

对于 JavaScript 来说,catch 到的异常信息比 window.onerror 捕获的异常要丰富、有用的多:

window.onerror try/catch
异常堆栈信息
异常位置准确性
异常信息准确性
对源码的影响
对业务逻辑的影响

总体来说

  • try/catch 可以获得更准确有效的异常信息。
    • 但是 catch 住异常,对正常的业务逻辑有较大影响;
    • 重新掷出异常,会导致一个异常被多次掷出,多次被监控。
    • try/catch 有一定的性能问题。
    • tyr/catch 整个模块,对其中的异步代码无效。
  • window.onerror 对业务无影响。
    • 但噪音较大,会发现客户端用户脚本等异常。
    • 异常位置和性能有可能不准确。

对于支付宝来说,业务逻辑中功能占的比重较大,catch 住异常,会导致本应该中断的逻辑会继续执行,并最终导致无法挽救的错误。尽管这个异常已经被监控到。

支付宝现有的监控方案主要通过 window.onerror 进行监控,另外还提供了 API 给业务代码中主动 catch 住的异常提供监控支持。

真正重要的是:发现有效异常并重现。

重现需要以下信息:

  • 用户所处的客户端环境,及其环境的扩展安装情况。例如 Windows 补丁包,浏览器插件安装情况。
  • 用户所处的服务环境,登录状态,持卡情况等。
  • 用户行为:点击路径等。
  • 用户身份信息:必要时直接联系客户。

catch 技术方案

对于展现型业务来说,catch 住异常也许是可以接受的。catch 异常的技术手段可以参考以下方案:

  • 运行时给函数添加 try/catch
    • 可以重写模块及其公开方法。
    • 无法重写内部私有方法。
  • 编译源码时静态给函数添加 try/catch
    • 可以重写所有的函数,包括公开方法和私有函数
    • 甚至可以重写到函数内部,而不是包含在函数外部。

客户端信息中增加是否为兼容模式

兼容模式对脚本引擎影响较大,因此考虑增加浏览器兼容模式信息。

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

敏感信息规则调整

  • 银行卡号限制:以 [34569] 开头,可以减少 50% 的随机数和时间戳造成的误判。
  • 隐私保护规则:
    • 身份证 6...4
    • 银行卡 6...4
    • 手机号 3...4

同步发送日志到 kcart 服务器

发送到 kcart 服务器,数据仓库可以帮助实现秒级的实时分析及 UV 分析能力,日志存储能力也有所增加。

切换过程中会同步保留原始到 magentmng 系统的日志。

监控完整的系统名,及其服务器编号

#23 新增了系统名的监控,但是只有处理后的系统统一名称,没有对应编号。

决定监控完整的系统名,包括机器编号。然后在数据分析时适当处理。

优点:

  • 可以精确找到异常所对应的详细服务器。
  • 可以区分生产环境和预发布环境。

增加系统名监控

  • 目前主要通过 URL 反映出来的域名来分『系统』。
  • 下一步准备直接监控真正的系统名。
<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;
});

考虑合并发送多个监控数据

考虑到无线设备目前的网络情况,几年内可能不会有巨大的提升,为了能更好的支持无线场景,减少网络请求,考虑合并多个监控数据到同一条请求中发送。

迁移现有使用版本代码到仓库

仓库现在的是很早之前的项目代码与实际使用的不尽相同。

本仓库代码规划为 3个阶段:

  1. 最早的现有代码 v0.1
  2. 支付宝发布使用的各个版本 v1.x
  3. 将来规划的版本 v2.x

发布 monitor-2.0.0

通过 CMS 平台发布 monitor 脚本,需要 3个 CMS 区域:

  1. seer.js

放置到 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>
  1. head
  2. foot
## 前端监控采样率:[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>

新增列号信息

部分浏览器可以通过间接手段拿到列号信息,这部分对应后续的 source map 非常有用。
预留提供列号字段。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.