index.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. * Used to configure the global error handling function, which can monitor vue errors, script errors, static resource errors and Promise errors
  3. */
  4. import type { ErrorLogInfo } from '/#/store';
  5. import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog';
  6. import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
  7. import { App } from 'vue';
  8. import projectSetting from '/@/settings/projectSetting';
  9. /**
  10. * Handling error stack information
  11. * @param error
  12. */
  13. function processStackMsg(error: Error) {
  14. if (!error.stack) {
  15. return '';
  16. }
  17. let stack = error.stack
  18. .replace(/\n/gi, '') // Remove line breaks to save the size of the transmitted content
  19. .replace(/\bat\b/gi, '@') // At in chrome, @ in ff
  20. .split('@') // Split information with @
  21. .slice(0, 9) // The maximum stack length (Error.stackTraceLimit = 10), so only take the first 10
  22. .map((v) => v.replace(/^\s*|\s*$/g, '')) // Remove extra spaces
  23. .join('~') // Manually add separators for later display
  24. .replace(/\?[^:]+/gi, ''); // Remove redundant parameters of js file links (?x=1 and the like)
  25. const msg = error.toString();
  26. if (stack.indexOf(msg) < 0) {
  27. stack = msg + '@' + stack;
  28. }
  29. return stack;
  30. }
  31. /**
  32. * get comp name
  33. * @param vm
  34. */
  35. function formatComponentName(vm: any) {
  36. if (vm.$root === vm) {
  37. return {
  38. name: 'root',
  39. path: 'root',
  40. };
  41. }
  42. const options = vm.$options as any;
  43. if (!options) {
  44. return {
  45. name: 'anonymous',
  46. path: 'anonymous',
  47. };
  48. }
  49. const name = options.name || options._componentTag;
  50. return {
  51. name: name,
  52. path: options.__file,
  53. };
  54. }
  55. /**
  56. * Configure Vue error handling function
  57. */
  58. function vueErrorHandler(err: Error, vm: any, info: string) {
  59. const errorLogStore = useErrorLogStoreWithOut();
  60. const { name, path } = formatComponentName(vm);
  61. errorLogStore.addErrorLogInfo({
  62. type: ErrorTypeEnum.VUE,
  63. name,
  64. file: path,
  65. message: err.message,
  66. stack: processStackMsg(err),
  67. detail: info,
  68. url: window.location.href,
  69. });
  70. }
  71. /**
  72. * Configure script error handling function
  73. */
  74. export function scriptErrorHandler(
  75. event: Event | string,
  76. source?: string,
  77. lineno?: number,
  78. colno?: number,
  79. error?: Error
  80. ) {
  81. if (event === 'Script error.' && !source) {
  82. return false;
  83. }
  84. const errorInfo: Partial<ErrorLogInfo> = {};
  85. colno = colno || (window.event && (window.event as any).errorCharacter) || 0;
  86. errorInfo.message = event as string;
  87. if (error?.stack) {
  88. errorInfo.stack = error.stack;
  89. } else {
  90. errorInfo.stack = '';
  91. }
  92. const name = source ? source.substr(source.lastIndexOf('/') + 1) : 'script';
  93. const errorLogStore = useErrorLogStoreWithOut();
  94. errorLogStore.addErrorLogInfo({
  95. type: ErrorTypeEnum.SCRIPT,
  96. name: name,
  97. file: source as string,
  98. detail: 'lineno' + lineno,
  99. url: window.location.href,
  100. ...(errorInfo as Pick<ErrorLogInfo, 'message' | 'stack'>),
  101. });
  102. return true;
  103. }
  104. /**
  105. * Configure Promise error handling function
  106. */
  107. function registerPromiseErrorHandler() {
  108. window.addEventListener(
  109. 'unhandledrejection',
  110. function (event) {
  111. const errorLogStore = useErrorLogStoreWithOut();
  112. errorLogStore.addErrorLogInfo({
  113. type: ErrorTypeEnum.PROMISE,
  114. name: 'Promise Error!',
  115. file: 'none',
  116. detail: 'promise error!',
  117. url: window.location.href,
  118. stack: 'promise error!',
  119. message: event.reason,
  120. });
  121. },
  122. true
  123. );
  124. }
  125. /**
  126. * Configure monitoring resource loading error handling function
  127. */
  128. function registerResourceErrorHandler() {
  129. // Monitoring resource loading error(img,script,css,and jsonp)
  130. window.addEventListener(
  131. 'error',
  132. function (e: Event) {
  133. const target = e.target ? e.target : (e.srcElement as any);
  134. const errorLogStore = useErrorLogStoreWithOut();
  135. errorLogStore.addErrorLogInfo({
  136. type: ErrorTypeEnum.RESOURCE,
  137. name: 'Resource Error!',
  138. file: (e.target || ({} as any)).currentSrc,
  139. detail: JSON.stringify({
  140. tagName: target.localName,
  141. html: target.outerHTML,
  142. type: e.type,
  143. }),
  144. url: window.location.href,
  145. stack: 'resource is not found',
  146. message: (e.target || ({} as any)).localName + ' is load error',
  147. });
  148. },
  149. true
  150. );
  151. }
  152. /**
  153. * Configure global error handling
  154. * @param app
  155. */
  156. export function setupErrorHandle(app: App) {
  157. const { useErrorHandle } = projectSetting;
  158. if (!useErrorHandle) {
  159. return;
  160. }
  161. // Vue exception monitoring;
  162. app.config.errorHandler = vueErrorHandler;
  163. // script error
  164. window.onerror = scriptErrorHandler;
  165. // promise exception
  166. registerPromiseErrorHandler();
  167. // Static resource exception
  168. registerResourceErrorHandler();
  169. }