我正在使用错误边界组件来捕获反应错误,它工作正常。
我的问题是,在生产应用程序中,日志记录有点无用,因为组件堆栈看起来像这样:
\n in t\n in t\n in t\n in t\n in t\n in div\n in t\n in u\n in n\n in t\n in t
在开发环境中,组件堆栈更有用:
in ErrorPage (created by Route)\n in Route (at Routes.js:60)\n in Switch (at Routes.js:46)\n in Router (created by BrowserRouter)\n in BrowserRouter (at Routes.js:45)\n in div (at Routes.js:43)\n in ThemeProvider (at theme.js:1262)\n in Theme (at Routes.js:42)\n in Provider (at Routes.js:41)\n in ErrorBoundary (at Routes.js:40)\n in Routes (at index.js:12)
消息也是如此。在生产中我们得到:
t.value (http://localhost:3333/static/js/main.5a3e606e.js:1:680858
在开发中:
Uncaught TypeError: Person is not a constructor
at ErrorPage._this.click2 (ErrorPage.js:12)
有没有办法让反应错误映射到源代码,使日志记录在生产中实际可用?
更新: 我正在使用一个名为http://js.jsnlog.com/的库来处理日志并实际捕获所有内容(甚至是事件处理程序)。这就是Boundary组件的外观https://pastebin.com/aBFtD7DB。问题不在于捕捉错误,但在生产中它们是无用的。
答案 0 :(得分:2)
我使用库https://www.stacktracejs.com/找到了解决方案。
方法StackTrace.report()方法将获取地图并为您提供所需的未经授权的信息!
所以现在我的React Boundary看起来像这样。我仍然使用window.onerror来确保抓住所有内容。
首先,请务必将stacktrace-gps
和stacktrace-js
添加到您的package.json
import React, { Component } from "react";
import StackTrace from "stacktrace-js";
window.onerror = function(msg, file, line, col, error) {
StackTrace.fromError(error).then(err => {
StackTrace.report(
err,
`//${window.location.hostname}:${process.env.REACT_APP_LOGGER_PORT || 3334}/jsnlog.logger`,
{
type: "window.onerror",
url: window.location.href,
userId: window.userId,
agent: window.navigator.userAgent,
date: new Date(),
msg: msg
}
);
});
};
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { error: null };
}
componentDidCatch(error, errorInfo) {
this.setState({ error });
StackTrace.fromError(error).then(err => {
StackTrace.report(
err,
`//${window.location.hostname}:${process.env.REACT_APP_LOGGER_PORT || 3334}/jsnlog.logger`,
{
type: "React boundary",
url: window.location.href,
userId: window.userId,
agent: window.navigator.userAgent,
date: new Date(),
msg: error.toString()
}
);
});
}
render() {
if (this.state.error) {
//render fallback UI
return (
<div className="snap text-center">
<p>We're sorry — something's gone wrong.</p>
<p>Our team has been notified</p>
</div>
);
} else {
//when there's not an error, render children untouched
return this.props.children;
}
}
}
export default ErrorBoundary;
答案 1 :(得分:0)
首先,创建源映射很重要。我是通过在Webpack配置中添加devtools来创建源地图来实现的。简短的摘要如下:
devtools: "source-map",
new UglifyJsPlugin({
sourceMap: true
})
创建源地图后,我就使用了https://www.stacktracejs.com/库。
但是,为了减少生产中的捆绑包大小,我没有导入整个stacktrace捆绑包。我通过将客户端代码和服务器端分开来实现。
客户端: 我导入了error-stack-parser。这将创建一个对象,其中包含文件名,行号,列号和函数名。我将使用它创建的对象发送到服务器。
import ErrorStackParser from "error-stack-parser";
componentDidCatch(error) {
let params = {stackframes: ErrorStackParser.parse(error)};
let url = 'https://example.com';
axios.post(url, params)
}
在服务器端,我导入了"stacktrace-gps"和"stackframe"并用它来查找它,以便从源映射中获取实际代码的行号和列。
const StackTraceGPS = require("stacktrace-gps");
const request = require("request");
var logger = function(req, res) {
let stackframes = req.body.stackframes;
let stackframe = new StackFrame(
stackframes[0]
); /* Getting stack of the topmost element as it contains the most important information */
/* We send extra ajax function to fetch source maps from url */
const gps = new StackTraceGPS({
ajax: url => {
return new Promise((resolve, reject) => {
request(
{
url,
method: "get"
},
(error, response) => {
if (error) {
reject(error);
} else {
resolve(response.body);
}
}
);
});
}
});
gps.pinpoint(stackframe).then(
info => {
console.log(info); /* Actual file Info*/
},
err => {
console.log(err);
}
);
};
这减小了包的大小,并使您能够在服务器端记录错误。