Sfoglia il codice sorgente

vue 全局错误处理

Michael Wang 3 anni fa
parent
commit
072d639a24
4 ha cambiato i file con 119 aggiunte e 1 eliminazioni
  1. 2 0
      src/main.ts
  2. 6 1
      src/utils/logger.ts
  3. 81 0
      src/utils/monitors.ts
  4. 30 0
      src/utils/ua.ts

+ 2 - 0
src/main.ts

@@ -5,10 +5,12 @@ import App from "./App.vue";
 import router from "@/router";
 import router from "@/router";
 import filters from "@/filters";
 import filters from "@/filters";
 import { createPinia } from "pinia";
 import { createPinia } from "pinia";
+import { vueErrorHandler } from "./utils/monitors";
 
 
 const app = createApp(App);
 const app = createApp(App);
 app.use(router);
 app.use(router);
 app.use(createPinia());
 app.use(createPinia());
 app.config.globalProperties.$filters = filters;
 app.config.globalProperties.$filters = filters;
+app.config.errorHandler = vueErrorHandler;
 
 
 app.mount("#app");
 app.mount("#app");

+ 6 - 1
src/utils/logger.ts

@@ -13,8 +13,9 @@ const aliLogger = new SlsWebLogger({
 });
 });
 
 
 type LogDetail = {
 type LogDetail = {
+  /** default log */
   level?: "debug" | "log" | "warn" | "error";
   level?: "debug" | "log" | "warn" | "error";
-  /** channels. 往哪些渠道放日志? */
+  /** channels. 往哪些渠道放日志? default: ['console'] */
   cnl?: ("console" | "local" | "server" | "bd")[];
   cnl?: ("console" | "local" | "server" | "bd")[];
   /** 操作的类型,方便在日志里面查找相同类型的操作 */
   /** 操作的类型,方便在日志里面查找相同类型的操作 */
   key?: string;
   key?: string;
@@ -44,6 +45,7 @@ type LogDetail = {
  * @param detail.key - '本地人脸比对'
  * @param detail.key - '本地人脸比对'
  * @param detail.pgn - '登录页面' | '在线考试列表页面'
  * @param detail.pgn - '登录页面' | '在线考试列表页面'
  * @param detail.act - '点击登录按钮'
  * @param detail.act - '点击登录按钮'
+ * @param detail.cnl - ['local', 'console']
  * @param detail.stk - error.stack
  * @param detail.stk - error.stack
  * @param detail.dtl - '第一次点击登录' | '第二次点击登录' // 方便查询
  * @param detail.dtl - '第一次点击登录' | '第二次点击登录' // 方便查询
  * @param detail.aul - '/api/login'
  * @param detail.aul - '/api/login'
@@ -54,10 +56,13 @@ type LogDetail = {
 export default function createLog(detail: LogDetail) {
 export default function createLog(detail: LogDetail) {
   const user = store.user;
   const user = store.user;
   const defaultFileds = {
   const defaultFileds = {
+    /** 供灰度发布识别日志 */
+    __ver: "3.0.0",
     level: "log",
     level: "log",
     uuidForEcs: localStorage.getItem("uuidForEcs"),
     uuidForEcs: localStorage.getItem("uuidForEcs"),
     clientDate: moment().format("YYYY-MM-DD HH:mm:ss.SSS"),
     clientDate: moment().format("YYYY-MM-DD HH:mm:ss.SSS"),
     ...(user?.id ? { userId: user.id } : {}),
     ...(user?.id ? { userId: user.id } : {}),
+    ...(detail?.cnl ? { cnl: detail.cnl } : { cnl: ["console"] }),
   };
   };
   const newDetail = Object.assign(
   const newDetail = Object.assign(
     defaultFileds,
     defaultFileds,

+ 81 - 0
src/utils/monitors.ts

@@ -0,0 +1,81 @@
+import { ComponentPublicInstance } from "vue";
+
+export function vueErrorHandler(
+  error: unknown,
+  instance: ComponentPublicInstance | null,
+  // `info` is a Vue-specific error info,
+  // e.g. which lifecycle hook the error was thrown in
+  info: string
+) {
+  // window._hmt.push(["_trackEvent", "Vue组件错误"]);
+  logger({
+    level: "error",
+    cnl: ["console", "server"],
+    key: "Vue组件错误",
+    pgu: "AUTO",
+    ext: {
+      error,
+      errorJSON: JSON.stringify(error, (key, value) =>
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+        key === "token" ? "" : value
+      ),
+      info,
+    },
+  });
+  console.trace("vue error", instance, info);
+  throw error;
+}
+
+window.addEventListener("error", function (event) {
+  logger({
+    key: "全局JS错误",
+    cnl: ["console", "local", "server"],
+    pgu: "AUTO",
+    ext: {
+      message: event.message,
+      errorJSON: JSON.stringify(event.error, (key, value) =>
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+        key === "token" ? "" : value
+      ),
+      errorName: event.error.name,
+      errorMessage: event.error.message,
+      errorStack: event.error.stack,
+      errorFileName: event.error.filename,
+      errorLineNo: event.error.lineno,
+      errorColNo: event.error.colno,
+    },
+  });
+  console.trace(event);
+});
+
+window.addEventListener("unhandledrejection", function (event) {
+  // 此错误由上传阿里云日志触发,会被重复好几次
+  // 改为fetch,阿里云日志的错误不应该触发到这里
+
+  try {
+    // 会造成死循环,logger.log 在网络异常的情况下,会有unhandledrejection
+    logger({
+      key: "unhandledrejection",
+      cnl: ["console", "local", "server"],
+      pgu: "AUTO",
+      dtl: event.reason,
+      ejn: JSON.stringify(event.reason),
+    });
+    console.trace(event);
+  } catch {
+    logger({
+      cnl: ["console", "local"],
+      pgu: "AUTO",
+      dtl: "promise error log",
+    });
+  }
+});
+
+window.addEventListener("rejectionhandled", function (event) {
+  console.log("rejectionhandled", event); // 似乎并不触发
+  logger({
+    pgu: "AUTO",
+    cnl: ["console", "local", "server"],
+    dtl: event.reason,
+  });
+});

+ 30 - 0
src/utils/ua.ts

@@ -0,0 +1,30 @@
+import UAParser from "ua-parser-js";
+
+const examShellRegex = [
+  [/(electron-exam-shell)\/([\w.]+)/i],
+  [UAParser.BROWSER.NAME, UAParser.BROWSER.VERSION],
+];
+export default new UAParser(
+  navigator.userAgent,
+  // "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) electron-exam-shell/2.0.0 Chrome/77.0.3865.120 Safari/537.36 ",
+  { browser: examShellRegex }
+);
+
+export const chromeUA = new UAParser(
+  navigator.userAgent.replace("electron-exam-shell/", "")
+).getBrowser();
+
+// const UA = new UAParser(
+//   // null,
+//   "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) electron-exam-shell/2.0.0 Chrome/76.0.3809.139 Electron/6.0.7 Safari/537.36",
+//   // navigator.userAgent,
+//   { browser: examShellRegex }
+// );
+// console.log(UA.getResult());
+
+// window.UA = new UAParser(
+//   // null,
+//   navigator.userAgent,
+//   // "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) electron-exam-shell/2.0.0 Chrome/77.0.3865.120 Safari/537.36 ",
+//   { browser: examShellRegex }
+// );