123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- import { store } from "@/store/store";
- import moment from "moment";
- import { omit } from "lodash-es";
- import SlsWebLogger from "js-sls-logger";
- import { VITE_SLS_STORE_NAME } from "@/constants/constants";
- import { electronLog } from "./electronLog";
- import getDeviceInfos from "./deviceInfo";
- import { isElectron } from "./nativeMethods";
- const aliLogger = new SlsWebLogger({
- host: "cn-shenzhen.log.aliyuncs.com",
- project: "examcloud",
- logstore: VITE_SLS_STORE_NAME,
- });
- type LogDetail = {
- /** default log */
- lvl?: "debug" | "log" | "warn" | "error";
- /** channels. 往哪些渠道放日志? default: ['console'] */
- cnl: ("console" | "local" | "server" | "bd")[];
- /** 操作的类型,方便在日志里面查找相同类型的操作 */
- key?: string;
- /** page name */
- pgn?: string;
- /** page url: AUTO => 自动从location.path获取 */
- pgu?: "AUTO" | `/${string}`;
- /** action 引发本次日志的操作 */
- act?: string;
- /** statck 错误信息的stack,单条错误信息也放此处 */
- stk?: string;
- /** detail 错误详细信息 */
- dtl?: string;
- /** api url */
- aul?: string;
- /** api status */
- aus?: string;
- /** error json */
- ejn?: string;
- /** 扩展字段的集合。TODO: 提示不允许出去前面的字段 */
- // "not in keyof T" - exclude keyof T from string #42315
- // https://github.com/microsoft/TypeScript/issues/42315
- ext?: Record<string, any>;
- };
- /** 记录重要日志到多个source
- * 示例:
- * @param detail.key - '本地人脸比对'
- * @param detail.pgn - '登录页面' | '在线考试列表页面'
- * @param detail.act - '点击登录按钮'
- * @param detail.cnl - ['local', 'console']
- * @param detail.stk - error.stack
- * @param detail.dtl - '第一次点击登录' | '第二次点击登录' // 方便查询
- * @param detail.aul - '/api/login'
- * @param detail.aus - '500'
- * @param detail.ejn - JSON.stringify({a: 0})
- * @param detail.ext - {UA: 'chrome 99'}
- */
- export default function createLog(detail: LogDetail) {
- const user = store.user;
- const defaultFileds = {
- /** 供灰度发布识别日志 */
- __ver: "3.0.0",
- lvl: "log",
- uuidForEcs: localStorage.getItem("uuidForEcs"),
- clientDate: moment().format("YYYY-MM-DD HH:mm:ss.SSS"),
- ...(user?.id ? { userId: user.id } : {}),
- ...(detail?.cnl ? { cnl: detail.cnl } : { cnl: ["console"] }),
- };
- const newDetail = Object.assign(
- defaultFileds,
- omit(detail, "ext"),
- detail.ext
- );
- // FIXME: 后期设置条件开启非log级别的日志,此时全部打回。
- if (newDetail.lvl !== "log") {
- return;
- }
- if (detail.cnl?.includes("console")) {
- if (import.meta.env.DEV) {
- console.log(
- omit(newDetail, ["__ver", "cnl", "lvl", "uuidForEcs", "clientDate"])
- );
- } else {
- console.log(newDetail);
- }
- }
- if (!import.meta.env.DEV && detail.cnl?.includes("server")) {
- aliLogger.send(newDetail);
- }
- if (detail.cnl?.includes("local") && electronLog) {
- void electronLog(newDetail);
- }
- }
- /** 要在用户登录后调用,仅需调用一次 */
- export function createUserDetailLog() {
- const ext: Record<string, any> = {};
- const user = store.user;
- const deviceInfos = getDeviceInfos();
- const { displayName, identityNumber, rootOrgName, rootOrgId } = store.user;
- Object.assign(
- ext,
- { displayName, identityNumber, rootOrgName, rootOrgId },
- { userStudentCodeList: user.studentCodeList.join(",") },
- { UA: navigator.userAgent },
- deviceInfos
- );
- createLog({ cnl: ["server"], pgn: "登录页面", act: "登录成功日志", ext });
- }
- export function createEncryptLog() {
- // 非 electron 返回
- if (!isElectron()) return;
- try {
- const uuidForEcs = localStorage.getItem("uuidForEcs");
- // 没有 uuidForEcs 日志没法查询
- if (!uuidForEcs) return;
- let log = null;
- let lastLogIndex: number = +(localStorage.getItem("lastLogIndex") || 0);
- log = window.nodeRequire("electron-log");
- // const filePath = log.getFile().path;
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
- const filePath: string = log.transports.file.findLogPath();
- const fs: typeof import("fs") = window.nodeRequire("fs");
- const content = fs.readFileSync(filePath, "utf-8");
- const ary = content.toString().split("\r\n").join("\n").split("\n");
- // 重复上传没有时间的行:跨过非时间戳的行; 错误识别:全部重新执行
- // let lastIndex = ary.findIndex(v => v === lastLog);
- // console.log({ lastIndex });
- if (ary.length < lastLogIndex) {
- lastLogIndex = 0;
- }
- const logLen = 10;
- const newAry = ary
- .slice(lastLogIndex, lastLogIndex + logLen)
- .filter((v) => v);
- // 如果没有上传的内容,则不修改lastLog, 也不上传
- if (!newAry.length) return;
- lastLogIndex = lastLogIndex + newAry.length;
- localStorage.setItem("lastLogIndex", lastLogIndex + "");
- createLog({ cnl: ["server"], ext: { encryptLog: newAry.join("\n") } });
- } catch (error) {
- console.debug(error);
- return;
- }
- }
|