UNPKG

@zyf2e/mitojs

Version:

A SDK for monitoring browser errors

2 lines (1 loc) 17.9 kB
var MITO=function(){"use strict";var e,t,r,n,o;!function(e){e.UNKNOWN="UNKNOWN",e.UNKNOWN_FUNCTION="UNKNOWN_FUNCTION",e.JAVASCRIPT_ERROR="JAVASCRIPT_ERROR",e.BUSINESS_ERROR="BUSINESS_ERROR",e.LOG_ERROR="LOG_ERROR",e.FETCH_ERROR="HTTP_ERROR",e.VUE_ERROR="VUE_ERROR",e.RESOURCE_ERROR="RESOURCE_ERROR",e.PROMISE_ERROR="PROMISE_ERROR"}(e||(e={})),function(e){e.ROUTE="Route",e.CLICK="UI.Click",e.CONSOLE="Console",e.XHR="Xhr",e.FETCH="Fetch",e.UNHANDLEDREJECTION="Unhandledrejection",e.VUE="Vue",e.RESOURCE="Resource",e.CODE_ERROR="Code Error",e.CUSTOMER="Customer"}(t||(t={})),function(e){e.HTTP="http",e.USER="user",e.DEBUG="debug",e.EXCEPTION="exception"}(r||(r={})),function(e){e.XHR="xhr",e.FETCH="fetch",e.CONSOLE="console",e.DOM="dom",e.HISTORY="history",e.ERROR="error",e.HASHCHANGE="hashchange",e.UNHANDLEDREJECTION="unhandledrejection",e.MITO="mito",e.VUE="Vue"}(n||(n={})),function(e){e.XHR="xhr",e.FETCH="fetch"}(o||(o={}));const s=/^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/,a={isLogAddBreadcrumb:!0,crossOriginThreshold:1e3};const i="[object process]"===Object.prototype.toString.call("undefined"!=typeof process?process:0)?global:"undefined"!=typeof window?window:"undefined"!=typeof self?self:{},c=(i.__MITO__=i.__MITO__||{},i.__MITO__);c.replaceFlag=c.replaceFlag||{};const l=c.replaceFlag;function u(e,t){l[e]||(l[e]=t)}function h(e){return!!l[e]}const p=c.logger||(c.logger=new class{constructor(){this.enabled=!0,this._console={};["log","debug","info","warn","error","assert"].forEach(e=>{e in i.console&&(this._console[e]=i.console[e])})}disable(){this.enabled=!1}bindOptions(e){this.enabled=!!e}enable(){this.enabled=!0}log(...e){this.enabled&&this._console.log("MITO Logger[Log]:",...e)}warn(...e){this.enabled&&this._console.warn("MITO Logger[Warn]:",...e)}error(...e){this.enabled&&this._console.error("MITO Logger[Error]:",...e)}});function d(){return"undefined"==typeof document||null==document.location?"":document.location.href}function f(e,t,r,n=!1){e.addEventListener(t,r,n)}function R(e,t,r){if(!(t in e))return;const n=r(e[t]);"function"==typeof n&&(e[t]=n)}function E(){return Date.now()}function g(e,t,r){return!!function(e,t){return typeof e===t}(e,r)||(void 0!==e&&p.error(`${t}期望传入${r}类型,目前是${typeof e}类型`),!1)}function m(e,t,r){return!!function(e,t){return Object.prototype.toString.call(e)===t}(e,r)||(void 0!==e&&p.error(`${t}期望传入${r}类型,目前是${typeof e}类型`),!1)}function O(e){a.isLogAddBreadcrumb=!1,e(),a.isLogAddBreadcrumb=!0}function y(e){if(!e)return{};const t=e.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/);if(!t)return{};const r=t[6]||"",n=t[8]||"";return{host:t[4],path:t[5],protocol:t[2],relative:t[5]+r+n}}function b(t,r){const n={time:E(),url:d(),name:t.name,level:r,message:t.message};if(void 0===t.stack||!t.stack)return n;const o=/^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|[a-z]:|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,s=/^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i,a=/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,i=/(\S+) line (\d+)(?: > eval line \d+)* > eval/i,c=/\((\S*)(?::(\d+))(?::(\d+))\)/,l=t.stack.split("\n"),u=[];let h,p,f;for(let r=0,n=l.length;r<n;++r){if(p=o.exec(l[r])){const t=p[2]&&0===p[2].indexOf("native");p[2]&&0===p[2].indexOf("eval")&&(h=c.exec(p[2]))&&(p[2]=h[1],p[3]=h[2],p[4]=h[3]),f={url:t?null:p[2],func:p[1]||e.UNKNOWN_FUNCTION,args:t?[p[2]]:[],line:p[3]?+p[3]:null,column:p[4]?+p[4]:null}}else if(p=a.exec(l[r]))f={url:p[2],func:p[1]||e.UNKNOWN_FUNCTION,args:[],line:+p[3],column:p[4]?+p[4]:null};else{if(!(p=s.exec(l[r])))continue;p[3]&&p[3].indexOf(" > eval")>-1&&(h=i.exec(p[3]))?(p[3]=h[1],p[4]=h[2],p[5]=null):0!==r||p[5]||void 0===t.columnNumber||(u[0].column=t.columnNumber+1),f={url:p[3],func:p[1]||e.UNKNOWN_FUNCTION,args:p[2]?p[2].split(","):[],line:p[4]?+p[4]:null,column:p[5]?+p[5]:null}}!f.func&&f.line&&(f.func=e.UNKNOWN_FUNCTION),u.push(f)}return u.length?{...n,stack:u}:null}function T(e){switch(Object.prototype.toString.call(e)){case"[object Error]":case"[object Exception]":case"[object DOMException]":return!0;default:return function(e,t){try{return e instanceof t}catch(e){return!1}}(e,Error)}}class N{constructor(){this.stack=[],this.isFlushing=!1,this.micro=Promise.resolve()}addFn(e){"function"==typeof e&&(this.stack.push(e),this.isFlushing||(this.isFlushing=!0,this.micro.then(()=>this.flushStack())))}flushStack(){const e=this.stack.slice(0);this.stack.length=0,this.isFlushing=!1;for(let t=0;t<e.length;t++)e[t]()}}const C=c.breadcrumb||(c.breadcrumb=new class{constructor(){this.maxBreadcrumbs=10,this.beforePushBreadcrumb=null,this.stack=[]}push(e){if("function"==typeof this.beforePushBreadcrumb){let t=null;return O(()=>{t=this.beforePushBreadcrumb(this,e)}),void(t&&this.immediatePush(t))}this.immediatePush(e)}immediatePush(e){e.time=E(),this.stack.length>=this.maxBreadcrumbs&&this.shift(),this.stack.push(e),p.log(this.stack)}shift(){return void 0!==this.stack.shift()}getStack(){return this.stack}getCategory(e){switch(e){case t.XHR:case t.FETCH:return r.HTTP;case t.CLICK:case t.ROUTE:return r.USER;case t.CUSTOMER:case t.CONSOLE:return r.DEBUG;case t.UNHANDLEDREJECTION:case t.CODE_ERROR:case t.RESOURCE:case t.VUE:default:return r.EXCEPTION}}bindOptions(e={}){const{maxBreadcrumbs:t,beforePushBreadcrumb:r}=e;g(t,"maxBreadcrumbs","number")&&(this.maxBreadcrumbs=t),g(r,"beforePushBreadcrumb","function")&&(this.beforePushBreadcrumb=r)}}),x={};function S(t){let r;const n=I(t.url);switch(t.type){case e.FETCH_ERROR:r=t.type+t.request.method+t.response.status+I(t.request.url);break;case e.JAVASCRIPT_ERROR:case e.VUE_ERROR:r=t.type+t.name+t.message+n;break;case e.BUSINESS_ERROR:case e.LOG_ERROR:r=t.type+t.name+t.message+n+t.customInfo;break;case e.PROMISE_ERROR:r=t.type+function(e){const t=e=>Object.keys(e).sort().reduce((r,n)=>("[object Object]"===Object.prototype.toString.call(e[n])?r[n]=t(e[n]):r[n]=e[n],r),{});try{if(/\{.*\}/.test(e)){let r=JSON.parse(e);return r=t(r),JSON.stringify(r)}}catch(t){return e}}(t.message)+n;break;default:r=t.type+t.message+n}return r=function(e){let t=0;if(0==e.length)return t;for(let r=0;r<e.length;r++){const n=e.charCodeAt(r);t=(t<<5)-t+n,t&=t}return t}(r),"number"==typeof x[r]?x[r]++:x[r]=1,x[r]>2?null:r}function I(e){return e.replace(/\?.*$/,"").replace(/\/\d+([\/]*$)/,"{param}$1")}var U;!function(e){e.Else="else",e.Error="error",e.Warning="warning",e.Info="info",e.Debug="debug",e.Low="low",e.Normal="normal",e.High="high",e.Critical="critical"}(U||(U={})),function(e){e.fromString=function(t){switch(t){case"debug":return e.Debug;case"info":case"log":case"assert":return e.Info;case"warn":case"warning":return e.Warning;case e.Low:case e.Normal:case e.High:case e.Critical:case"error":return e.Error;default:return e.Else}}}(U||(U={}));const H={img:"图片",script:"脚本"};class k{constructor(e){this.url=e,this.beforeDataReport=null,this.backTrackerId=null,this.configXhr=null,this.sdkVersion="1.0.0",this.apikey="",this.queue=new N}imgRequest(e){var t;k.img.src=`${this.url}?${t=e,Object.entries(t).reduce((e,[t,r],n)=>(0!==n&&(e+="&"),e+=`${t}=${r}`),"")}`}getRecord(){const e=c.record;return e&&Array.isArray(e)&&e.length>2?e:[]}xhrPost(e){this.queue.addFn(()=>{if("undefined"==typeof XMLHttpRequest)return;if("function"==typeof this.beforeDataReport&&!(e=this.beforeDataReport(e)))return;const t=new XMLHttpRequest;t.open("POST",this.url),t.setRequestHeader("Content-Type","application/json;charset=UTF-8"),t.withCredentials=!0,"function"==typeof this.configXhr&&this.configXhr(t);const r=S(e);r&&(e.errorId=r,t.send(JSON.stringify(this.getTransportData(e))))})}getAuthInfo(){const e=this.getTrackerId();return{trackerId:String(e),sdkVersion:this.sdkVersion,apikey:this.apikey}}getTrackerId(){if("function"==typeof this.backTrackerId){const e=this.backTrackerId();if("string"==typeof e||"number"==typeof e)return e;p.error(`trackerId:${e} 期望 string 或 number 类型,但是传入 ${typeof e}`)}return""}getTransportData(e){return{authInfo:this.getAuthInfo(),breadcrumb:C.getStack(),data:e,record:this.getRecord()}}isSdkTransportUrl(e){return e.includes(this.url)}bindOptions(e={}){const{dsn:t,beforeDataReport:r,apikey:n,configXhr:o,backTrackerId:s}=e;g(n,"apikey","string")&&(this.apikey=n),g(t,"dsn","string")&&(this.url=t),g(r,"beforeDataReport","function")&&(this.beforeDataReport=r),g(o,"configXhr","function")&&(this.configXhr=o),g(s,"backTrackerId","function")&&(this.backTrackerId=s)}send(e){this.xhrPost(e)}}k.img=new Image;const _=c.transportData||(c.transportData=new k("//localhost:3000/api/error/error.gif")),v={handleHttp(r,n){const o=r.status>=402||0===r.status;if(C.push({type:n,category:C.getCategory(n),data:r,level:U.Info}),o){C.push({type:n,category:C.getCategory(t.CODE_ERROR),data:r,level:U.Error});const o=function(t){let r=t.responseText;return 0===t.status&&(r=t.elapsedTime<=a.crossOriginThreshold?"http请求失败,失败原因:跨域限制":"http请求失败,失败原因:超时"),{type:e.FETCH_ERROR,url:d(),time:t.time,elapsedTime:t.elapsedTime,level:U.Normal,request:{httpType:t.type,traceId:t.traceId,method:t.method,url:t.url,data:t.reqData||""},response:{status:t.status,statusText:t.statusText,data:t.responseText||"",description:r}}}(r);_.send(o)}},handleError(r){if(r.target.localName){const n=function(t){return{type:e.RESOURCE_ERROR,url:d(),message:"资源地址: "+(t.src||t.href),level:U.Low,time:E(),name:(H[t.localName]||t.localName)+" failed to load"}}(r.target);return C.push({type:t.RESOURCE,category:C.getCategory(t.RESOURCE),data:n,level:U.Error}),_.send(n)}const{message:n,filename:o,lineno:a,colno:i,error:c}=r;let l;if(c&&T(c))l=b(c,U.High);else{let t=e.UNKNOWN;const r=o||d();let c=n;const u=n.match(s);u[1]&&(t=u[1],c=u[2]);const h={url:r,func:e.UNKNOWN_FUNCTION,args:e.UNKNOWN,line:a,col:i};l={url:r,name:t,message:c,level:U.Normal,time:E(),stack:[h]}}l.type=e.JAVASCRIPT_ERROR,C.push({type:t.CODE_ERROR,category:C.getCategory(t.CODE_ERROR),data:l,level:U.Error}),_.send(l)},handleHistory(e){const{from:r,to:n}=e,{relative:o}=y(r),{relative:s}=y(n);C.push({type:t.ROUTE,category:C.getCategory(t.ROUTE),data:{from:o||"/",to:s||"/"},level:U.Info})},handleHashchange(e){const{oldURL:r,newURL:n}=e,{relative:o}=y(r),{relative:s}=y(n);C.push({type:t.ROUTE,category:C.getCategory(t.ROUTE),data:{from:o,to:s},level:U.Info})},handleUnhandleRejection(r){let n={type:e.PROMISE_ERROR,message:JSON.stringify(r.reason),url:d(),name:r.type,time:E(),level:U.Normal};T(r.reason)&&(n={...n,...b(r.reason,U.Normal)}),C.push({type:t.UNHANDLEDREJECTION,category:C.getCategory(t.UNHANDLEDREJECTION),data:n,level:U.Error}),_.send(n)},handleConsole(e){a.isLogAddBreadcrumb&&C.push({type:t.CONSOLE,category:C.getCategory(t.CONSOLE),data:e,level:U.fromString(e.level)})}};const D=c.options||(c.options=new class{constructor(){this.traceIdFieldName="Trace-Id",this.enableTraceId=!1}bindOptions(e={}){const{beforeAjaxSend:t,enableTraceId:r,filterXhrUrlRegExp:n,traceIdFieldName:o}=e;g(t,"beforeAjaxSend","function")&&(this.beforeAjaxSend=t),g(r,"enableTraceId","boolean")&&(this.enableTraceId=r),g(o,"traceIdFieldName","string")&&(this.traceIdFieldName=o),m(n,"filterXhrUrlRegExp","[object RegExp]")&&(this.filterXhrUrlRegExp=n)}}),L={},A=((e,t)=>{let r=!0;return function(...n){r&&(e.apply(this,n),r=!1,setTimeout(()=>{r=!0},t))}})(F,600);function w(e){switch(e){case n.XHR:!function(){if(!("XMLHttpRequest"in i))return;const e=XMLHttpRequest.prototype;R(e,"open",e=>function(...t){t[1];var r;this.mito_xhr={method:(r=t[0],"[object String]"===Object.prototype.toString.call(r)?t[0].toUpperCase():t[0]),url:t[1],sTime:E(),type:o.XHR},e.apply(this,t)}),R(e,"send",e=>function(...t){const{method:r,url:o}=this.mito_xhr;if(D.enableTraceId){const e=function(){let e=(new Date).getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(t){const r=(e+16*Math.random())%16|0;return e=Math.floor(e/16),("x"==t?r:3&r|8).toString(16)}))}();this.mito_xhr.traceId=e,this.setRequestHeader(D.traceIdFieldName,e)}this.setRequestHeader;D.beforeAjaxSend&&D.beforeAjaxSend({method:r,url:o},this),f(this,"loadend",(function(){if("POST"===r&&_.isSdkTransportUrl(o))return;if(D.filterXhrUrlRegExp&&D.filterXhrUrlRegExp.test(this.mito_xhr.url))return;this.mito_xhr.reqData=t[0];const e=E();this.mito_xhr.time=e,this.mito_xhr.status=this.status,this.mito_xhr.statusText=this.statusText,this.mito_xhr.responseText=this.responseText,this.mito_xhr.elapsedTime=e-this.mito_xhr.sTime,F(n.XHR,this.mito_xhr)})),e.apply(this,t)})}();break;case n.FETCH:!function(){if(!("fetch"in i))return;R(i,n.FETCH,e=>function(t,r){const s=E(),a=r&&r.method||"GET";let c={type:o.FETCH,method:a,reqData:r&&r.body,url:t};const l=new Headers(r.headers||{});return Object.assign(l,{setRequestHeader:l.set}),D.beforeAjaxSend&&D.beforeAjaxSend({method:a,url:t},l),r={...r,headers:l},console.log(r.headers),e.apply(i,[t,r]).then(e=>{const r=e.clone(),o=E();return c={...c,elapsedTime:o-s,status:r.status,statusText:r.statusText,time:o},r.text().then(e=>{"POST"===a&&_.isSdkTransportUrl(t)||D.filterXhrUrlRegExp&&D.filterXhrUrlRegExp.test(t)||(c.responseText=e,F(n.FETCH,c))}),e},e=>{const r=E();if(!("POST"===a&&_.isSdkTransportUrl(t)||D.filterXhrUrlRegExp&&D.filterXhrUrlRegExp.test(t)))throw c={...c,elapsedTime:r-s,status:0,statusText:e.name+e.message,time:r},F(n.FETCH,c),e})})}();break;case n.ERROR:f(i,"error",(function(e){F(n.ERROR,e)}),!0);break;case n.CONSOLE:!function(){if(!("console"in i))return;["log","debug","info","warn","error","assert"].forEach((function(e){e in i.console&&R(i.console,e,(function(t){return function(...r){t&&(F(n.CONSOLE,{args:r,level:e}),t.apply(i.console,r))}}))}))}();break;case n.HISTORY:!function(){if(!function(){const e=i,t=e.chrome,r=t&&t.app&&t.app.runtime,n="history"in e&&!!e.history.pushState&&!!e.history.replaceState;return!r&&n}())return;const e=i.onpopstate;function t(e){return function(...t){const r=t.length>2?t[2]:void 0;if(r){const e=X,t=String(r);X=t,F(n.HISTORY,{from:e,to:t})}return e.apply(this,t)}}i.onpopstate=function(...t){const r=d(),o=X;F(n.HISTORY,{from:o,to:r}),e&&e.apply(this,t)},R(i.history,"pushState",t),R(i.history,"replaceState",t)}();break;case n.UNHANDLEDREJECTION:f(i,n.UNHANDLEDREJECTION,(function(e){F(n.UNHANDLEDREJECTION,e)}));break;case n.DOM:!function(){if(!("document"in i))return;f(i.document,"click",(function(){A(n.DOM,{category:"click",data:this})}),!0);const e=EventTarget&&EventTarget.prototype;if(!e||!e.hasOwnProperty||!e.hasOwnProperty("addEventListener"))return;R(e,"addEventListener",(function(e){return function(t,r,n){return e.call(this,t,(...e)=>{try{return r.apply(this,e)}catch(e){throw console.log("wrapperListener",e),e}},n)}}))}();break;case n.HASHCHANGE:t="onpopstate",i.hasOwnProperty(t)||f(i,n.HASHCHANGE,(function(e){F(n.HASHCHANGE,e)}))}var t}function $(e){e&&(h(e.type)||(u(e.type,!0),L[e.type]=L[e.type]||[],L[e.type].push(e.callback),w(e.type)))}function F(e,t){e&&L[e]&&L[e].forEach(r=>{!function(e,t){try{e()}catch(e){console.log("err",e),t&&t(e)}}(()=>{r(t)},t=>{p.error(`重写事件triggerHandlers的回调函数发生错误\nType:${e}\nName: ${function(e){try{return e&&"function"==typeof e&&e.name||"<anonymous>"}catch(e){return"<anonymous>"}}(r)}\nError: ${t}`)})})}let X;function P(r,n,o,s,a){const i=function(e){if(e.$root===e)return"root";const t=e._isVue?e.$options&&e.$options.name||e.$options&&e.$options._componentTag:e.name;return(t?"component <"+t+">":"anonymous component")+(e._isVue&&e.$options&&e.$options.__file?" at "+(e.$options&&e.$options.__file):"")}(n),c=n.$options&&n.$options.propsData,l={type:e.VUE_ERROR,message:`${r.message}(${o})`,level:s,url:d(),componentName:i,propsData:c||"",name:r.name,stack:r.stack||[],time:E()};C.push({type:t.VUE,category:C.getCategory(t.VUE),data:l,level:a}),_.send(l)}X=d();const j="undefined"!=typeof console;function M(e={}){!function(e={}){u(n.XHR,!!e.silentXhr),u(n.FETCH,!!e.silentFetch),u(n.CONSOLE,!!e.silentConsole),u(n.DOM,!!e.silentDom),u(n.HISTORY,!!e.silentHistory),u(n.ERROR,!!e.silentError),u(n.HASHCHANGE,!!e.silentHashchange),u(n.UNHANDLEDREJECTION,!!e.silentUnhandledrejection),u(n.VUE,!!e.silentVue)}(e),C.bindOptions(e),p.bindOptions(e.debug),_.bindOptions(e),D.bindOptions(e)}return{MitoVue:{install(e){!h(n.VUE)&&e&&e.config&&(u(n.VUE,!0),e.config.errorHandler=function(t,r,n){P.apply(null,[t,r,n,U.Normal,U.Error]),j&&!e.config.silent&&O(()=>{console.error("Error in "+n+': "'+t.toString()+'"',r),console.error(t)})},e.config.warnHandler=function(e,t,r){P.apply(null,[e,t,r,U.Normal,U.Warning]),O(()=>{j&&console.error("[Vue warn]: "+e+r)})})}},SDK_VERSION:"1.0.0",SDK_NAME:"MITO.browser",init:function(e={}){e.disabled||(M(e),$({callback:e=>{v.handleHttp(e,t.XHR)},type:n.XHR}),$({callback:e=>{v.handleHttp(e,t.FETCH)},type:n.FETCH}),$({callback:e=>{v.handleError(e)},type:n.ERROR}),$({callback:e=>{v.handleConsole(e)},type:n.CONSOLE}),$({callback:e=>{v.handleHistory(e)},type:n.HISTORY}),$({callback:e=>{v.handleUnhandleRejection(e)},type:n.UNHANDLEDREJECTION}),$({callback:e=>{const r=function(e){const t=e.tagName.toLowerCase();if("body"===t)return null;let r=e.classList.value;return r=""!==r?` class="${r}"`:"",`<${t}${e.id?' id="'+e.id:""}${""!==r?r:""}>${e.innerText}</${t}>`}(e.data.activeElement);r&&C.push({type:t.CLICK,category:C.getCategory(t.CLICK),data:r,level:U.Info})},type:n.DOM}),$({callback:e=>{v.handleHashchange(e)},type:n.HASHCHANGE}))},log:function({info:r="emptyMsg",tag:n="",level:o=U.Normal,ex:s="",type:a=e.BUSINESS_ERROR}){let i={};T(s)&&(i=b(s,o));const c={...i,type:a,customInfo:r,level:o,custmerTag:n,url:d()};C.push({type:t.CUSTOMER,data:r,level:U.fromString(o.toString())}),_.send(c)}}}();