feat(fe/log_error): add error reporter
This commit is contained in:
parent
46e40d1831
commit
3cb711b37e
7 changed files with 107 additions and 15 deletions
|
@ -19,6 +19,7 @@
|
|||
"@types/assert": "^1.4.2",
|
||||
"@types/deep-diff": "^1.0.0",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/object-hash": "^2.2.1",
|
||||
"assert": "^2.0.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"deep-diff": "^1.0.2",
|
||||
|
@ -52,6 +53,7 @@
|
|||
"css-loader": "^5.0.0",
|
||||
"filesize": "^6.1.0",
|
||||
"immutable": "^4.0.0-rc.12",
|
||||
"object-hash": "^2.2.0",
|
||||
"react": "^16.8.6",
|
||||
"react-copy-to-clipboard": "^5.0.1",
|
||||
"react-dom": "^16.8.6",
|
||||
|
|
|
@ -14,9 +14,9 @@ window.onerror = (
|
|||
) => {
|
||||
const lowerMsg = msg.toLowerCase();
|
||||
if (lowerMsg.indexOf("script error") > -1) {
|
||||
ErrorLogger().error(errCorsScript, "Check Browser Console for Detail");
|
||||
ErrorLogger().error("Check Browser Console for Detail");
|
||||
}
|
||||
ErrorLogger().error(`${source}:${lineno}:${colno}: ${error.toString()}`, "");
|
||||
ErrorLogger().error(`${source}:${lineno}:${colno}: ${error.toString()}`);
|
||||
};
|
||||
|
||||
ReactDOM.render(<StateMgr />, document.getElementById("mount"));
|
||||
|
|
|
@ -139,6 +139,7 @@ export interface ISettingsClient {
|
|||
health: () => Promise<Response>;
|
||||
getClientCfg: () => Promise<Response>;
|
||||
setClientCfg: (cfg: ClientConfig) => Promise<Response>;
|
||||
reportError: (content: string, version: string) => Promise<Response>;
|
||||
}
|
||||
|
||||
export interface Response<T = any> {
|
||||
|
|
|
@ -30,4 +30,15 @@ export class SettingsClient extends BaseClient {
|
|||
},
|
||||
});
|
||||
};
|
||||
|
||||
reportError = (content: string, version: string): Promise<Response> => {
|
||||
return this.do({
|
||||
method: "post",
|
||||
url: `${this.url}/v1/settings/errors`,
|
||||
data: {
|
||||
content,
|
||||
version,
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ export interface SettingsClientResps {
|
|||
healthMockResp?: Response;
|
||||
setClientCfgMockResp?: Response;
|
||||
getClientCfgMockResp?: Response<ClientConfigMsg>;
|
||||
reportErrorResp?: Response;
|
||||
}
|
||||
|
||||
export const resps = {
|
||||
|
@ -25,9 +26,14 @@ export const resps = {
|
|||
position: "clientCfg_bg_position",
|
||||
align: "clientCfg_bg_align",
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
reportErrorResp: {
|
||||
status: 200,
|
||||
statusText: "",
|
||||
data: {},
|
||||
},
|
||||
};
|
||||
export class MockSettingsClient {
|
||||
private url: string;
|
||||
|
@ -59,4 +65,8 @@ export class MockSettingsClient {
|
|||
getClientCfg = (): Promise<Response> => {
|
||||
return this.wrapPromise(this.resps.getClientCfgMockResp);
|
||||
};
|
||||
|
||||
reportError = (): Promise<Response> => {
|
||||
return this.wrapPromise(this.resps.reportErrorResp);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,12 +1,27 @@
|
|||
import { Map } from "immutable";
|
||||
import { sha1 } from "object-hash";
|
||||
|
||||
import { ILocalStorage, Storage } from "./localstorage";
|
||||
import { ISettingsClient } from "../client";
|
||||
import { SettingsClient } from "../client/settings";
|
||||
import { ICoreState } from "../components/core_state";
|
||||
import { updater } from "../components/state_updater";
|
||||
|
||||
const errorVer = "0.0.1";
|
||||
const cookieKeyClErrs = "qs_cli_errs";
|
||||
|
||||
export interface ClientErrorV001 {
|
||||
version: string;
|
||||
error: string;
|
||||
state: ICoreState;
|
||||
}
|
||||
|
||||
export interface IErrorLogger {
|
||||
setClient: (client: ISettingsClient) => void;
|
||||
setStorage: (storage: ILocalStorage) => void;
|
||||
error: (key: string, msg: string) => void;
|
||||
report: () => void;
|
||||
error: (msg: string) => null | Error;
|
||||
report: () => Promise<null | Error>;
|
||||
readErrs: () => Map<string, ClientErrorV001>;
|
||||
}
|
||||
|
||||
export class ErrorLog {
|
||||
|
@ -25,18 +40,61 @@ export class ErrorLog {
|
|||
this.storage = storage;
|
||||
}
|
||||
|
||||
error = (key: string, msg: string) => {
|
||||
const existKey = this.storage.get(key);
|
||||
if (existKey === "") {
|
||||
this.storage.set(key, msg);
|
||||
}
|
||||
private getErrorSign = (errMsg: string): string => {
|
||||
return `e:${sha1(errMsg)}`;
|
||||
};
|
||||
|
||||
report = () => {
|
||||
// TODO:
|
||||
// check last submitting, and set submit time
|
||||
// report all errors to backend
|
||||
// clean storage
|
||||
readErrs = (): Map<string, ClientErrorV001> => {
|
||||
const errsStr = this.storage.get(cookieKeyClErrs);
|
||||
const errsObj = JSON.parse(errsStr);
|
||||
return Map(errsObj);
|
||||
};
|
||||
|
||||
private writeErrs = (errs: Map<string, ClientErrorV001>) => {
|
||||
const errsObj = errs.toObject();
|
||||
const errsStr = JSON.stringify(errsObj);
|
||||
this.storage.set(cookieKeyClErrs, errsStr);
|
||||
};
|
||||
|
||||
error = (msg: string): null | Error => {
|
||||
try {
|
||||
const sign = this.getErrorSign(msg);
|
||||
const clientErr: ClientErrorV001 = {
|
||||
version: errorVer,
|
||||
error: msg,
|
||||
state: updater().props,
|
||||
};
|
||||
let errs = this.readErrs();
|
||||
if (!errs.has(sign)) {
|
||||
errs = errs.set(sign, clientErr);
|
||||
this.writeErrs(errs);
|
||||
}
|
||||
} catch (err: any) {
|
||||
return Error(`failed to save err log: ${err}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
report = async (): Promise<null | Error> => {
|
||||
try {
|
||||
const errs = this.readErrs();
|
||||
|
||||
for (let sign of errs.keySeq().toArray()) {
|
||||
const err = errs.get(sign);
|
||||
const resp = await this.client.reportError(sign, JSON.stringify(err));
|
||||
if (resp.status !== 200) {
|
||||
return Error(`failed to report error: ${resp.data}`);
|
||||
}
|
||||
}
|
||||
|
||||
// truncate errors
|
||||
this.writeErrs(Map());
|
||||
} catch (e: any) {
|
||||
return Error(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -1320,6 +1320,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.2.tgz#81f5a039d6ed1941f8cc57506c74e7c2b8fc64b9"
|
||||
integrity sha512-ZHty/hKoOLZvSz6BtP1g7tc7nUeJhoCf3flLjh8ZEv1vFKBWHXcnMbJMyN/pftSljNyy0kNW/UqI3DccnBnZ8w==
|
||||
|
||||
"@types/object-hash@^2.2.1":
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/object-hash/-/object-hash-2.2.1.tgz#67c169f8f033e0b62abbf81df2d00f4598d540b9"
|
||||
integrity sha512-i/rtaJFCsPljrZvP/akBqEwUP2y5cZLOmvO+JaYnz01aPknrQ+hB5MRcO7iqCUsFaYfTG8kGfKUyboA07xeDHQ==
|
||||
|
||||
"@types/prettier@^2.1.5":
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3"
|
||||
|
@ -3768,6 +3773,11 @@ object-assign@^4.1.1:
|
|||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-hash@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5"
|
||||
integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
|
||||
|
||||
object-inspect@^1.11.0, object-inspect@^1.9.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue