@error-monitor/web-sdk
Version:
Monitor Web SDK - 专为Web平台设计的前端监控SDK,轻量级、高性能、开箱即用
3 lines (2 loc) • 18.6 kB
JavaScript
"use strict";function e(){return Date.now().toString(36)+Math.random().toString(36).substr(2)}function t(){return Date.now()}function r(){return`session_${Date.now().toString(36)}_${Math.random().toString(36).substr(2,9)}`}function o(e){if(!e)return null;if(e instanceof Error)return{name:e.name,message:e.message,stack:e.stack,...Object.getOwnPropertyNames(e).reduce((t,r)=>(["name","message","stack"].includes(r)||(t[r]=e[r]),t),{})};if("string"==typeof e)return{message:e};try{return JSON.parse(JSON.stringify(e))}catch(t){return{message:String(e)}}}function i(e){if(e&&e.stack)return e.stack.split("\n").filter(e=>e.trim()).slice(0,20).join("\n")}function s(){return"undefined"!=typeof globalThis&&void 0!==globalThis.location&&void 0!==globalThis.document?{url:globalThis.location.href,title:globalThis.document.title,referrer:globalThis.document.referrer}:{url:"",title:"",referrer:""}}function n(){return"undefined"!=typeof globalThis&&void 0!==globalThis.navigator?globalThis.navigator.userAgent:""}Object.defineProperty(exports,"__esModule",{value:!0});class a{constructor(e,t){this.dataQueue=[],this.isInitialized=!1,this.isEnabled=!0,this.listeners=new Map,this.config=this.mergeConfig(e),this.platformAdapter=t,this.sessionId=r()}mergeConfig(e){return this.deepMerge({enableInDev:!1,sampleRate:1,error:{enabled:!0,maxErrors:100,filters:[],sampleRate:1},performance:{enabled:!0,maxPerformance:100,enableResourceTiming:!0,enableUserTiming:!0},behavior:{enabled:!0,maxBehaviors:200,autoTrackClick:!0,autoTrackPageView:!0},report:{interval:1e4,maxQueueSize:500,batchSize:20,timeout:5e3,maxRetries:3,retryDelay:2e3,enableOfflineCache:!0}},e)}deepMerge(e,t){const r={...e};for(const o in t)t.hasOwnProperty(o)&&("object"!=typeof t[o]||null===t[o]||Array.isArray(t[o])?r[o]=t[o]:r[o]=this.deepMerge(e[o]||{},t[o]));return r}async init(){if(!this.isInitialized)if(this.shouldEnable())try{await this.platformAdapter.init(this.config),this.initErrorMonitor(),this.initPerformanceMonitor(),this.initBehaviorMonitor(),this.startReportTimer(),this.isInitialized=!0,this.emit("init",this.getStatus())}catch(e){throw this.emit("error",e),e}else this.isEnabled=!1}shouldEnable(){return!(this.isDevelopment()&&!this.config.enableInDev)&&!(Math.random()>(this.config.sampleRate||1))}isDevelopment(){return("undefined"==typeof process||!process.env)&&("undefined"!=typeof globalThis&&void 0!==globalThis.location&&("localhost"===globalThis.location.hostname||"127.0.0.1"===globalThis.location.hostname))}initErrorMonitor(){var e;(null===(e=this.config.error)||void 0===e?void 0:e.enabled)&&this.platformAdapter.errorCapture.initErrorListeners(e=>{this.addToQueue(e),this.emit("error",e)})}initPerformanceMonitor(){var e;(null===(e=this.config.performance)||void 0===e?void 0:e.enabled)&&this.platformAdapter.performance.initPerformanceMonitor(e=>{this.addToQueue(e),this.emit("performance",e)})}initBehaviorMonitor(){var e;(null===(e=this.config.behavior)||void 0===e?void 0:e.enabled)&&this.platformAdapter.behavior.initBehaviorMonitor(e=>{this.addToQueue(e),this.emit("behavior",e)})}addToQueue(e){var t;if(!this.isEnabled)return;e.projectId=this.config.projectId,e.userId=this.config.userId,e.sessionId=this.sessionId,e.platform=this.platformAdapter.platformInfo.platform,this.config.projectVersion&&(e.projectVersion=this.config.projectVersion),this.config.tags&&(e.tags={...e.tags,...this.config.tags});const r=(null===(t=this.config.report)||void 0===t?void 0:t.maxQueueSize)||500;this.dataQueue.length>=r&&this.dataQueue.shift(),this.dataQueue.push(e),this.emit("dataAdded",e)}startReportTimer(){var e;const t=(null===(e=this.config.report)||void 0===e?void 0:e.interval)||1e4;this.reportTimer=setInterval(()=>{this.flush()},t)}async flush(){var e;if(!this.isEnabled||0===this.dataQueue.length)return;const t=(null===(e=this.config.report)||void 0===e?void 0:e.batchSize)||20,r=this.dataQueue.splice(0,t);try{await this.sendData(r),this.emit("dataReported",r)}catch(e){throw this.dataQueue.unshift(...r),this.emit("reportError",e),e}}async sendData(e){var t,r;const o=`${this.config.serverUrl}/api/monitor/report`,i={timeout:(null===(t=this.config.report)||void 0===t?void 0:t.timeout)||5e3,retries:(null===(r=this.config.report)||void 0===r?void 0:r.maxRetries)||3,headers:this.config.apiKey?{"X-API-Key":this.config.apiKey}:void 0};await this.platformAdapter.network.sendData(o,e,i)}captureError(e,t){var r;if(!(null===(r=this.config.error)||void 0===r?void 0:r.enabled))return;const o=this.platformAdapter.errorCapture.captureError(e,t);this.addToQueue(o)}recordPerformance(e,t){var r;if(!(null===(r=this.config.performance)||void 0===r?void 0:r.enabled))return;const o=this.platformAdapter.performance.recordPerformance(e,t);this.addToQueue(o)}recordBehavior(e,t){var r;if(!(null===(r=this.config.behavior)||void 0===r?void 0:r.enabled))return;const o=this.platformAdapter.behavior.recordBehavior(e,t);this.addToQueue(o)}getStatus(){var e,t,r,o,i;const s=this.dataQueue.filter(e=>"type"in e&&e.type).length,n=this.dataQueue.filter(e=>"metrics"in e).length,a=this.dataQueue.filter(e=>"event"in e).length;return{initialized:this.isInitialized,enabled:this.isEnabled,queue:{size:this.dataQueue.length,maxSize:(null===(e=this.config.report)||void 0===e?void 0:e.maxQueueSize)||500,isFull:this.dataQueue.length>=((null===(t=this.config.report)||void 0===t?void 0:t.maxQueueSize)||500),errorCount:s,performanceCount:n,behaviorCount:a},lastReportTime:Date.now(),errorMonitor:!!(null===(r=this.config.error)||void 0===r?void 0:r.enabled),performanceMonitor:!!(null===(o=this.config.performance)||void 0===o?void 0:o.enabled),behaviorMonitor:!!(null===(i=this.config.behavior)||void 0===i?void 0:i.enabled)}}destroy(){this.isInitialized&&(this.reportTimer&&(clearInterval(this.reportTimer),this.reportTimer=void 0),this.flush().catch(e=>{}),this.platformAdapter.destroy(),this.dataQueue=[],this.listeners.clear(),this.isInitialized=!1,this.isEnabled=!1,this.emit("destroy"))}on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}off(e,t){if(this.listeners.has(e))if(t){const r=this.listeners.get(e),o=r.indexOf(t);o>-1&&r.splice(o,1)}else this.listeners.delete(e)}emit(e,...t){if(!this.listeners.has(e))return!1;return this.listeners.get(e).forEach(e=>{try{e(...t)}catch(e){}}),!0}once(e,t){const r=(...o)=>{this.off(e,r),t(...o)};this.on(e,r)}}var c,l,d;exports.ErrorType=void 0,(c=exports.ErrorType||(exports.ErrorType={})).JS_ERROR="js_error",c.PROMISE_ERROR="promise_error",c.RESOURCE_ERROR="resource_error",c.HTTP_ERROR="http_error",c.CUSTOM_ERROR="custom_error",c.FRAMEWORK_ERROR="framework_error",exports.PerformanceType=void 0,(l=exports.PerformanceType||(exports.PerformanceType={})).PAGE_LOAD="page_load",l.HTTP_REQUEST="http_request",l.RESOURCE_LOAD="resource_load",l.USER_INTERACTION="user_interaction",l.CUSTOM_METRIC="custom_metric",exports.BehaviorType=void 0,(d=exports.BehaviorType||(exports.BehaviorType={})).PAGE_VIEW="page_view",d.CLICK="click",d.SCROLL="scroll",d.FORM_SUBMIT="form_submit",d.ROUTE_CHANGE="route_change",d.CUSTOM="custom";class u{constructor(){this.listeners=[]}initErrorListeners(e){this.setupGlobalErrorHandler(e),this.setupUnhandledRejectionHandler(e),this.setupResourceErrorHandler(e)}setupGlobalErrorHandler(a){const c=c=>{const l={id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.ErrorType.JS_ERROR,message:c.message,filename:c.filename,lineno:c.lineno,colno:c.colno,stack:c.error?i(c.error):void 0,error:o(c.error)};a(l)};window.addEventListener("error",c),this.listeners.push(()=>window.removeEventListener("error",c))}setupUnhandledRejectionHandler(a){const c=c=>{const l=c.reason,d={id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.ErrorType.PROMISE_ERROR,message:l instanceof Error?l.message:String(l),stack:l instanceof Error?i(l):void 0,error:o(l)};a(d)};window.addEventListener("unhandledrejection",c),this.listeners.push(()=>window.removeEventListener("unhandledrejection",c))}setupResourceErrorHandler(o){const i=i=>{var a,c;const l=i.target;if(!(l&&l!==window&&l instanceof HTMLElement))return;const d=null===(a=l.tagName)||void 0===a?void 0:a.toLowerCase(),u=l.src||l.href;if(!u)return;const h={id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.ErrorType.RESOURCE_ERROR,message:`Failed to load ${d}: ${u}`,filename:u,error:{tagName:d,resourceUrl:u,outerHTML:null===(c=l.outerHTML)||void 0===c?void 0:c.substring(0,200)}};o(h)};window.addEventListener("error",i,!0),this.listeners.push(()=>window.removeEventListener("error",i,!0))}destroyErrorListeners(){this.listeners.forEach(e=>e()),this.listeners=[]}captureError(a,c){return{id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.ErrorType.CUSTOM_ERROR,message:a instanceof Error?a.message:String(a),stack:a instanceof Error?i(a):void 0,error:o(a),...c}}captureHttpError(o){return{id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.ErrorType.HTTP_ERROR,message:`HTTP ${o.status} ${o.statusText}: ${o.method} ${o.url}`,error:{url:o.url,method:o.method,status:o.status,statusText:o.statusText,duration:o.duration}}}}class h{initPerformanceMonitor(e){this.onPerformance=e,this.setupNavigationTiming(),this.setupResourceTiming(),this.setupUserTiming()}setupNavigationTiming(){"undefined"!=typeof performance&&("complete"===document.readyState?this.collectNavigationTiming():window.addEventListener("load",()=>{setTimeout(()=>this.collectNavigationTiming(),0)}))}collectNavigationTiming(){var o;if(!performance.timing)return;const i=performance.timing,a={dnsTime:i.domainLookupEnd-i.domainLookupStart,tcpTime:i.connectEnd-i.connectStart,requestTime:i.responseStart-i.requestStart,responseTime:i.responseEnd-i.responseStart,domParseTime:i.domContentLoadedEventStart-i.domLoading,resourceLoadTime:i.loadEventStart-i.domContentLoadedEventStart,totalTime:i.loadEventEnd-i.navigationStart},c={id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.PerformanceType.PAGE_LOAD,metrics:a};null===(o=this.onPerformance)||void 0===o||o.call(this,c)}setupResourceTiming(){performance.getEntriesByType&&(this.observer=new PerformanceObserver(e=>{for(const t of e.getEntries())"resource"===t.entryType&&this.handleResourceEntry(t)}),this.observer.observe({entryTypes:["resource"]}))}handleResourceEntry(o){var i;const a={id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.PerformanceType.RESOURCE_LOAD,metrics:{duration:o.duration,size:o.transferSize||0,dnsTime:o.domainLookupEnd-o.domainLookupStart,tcpTime:o.connectEnd-o.connectStart,requestTime:o.responseStart-o.requestStart,responseTime:o.responseEnd-o.responseStart},resource:{name:o.name,size:o.transferSize||0,duration:o.duration,type:this.getResourceType(o.name)}};null===(i=this.onPerformance)||void 0===i||i.call(this,a)}getResourceType(e){var t;const r=null===(t=e.split(".").pop())||void 0===t?void 0:t.toLowerCase();return r?["js","jsx","ts","tsx"].includes(r)?"script":["css","scss","sass","less"].includes(r)?"stylesheet":["png","jpg","jpeg","gif","svg","webp"].includes(r)?"image":["woff","woff2","ttf","otf","eot"].includes(r)?"font":"other":"other"}setupUserTiming(){performance.getEntriesByType&&(this.observer=new PerformanceObserver(e=>{for(const t of e.getEntries())"measure"===t.entryType&&this.handleMeasureEntry(t)}),this.observer.observe({entryTypes:["measure"]}))}handleMeasureEntry(o){var i;const a={id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.PerformanceType.USER_INTERACTION,metrics:{duration:o.duration,startTime:o.startTime}};null===(i=this.onPerformance)||void 0===i||i.call(this,a)}destroyPerformanceMonitor(){this.observer&&(this.observer.disconnect(),this.observer=void 0)}recordPerformance(o,i){return{id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.PerformanceType.CUSTOM_METRIC,metrics:i}}getPagePerformance(){if(!performance.timing)return{};const e=performance.timing;return{dnsTime:e.domainLookupEnd-e.domainLookupStart,tcpTime:e.connectEnd-e.connectStart,requestTime:e.responseStart-e.requestStart,responseTime:e.responseEnd-e.responseStart,domParseTime:e.domContentLoadedEventStart-e.domLoading,totalTime:e.loadEventEnd-e.navigationStart}}}class p{constructor(){this.listeners=[]}initBehaviorMonitor(e){this.onBehavior=e,this.setupClickTracking(),this.setupPageViewTracking(),this.setupScrollTracking()}setupClickTracking(){const o=o=>{var i,a;const c=o.target,l={id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.BehaviorType.CLICK,event:"click",target:this.getElementSelector(c),xpath:this.getElementXPath(c),data:{x:o.clientX,y:o.clientY,tagName:c.tagName,className:c.className,id:c.id,text:null===(i=c.textContent)||void 0===i?void 0:i.substring(0,100)}};null===(a=this.onBehavior)||void 0===a||a.call(this,l)};document.addEventListener("click",o,!0),this.listeners.push(()=>document.removeEventListener("click",o,!0))}setupPageViewTracking(){this.recordPageView();const e=history.pushState,t=history.replaceState;history.pushState=(...t)=>{e.apply(history,t),setTimeout(()=>this.recordPageView(),0)},history.replaceState=(...e)=>{t.apply(history,e),setTimeout(()=>this.recordPageView(),0)};const r=()=>{setTimeout(()=>this.recordPageView(),0)};window.addEventListener("popstate",r),this.listeners.push(()=>{window.removeEventListener("popstate",r),history.pushState=e,history.replaceState=t})}recordPageView(){var o;const i=s(),a={id:e(),timestamp:t(),projectId:"",sessionId:r(),url:i.url,userAgent:n(),platform:"web",type:exports.BehaviorType.PAGE_VIEW,event:"page_view",data:{title:i.title,referrer:i.referrer}};null===(o=this.onBehavior)||void 0===o||o.call(this,a)}setupScrollTracking(){let o=0;const i=()=>{var i;const a=Date.now();if(a-o<1e3)return;o=a;const c={id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.BehaviorType.SCROLL,event:"scroll",data:{scrollTop:window.pageYOffset||document.documentElement.scrollTop,scrollLeft:window.pageXOffset||document.documentElement.scrollLeft,scrollHeight:document.documentElement.scrollHeight,clientHeight:document.documentElement.clientHeight}};null===(i=this.onBehavior)||void 0===i||i.call(this,c)};window.addEventListener("scroll",i,{passive:!0}),this.listeners.push(()=>window.removeEventListener("scroll",i))}getElementSelector(e){if(e.id)return`#${e.id}`;if(e.className){const t=e.className.split(" ").filter(e=>e).join(".");if(t)return`${e.tagName.toLowerCase()}.${t}`}return e.tagName.toLowerCase()}getElementXPath(e){if(e.id)return`//*[@id="${e.id}"]`;const t=[];let r=e;for(;r&&r.nodeType===Node.ELEMENT_NODE;){let e=1,o=r.previousSibling;for(;o;)o.nodeType===Node.ELEMENT_NODE&&o.nodeName===r.nodeName&&e++,o=o.previousSibling;t.unshift(`${r.nodeName.toLowerCase()}[${e}]`),r=r.parentElement}return"/"+t.join("/")}destroyBehaviorMonitor(){this.listeners.forEach(e=>e()),this.listeners=[]}recordBehavior(o,i){return{id:e(),timestamp:t(),projectId:"",sessionId:r(),url:s().url,userAgent:n(),platform:"web",type:exports.BehaviorType.CUSTOM,event:o,data:i}}}class m{interceptNetwork(e,t,r){this.interceptXHR(e,t,r),this.interceptFetch(e,t,r)}interceptXHR(e,t,r){const o=window.XMLHttpRequest;window.XMLHttpRequest=function(){const i=new o,s=i.open,n=i.send;let a={method:"",url:"",startTime:0,headers:{}};return i.open=function(e,t,r=!0,o,i){return a.method=e,a.url=t,a.startTime=Date.now(),s.call(this,e,t,r,o,i)},i.send=function(o){e(a);return i.addEventListener("load",()=>{var e;const o={...a,status:i.status,statusText:i.statusText,duration:Date.now()-a.startTime,responseSize:(null===(e=i.responseText)||void 0===e?void 0:e.length)||0};i.status>=400?r(o):t(o)}),i.addEventListener("error",()=>r(a)),i.addEventListener("timeout",()=>r({...a,error:"timeout"})),n.apply(this,[o])},i}}interceptFetch(e,t,r){const o=window.fetch;window.fetch=async function(i,s){const n=Date.now(),a={url:"string"==typeof i?i:i.toString(),method:(null==s?void 0:s.method)||"GET",startTime:n,headers:(null==s?void 0:s.headers)||{}};e(a);try{const e=await o(i,s),c={...a,status:e.status,statusText:e.statusText,duration:Date.now()-n};return e.status>=400?r(c):t(c),e}catch(e){throw r({...a,error:e instanceof Error?e.message:String(e)}),e}}}async sendData(e,t,r){const o={method:"POST",headers:{"Content-Type":"application/json",...null==r?void 0:r.headers},body:JSON.stringify(t)};if(null==r?void 0:r.timeout){const e=new AbortController;setTimeout(()=>e.abort(),r.timeout),o.signal=e.signal}const i=await fetch(e,o);if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);return i.json()}}class f{setItem(e,t){try{localStorage.setItem(e,t)}catch(e){}}getItem(e){try{return localStorage.getItem(e)}catch(e){return null}}removeItem(e){try{localStorage.removeItem(e)}catch(e){}}clear(){try{localStorage.clear()}catch(e){}}}class g{constructor(){this.platformInfo={platform:"web",version:"1.0.0",userAgent:n(),deviceInfo:{language:navigator.language,cookieEnabled:navigator.cookieEnabled,onLine:navigator.onLine,screen:{width:screen.width,height:screen.height,colorDepth:screen.colorDepth}}},this.errorCapture=new u,this.performance=new h,this.behavior=new p,this.network=new m,this.storage=new f}init(e){}destroy(){this.errorCapture.destroyErrorListeners(),this.performance.destroyPerformanceMonitor(),this.behavior.destroyBehaviorMonitor()}}class v extends a{constructor(e){super(e,new g)}static init(e){return v.instance||(v.instance=new v(e),v.instance.init().catch(e=>{})),v.instance}static getInstance(){return v.instance}static destroy(){v.instance&&(v.instance.destroy(),v.instance=null)}}v.instance=null;const T={init:e=>v.init(e),setVersionInfo:e=>{v.getInstance()},getInstance:()=>v.getInstance(),captureError:(e,t)=>{const r=v.getInstance();r&&r.captureError(e,t)},recordPerformance:(e,t)=>{const r=v.getInstance();r&&r.recordPerformance(e,t)},recordBehavior:(e,t)=>{const r=v.getInstance();r&&r.recordBehavior(e,t)},flush:async()=>{const e=v.getInstance();e&&await e.flush()},getStatus:()=>{const e=v.getInstance();return e?e.getStatus():null},destroy:()=>v.destroy(),on:(e,t)=>{const r=v.getInstance();r&&r.on(e,t)},off:(e,t)=>{const r=v.getInstance();r&&r.off(e,t)}};"undefined"!=typeof window&&(window.MonitorSDK=T),exports.WebMonitorSDK=v,exports.default=T;
//# sourceMappingURL=index.js.map