add rudimentary error reporting in a new tab
This commit is contained in:
parent
bf70e752b6
commit
21c176a69e
@ -208,6 +208,44 @@ export async function recordException(msg: string, e: any): Promise<void> {
|
||||
return record("error", e.toString(), stack, frame.file, frame.line, frame.column);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cache for reports. Also used when something is so broken that we can't even
|
||||
* access the database.
|
||||
*/
|
||||
const reportCache: { [reportId: string]: any } = {};
|
||||
|
||||
|
||||
/**
|
||||
* Get a UUID that does not use cryptographically secure randomness.
|
||||
* Formatted as RFC4122 version 4 UUID.
|
||||
*/
|
||||
function getInsecureUuid() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store a report and return a unique identifier to retrieve it later.
|
||||
*/
|
||||
export async function storeReport(report: any): Promise<string> {
|
||||
const uid = getInsecureUuid();
|
||||
reportCache[uid] = report;
|
||||
return uid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a report by its unique identifier.
|
||||
*/
|
||||
export async function getReport(reportUid: string): Promise<any> {
|
||||
return reportCache[reportUid];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record a log entry in the database.
|
||||
*/
|
||||
@ -218,6 +256,8 @@ export async function record(level: Level,
|
||||
line?: number,
|
||||
col?: number): Promise<void> {
|
||||
if (typeof indexedDB === "undefined") {
|
||||
console.log("can't access DB for logging in this context");
|
||||
console.log("log was", { level, msg, detail, source, line, col });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -257,7 +297,7 @@ export async function record(level: Level,
|
||||
}
|
||||
}
|
||||
|
||||
const loggingDbVersion = 1;
|
||||
const loggingDbVersion = 2;
|
||||
|
||||
const logsStore: Store<LogEntry> = new Store<LogEntry>("logs");
|
||||
|
||||
@ -283,7 +323,8 @@ export function openLoggingDb(): Promise<IDBDatabase> {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
resDb.createObjectStore("logs", {keyPath: "id", autoIncrement: true});
|
||||
resDb.createObjectStore("logs", { keyPath: "id", autoIncrement: true });
|
||||
resDb.createObjectStore("reports", { keyPath: "uid", autoIncrement: false });
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -176,6 +176,14 @@ export interface MessageMap {
|
||||
request: { };
|
||||
response: void;
|
||||
};
|
||||
"log-and-display-error": {
|
||||
request: any;
|
||||
response: void;
|
||||
};
|
||||
"get-report": {
|
||||
request: { reportUid: string };
|
||||
response: void;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,40 +22,69 @@
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import URI = require("urijs");
|
||||
|
||||
import * as wxApi from "../wxApi";
|
||||
|
||||
interface ErrorProps {
|
||||
message: string;
|
||||
report: any;
|
||||
}
|
||||
|
||||
class ErrorView extends React.Component<ErrorProps, { }> {
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<div>
|
||||
An error occurred: {this.props.message}
|
||||
</div>
|
||||
);
|
||||
const report = this.props.report;
|
||||
if (!report) {
|
||||
return (
|
||||
<div>
|
||||
<h1>Error Report Not Found</h1>
|
||||
<p>This page is supposed to display an error reported by the GNU Taler wallet,
|
||||
but the corresponding error report can't be found.</p>
|
||||
<p>Maybe the error occured before the browser was restarted or the wallet was reloaded.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
switch (report.name) {
|
||||
default:
|
||||
return (
|
||||
<div>
|
||||
<h1>Unknown Error</h1>
|
||||
The GNU Taler wallet reported an unknown error. Here are the details:
|
||||
<pre>
|
||||
{JSON.stringify(report, null, " ")}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const url = new URI(document.location.href);
|
||||
const query: any = URI.parseQuery(url.query());
|
||||
const url = new URI(document.location.href);
|
||||
const query: any = URI.parseQuery(url.query());
|
||||
|
||||
const message: string = query.message || "unknown error";
|
||||
|
||||
ReactDOM.render(<ErrorView message={message} />, document.getElementById(
|
||||
"container")!);
|
||||
|
||||
} catch (e) {
|
||||
// TODO: provide more context information, maybe factor it out into a
|
||||
// TODO:generic error reporting function or component.
|
||||
document.body.innerText = `Fatal error: "${e.message}".`;
|
||||
console.error(`got error "${e.message}"`, e);
|
||||
const container = document.getElementById("container");
|
||||
if (!container) {
|
||||
console.error("fatal: can't mount component, countainer missing");
|
||||
return;
|
||||
}
|
||||
|
||||
// report that we'll render, either looked up from the
|
||||
// logging module or synthesized here for fixed/fatal errors
|
||||
let report;
|
||||
|
||||
const reportUid: string = query.reportUid;
|
||||
if (!reportUid) {
|
||||
report = {
|
||||
name: "missing-error",
|
||||
};
|
||||
} else {
|
||||
report = await wxApi.getReport(reportUid);
|
||||
}
|
||||
|
||||
ReactDOM.render(<ErrorView report={report} />, container);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => main());
|
||||
|
@ -321,3 +321,11 @@ export function getSenderWireInfos(): Promise<SenderWireInfos> {
|
||||
export function returnCoins(args: { amount: AmountJson, exchange: string, senderWire: object }): Promise<void> {
|
||||
return callBackend("return-coins", args);
|
||||
}
|
||||
|
||||
export function logAndDisplayError(args: any): Promise<void> {
|
||||
return callBackend("log-and-display-error", args);
|
||||
}
|
||||
|
||||
export function getReport(reportUid: string): Promise<void> {
|
||||
return callBackend("get-report", { reportUid });
|
||||
}
|
||||
|
@ -303,6 +303,15 @@ function handleMessage(sender: MessageSender,
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
case "log-and-display-error":
|
||||
logging.storeReport(detail).then((reportUid) => {
|
||||
chrome.tabs.create({
|
||||
url: chrome.extension.getURL(`/src/webex/pages/error.html?reportUid=${reportUid}`),
|
||||
});
|
||||
});
|
||||
return;
|
||||
case "get-report":
|
||||
return logging.getReport(detail.reportUid);
|
||||
default:
|
||||
// Exhaustiveness check.
|
||||
// See https://www.typescriptlang.org/docs/handbook/advanced-types.html
|
||||
|
Loading…
Reference in New Issue
Block a user