@error-monitor/core
Version:
Monitor Core - 前端监控SDK核心模块,提供跨平台的监控基础能力
3 lines (2 loc) • 19.1 kB
JavaScript
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 i(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 s(e){if(e&&e.stack)return e.stack.split("\n").filter(e=>e.trim()).slice(0,20).join("\n")}function n(e,t=10){const r=new WeakSet;try{const s=function e(s,n,o=0){if(o>t)return"[Max Depth Reached]";if(null==n)return n;if("object"==typeof n){if(r.has(n))return"[Circular Reference]";r.add(n)}if(n instanceof Error)return i(n);if(n instanceof Date)return n.toISOString();if(n instanceof RegExp)return n.toString();if("function"==typeof n)return"[Function]";if("symbol"==typeof n)return n.toString();if("object"==typeof n){if(Array.isArray(n))return n.map((t,r)=>e(String(r),t,o+1));{const t={};for(const r in n)n.hasOwnProperty(r)&&(t[r]=e(r,n[r],o+1));return t}}return n}(0,e);return JSON.stringify(s)}catch(e){return JSON.stringify({error:"Serialization failed",message:e instanceof Error?e.message:String(e)})}}function o(e,t=null){try{return JSON.parse(e)}catch(e){return t}}function a(e,t){let r;return function(...i){clearTimeout(r),r=setTimeout(()=>{clearTimeout(r),e(...i)},t)}}function h(e,t){let r;return function(...i){r||(e(...i),r=!0,setTimeout(()=>r=!1,t))}}function c(){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 u(){return"undefined"!=typeof globalThis&&void 0!==globalThis.navigator?globalThis.navigator.userAgent:""}function l(){const e=u();return/Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(e)}function g(){if("undefined"!=typeof globalThis&&void 0!==globalThis.navigator&&"connection"in globalThis.navigator){const e=globalThis.navigator.connection;return e.effectiveType||e.type||"unknown"}return"unknown"}function f(e){if(0===e)return"0 Bytes";const t=Math.floor(Math.log(e)/Math.log(1024));return parseFloat((e/Math.pow(1024,t)).toFixed(2))+" "+["Bytes","KB","MB","GB"][t]}function d(e){if(e<1e3)return`${Math.round(e)}ms`;if(e<6e4)return`${(e/1e3).toFixed(2)}s`;return`${Math.floor(e/6e4)}m ${(e%6e4/1e3).toFixed(0)}s`}function m(e){if(null===e||"object"!=typeof e)return e;if(e instanceof Date)return new Date(e.getTime());if(e instanceof Array)return e.map(e=>m(e));if("object"==typeof e){const t={};for(const r in e)e.hasOwnProperty(r)&&(t[r]=m(e[r]));return t}return e}function p(e){return null==e||("string"==typeof e&&""===e.trim()||(!(!Array.isArray(e)||0!==e.length)||"object"==typeof e&&0===Object.keys(e).length))}function v(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}function E(e,t,r=void 0){const i=t.split(".");let s=e;for(const e of i){if(null==s||"object"!=typeof s)return r;s=s[e]}return void 0!==s?s:r}class b{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 i in t)t.hasOwnProperty(i)&&("object"!=typeof t[i]||null===t[i]||Array.isArray(t[i])?r[i]=t[i]:r[i]=this.deepMerge(e[i]||{},t[i]));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 i=`${this.config.serverUrl}/api/monitor/report`,s={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(i,e,s)}captureError(e,t){var r;if(!(null===(r=this.config.error)||void 0===r?void 0:r.enabled))return;const i=this.platformAdapter.errorCapture.captureError(e,t);this.addToQueue(i)}recordPerformance(e,t){var r;if(!(null===(r=this.config.performance)||void 0===r?void 0:r.enabled))return;const i=this.platformAdapter.performance.recordPerformance(e,t);this.addToQueue(i)}recordBehavior(e,t){var r;if(!(null===(r=this.config.behavior)||void 0===r?void 0:r.enabled))return;const i=this.platformAdapter.behavior.recordBehavior(e,t);this.addToQueue(i)}getStatus(){var e,t,r,i,s;const n=this.dataQueue.filter(e=>"type"in e&&e.type).length,o=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:n,performanceCount:o,behaviorCount:a},lastReportTime:Date.now(),errorMonitor:!!(null===(r=this.config.error)||void 0===r?void 0:r.enabled),performanceMonitor:!!(null===(i=this.config.performance)||void 0===i?void 0:i.enabled),behaviorMonitor:!!(null===(s=this.config.behavior)||void 0===s?void 0:s.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),i=r.indexOf(t);i>-1&&r.splice(i,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=(...i)=>{this.off(e,r),t(...i)};this.on(e,r)}}function S(e){const t=new Date;return{projectVersion:e.projectVersion||"0.0.0",buildId:e.buildId||y(),buildTime:e.buildTime||t.toISOString(),environment:e.environment||"production",hasSourcemap:e.hasSourcemap||!1,extra:e.extra||{}}}function y(){return`${Date.now().toString(36)}-${Math.random().toString(36).substring(2,8)}`}function T(e){const t={},r=e.split("\n");for(const e of r){if(e===r[0]&&!e.includes("at ")&&!e.includes("@"))continue;const i=e.match(/at\s+(?:.+?\s+)?\((.+?):(\d+):(\d+)\)/);if(i){t.filename=i[1],t.lineno=parseInt(i[2],10),t.colno=parseInt(i[3],10);break}const s=e.match(/at\s+(.+?):(\d+):(\d+)/);if(s){t.filename=s[1],t.lineno=parseInt(s[2],10),t.colno=parseInt(s[3],10);break}const n=e.match(/(.+?)@(.+?):(\d+):(\d+)/);if(n){t.filename=n[2],t.lineno=parseInt(n[3],10),t.colno=parseInt(n[4],10);break}const o=e.match(/(.+?):(\d+):(\d+)/);if(o){t.filename=o[1],t.lineno=parseInt(o[2],10),t.colno=parseInt(o[3],10);break}}return t}function R(e,t,r=3){const i=e.split("\n"),s=t-1;if(s<0||s>=i.length)return{preLines:[],errorLine:"",postLines:[]};const n=i[s],o=[];for(let e=Math.max(0,s-r);e<s;e++)o.push(i[e]);const a=[];for(let e=s+1;e<Math.min(i.length,s+r+1);e++)a.push(i[e]);return{preLines:o,errorLine:n,postLines:a}}class C{constructor(e,t){this.aggregations=new Map,this.config={enabled:!0,maxErrors:100,filters:[],sampleRate:1,aggregationWindow:3e5,maxAggregations:1e3,maxRecentErrors:5,enableAggregation:!0,projectVersion:void 0,buildId:void 0,enableSourceMapping:!0,...e},this.errorCapture=t,this.init()}init(){this.config.enabled&&(this.errorCapture.initErrorListeners(e=>{this.handleError(e)}),this.startCleanupTimer())}setErrorCallback(e){this.onError=e}setAggregatedErrorCallback(e){this.onAggregatedError=e}handleError(e){this.shouldCaptureError(e)&&(Math.random()>(this.config.sampleRate||1)||(this.enrichErrorWithVersionInfo(e),this.config.enableAggregation?this.aggregateError(e):this.reportError(e)))}enrichErrorWithVersionInfo(e){this.config.projectVersion&&(e.projectVersion=this.config.projectVersion),this.config.buildId&&(e.buildId=this.config.buildId),this.config.enableSourceMapping&&(e.sourceMappingStatus="pending"),e.stack&&this.parseErrorStack(e)}parseErrorStack(e){if(e.filename&&void 0!==e.lineno&&void 0!==e.colno)return;if(!e.stack)return;const t=T(e.stack);t.filename&&(e.filename=e.filename||t.filename),t.lineno&&(e.lineno=e.lineno||t.lineno),t.colno&&(e.colno=e.colno||t.colno),e.filename&&(e.sourceFilePath=e.filename)}shouldCaptureError(e){return!(this.config.filters&&this.config.filters.length>0)||!this.config.filters.some(t=>t.test(e.message))}aggregateError(e){const t=this.generateErrorFingerprint(e);let r=this.aggregations.get(t);r||(r={fingerprint:t,message:e.message,stack:e.stack,count:0,firstSeen:e.timestamp,lastSeen:e.timestamp,level:e.level||"error",affectedUsers:new Set,recentErrors:[]},this.aggregations.set(t,r)),r.count++,r.lastSeen=e.timestamp,e.userId&&r.affectedUsers.add(e.userId),r.recentErrors.push(e),r.recentErrors.length>(this.config.maxRecentErrors||5)&&r.recentErrors.shift(),this.checkAggregationReporting(r),this.aggregations.size>(this.config.maxAggregations||1e3)&&this.cleanOldAggregations()}generateErrorFingerprint(e){const t=[e.type,e.message,e.filename||"",e.lineno||0,e.colno||0];if(e.stack){const r=e.stack.split("\n").slice(0,3);t.push(r.join("|"))}return this.simpleHash(t.join("||"))}simpleHash(e){let t=0;if(0===e.length)return t.toString();for(let r=0;r<e.length;r++){t=(t<<5)-t+e.charCodeAt(r),t&=t}return Math.abs(t).toString(36)}checkAggregationReporting(e){(1===e.count||5===e.count||10===e.count||e.count%50==0)&&this.reportAggregatedError(e)}reportError(e){this.onError&&this.onError(e)}reportAggregatedError(e){this.onAggregatedError&&this.onAggregatedError(e);const t=e.recentErrors[e.recentErrors.length-1];if(t&&this.onError){const r={...t,tags:{...t.tags,aggregation_count:String(e.count),aggregation_fingerprint:e.fingerprint,affected_users:String(e.affectedUsers.size)}};this.onError(r)}}captureError(e,t){const r=this.errorCapture.captureError(e,t);this.handleError(r)}captureHttpError(e){const t=this.errorCapture.captureHttpError(e);this.handleError(t)}getErrorStats(){let e=0;const t=new Set;for(const r of this.aggregations.values())e+=r.count,r.affectedUsers.forEach(e=>t.add(e));const r=Array.from(this.aggregations.values()).sort((e,t)=>t.count-e.count).slice(0,10).map(e=>({fingerprint:e.fingerprint,message:e.message,count:e.count,affectedUsers:e.affectedUsers.size}));return{totalAggregations:this.aggregations.size,totalErrors:e,affectedUsers:t.size,topErrors:r}}cleanOldAggregations(){const e=Date.now(),t=this.config.aggregationWindow||3e5;for(const[r,i]of this.aggregations)e-i.lastSeen>t&&this.aggregations.delete(r)}startCleanupTimer(){this.cleanupTimer=setInterval(()=>{this.cleanOldAggregations()},6e4)}destroy(){this.errorCapture.destroyErrorListeners(),this.cleanupTimer&&(clearInterval(this.cleanupTimer),this.cleanupTimer=void 0),this.aggregations.clear()}}var I,A,M,_;!function(e){e.JS_ERROR="js_error",e.PROMISE_ERROR="promise_error",e.RESOURCE_ERROR="resource_error",e.HTTP_ERROR="http_error",e.CUSTOM_ERROR="custom_error",e.FRAMEWORK_ERROR="framework_error"}(I||(I={})),function(e){e.PAGE_LOAD="page_load",e.HTTP_REQUEST="http_request",e.RESOURCE_LOAD="resource_load",e.USER_INTERACTION="user_interaction",e.CUSTOM_METRIC="custom_metric"}(A||(A={})),function(e){e.PAGE_VIEW="page_view",e.CLICK="click",e.SCROLL="scroll",e.FORM_SUBMIT="form_submit",e.ROUTE_CHANGE="route_change",e.CUSTOM="custom"}(M||(M={})),function(e){e.ITEM_ADDED="itemAdded",e.ITEMS_FLUSHED="itemsFlushed",e.FLUSH_SUCCESS="flushSuccess",e.FLUSH_ERROR="flushError",e.QUEUE_FULL="queueFull",e.CACHE_RESTORED="cacheRestored"}(_||(_={}));class O{constructor(e={},t,r){this.queue=[],this.pendingQueue=[],this.stats={successCount:0,failedCount:0},this.debouncedSaveToCache=a(()=>{this.saveToCache()},1e3),this.config={maxSize:500,batchSize:20,flushInterval:1e4,enablePersistence:!1,storageKey:"monitor_queue",maxCacheSize:100,enableCompression:!1,...e},this.storage=t,this.eventEmitter=r,this.init()}init(){this.config.enablePersistence&&this.storage&&this.restoreFromCache(),this.startFlushTimer()}add(e){var t,r;this.queue.length>=this.config.maxSize&&(this.queue.shift(),null===(t=this.eventEmitter)||void 0===t||t.emit(_.QUEUE_FULL,this.getStatus())),this.queue.push(e),null===(r=this.eventEmitter)||void 0===r||r.emit(_.ITEM_ADDED,e),this.config.enablePersistence&&this.debouncedSaveToCache()}addBatch(e){e.forEach(e=>this.add(e))}getBatch(e){const t=e||this.config.batchSize;return this.queue.splice(0,Math.min(t,this.queue.length))}flush(){var e;const t=[...this.queue];return this.queue=[],null===(e=this.eventEmitter)||void 0===e||e.emit(_.ITEMS_FLUSHED,t),this.config.enablePersistence&&this.saveToCache(),t}onSendSuccess(e){var t;this.stats.successCount+=e.length,null===(t=this.eventEmitter)||void 0===t||t.emit(_.FLUSH_SUCCESS,e)}onSendError(e,t){var r;this.stats.failedCount+=e.length,this.queue.unshift(...e),this.queue.length>this.config.maxSize&&(this.queue=this.queue.slice(0,this.config.maxSize)),null===(r=this.eventEmitter)||void 0===r||r.emit(_.FLUSH_ERROR,{data:e,error:t})}getStatus(){return{size:this.queue.length,maxSize:this.config.maxSize,isFull:this.queue.length>=this.config.maxSize,pendingCount:this.pendingQueue.length,failedCount:this.stats.failedCount,successCount:this.stats.successCount}}isEmpty(){return 0===this.queue.length}isFull(){return this.queue.length>=this.config.maxSize}clear(){this.queue=[],this.pendingQueue=[],this.stats={successCount:0,failedCount:0},this.config.enablePersistence&&this.storage&&this.storage.removeItem(this.config.storageKey)}startFlushTimer(){this.config.flushInterval>0&&(this.flushTimer=setInterval(()=>{var e;if(!this.isEmpty()){const t=this.getBatch();t.length>0&&(null===(e=this.eventEmitter)||void 0===e||e.emit(_.ITEMS_FLUSHED,t))}},this.config.flushInterval))}stopFlushTimer(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=void 0)}saveToCache(){if(this.storage)try{const e={queue:this.queue.slice(-this.config.maxCacheSize),timestamp:Date.now(),stats:this.stats},t=this.config.enableCompression?this.compress(n(e)):n(e);this.storage.setItem(this.config.storageKey,t)}catch(e){}}restoreFromCache(){var e;if(this.storage)try{const t=this.storage.getItem(this.config.storageKey);if(!t)return;const r=o(this.config.enableCompression?this.decompress(t):t);if(!r)return;const i=864e5;if(Date.now()-r.timestamp>i)return void this.storage.removeItem(this.config.storageKey);Array.isArray(r.queue)&&(this.queue=r.queue),r.stats&&(this.stats={...this.stats,...r.stats}),null===(e=this.eventEmitter)||void 0===e||e.emit(_.CACHE_RESTORED,{restoredCount:this.queue.length,stats:this.stats})}catch(e){this.storage.removeItem(this.config.storageKey)}}compress(e){try{return btoa(encodeURIComponent(e))}catch(t){return e}}decompress(e){try{return decodeURIComponent(atob(e))}catch(t){return e}}destroy(){this.stopFlushTimer(),this.config.enablePersistence&&this.saveToCache(),this.clear()}}class x extends O{constructor(e={},t,r){super(e,t,r),this.retryAttempts=new Map,this.maxRetries=e.maxRetries||3,this.retryDelay=e.retryDelay||2e3}addRetry(e,t){const r=e.id,i=this.retryAttempts.get(r)||0;i<this.maxRetries?(this.retryAttempts.set(r,i+1),setTimeout(()=>{this.add(e)},this.retryDelay*Math.pow(2,i))):this.retryAttempts.delete(r)}onSendSuccess(e){super.onSendSuccess(e),e.forEach(e=>{this.retryAttempts.delete(e.id)})}getRetryStats(){return{totalRetries:Array.from(this.retryAttempts.values()).reduce((e,t)=>e+t,0),activeRetries:this.retryAttempts.size}}clear(){super.clear(),this.retryAttempts.clear()}}const D="1.0.0",w={name:"Monitor SDK Core",version:D,description:"前端监控SDK核心模块,提供跨平台的监控功能",author:"Monitor Team",license:"MIT"},z=["web","taro-mini","wechat-mini","react-native"];export{b as BaseManager,M as BehaviorType,w as CORE_INFO,O as DataQueue,C as ErrorManager,I as ErrorType,A as PerformanceType,_ as QueueEventType,x as RetryQueue,z as SUPPORTED_PLATFORMS,D as VERSION,S as createVersionInfo,a as debounce,m as deepClone,R as extractErrorContext,f as formatBytes,d as formatDuration,y as generateBuildId,e as generateId,r as generateSessionId,E as get,s as getErrorStack,g as getNetworkType,c as getPageInfo,t as getTimestamp,v as getType,u as getUserAgent,p as isEmpty,l as isMobile,T as parseSourceLocation,o as safeJsonParse,n as safeJsonStringify,i as serializeError,h as throttle};
//# sourceMappingURL=index.esm.js.map