diff --git a/app/lib/express.js b/app/lib/express.js index b65568b..1847040 100644 --- a/app/lib/express.js +++ b/app/lib/express.js @@ -691,6 +691,20 @@ router.get("/debug-error", (_req, res) => { res.send("should never reach here"); }); +router.post("/frontend-error", (req, res) => { + const message = req.body.message; + const stacktrace = req.body.stacktrace; + + if (SENTRY_DSN && process.env.NODE_ENV == "production") { + Sentry.captureEvent({ + message, + stacktrace, + }); + } + + res.send("ok"); +}); + router.get("/metrics", { public: true }, (_req, res) => { res.set("Content-Type", metrics.register.contentType); res.end(metrics.register.metrics()); diff --git a/app/public/js/shared.js b/app/public/js/shared.js index e0ceec4..dc91851 100644 --- a/app/public/js/shared.js +++ b/app/public/js/shared.js @@ -31,3 +31,30 @@ document.addEventListener("readystatechange", (event) => { } }); setTimeout(fixImageHeights, 2000); + +/** + * Client JS error monitoring + */ + +window.debugError = () => { + const throwLevel1 = () => { + throwLevel2(); + }; + const throwLevel2 = () => { + const object = {}; + object.isUndefinedAFunction(); + }; + setTimeout(throwLevel1, 1); +}; + +window.onerror = (message, _url, _lineNo, _columnNo, error) => { + fetch("/frontend-error", { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: + "message=" + + encodeURIComponent(message.toString()) + + "&stacktrace=" + + encodeURIComponent(error.stack), + }); +};