如何追踪JavaScript错误?现有的工具是否有效?

25

今天我发现需要跟踪和检索Javascript错误堆栈以解决它们。

今天我们能够捕获所有的rest调用,这样一来,一旦出错,自动发布该错误的堆栈跟踪加上rest保存服务的响应,这样我们就可以在几乎相同的环境/情况下检测、复制和解决问题。

作为一个要求,我们被要求制作一个可以包含而不具侵入性的模块,例如:将包含钩子逻辑的模块包含在一个JS中,将不具侵入性,在各种JS文件中包含几行代码将具有侵入性。

目标是制作一个可以包含在已经开发的系统中并跟踪错误事件(如console)的工具。

我阅读了关于这些追踪器逻辑的文章:

  • errorception.com/
  • trackjs.com/
  • atatus.com/
  • airbrake.io/
  • jslogger.com/
  • getsentry.com/
  • muscula.com/
  • debuggify.net/
  • raygun.io/home

我们需要做类似的事情,跟踪错误并将其发送到我们的服务器。

正如“Dagg Nabbit”所说...“目前很难从‘野外’错误中获取堆栈跟踪”...

所以,我们有很多付费产品,但它们真的是如何运作的呢?

在Airbrake中,他们使用堆栈跟踪和window.onerror:

window.onerror = function(message, file, line) {
  setTimeout(function() {
    Hoptoad.notify({
      message : message,
      stack   : '()@' + file + ':' + line
    });
  }, 100);
  return true;
};

但我无法确定堆栈跟踪何时真正被使用。

在某些情况下,堆栈跟踪、raven.js和其他跟踪器需要尝试/捕获。

  1. 如果我们找到一种方法来创建全局包装器会发生什么?
  2. 我们可以只调用堆栈跟踪并等待捕获吗?

当客户端出现意外错误时,如何将堆栈跟踪发送到我的服务器?有什么建议或良好实践?


我知道 https://appenlight.com/ 这个网站提供免费账户,但有一些限制。不过对于开源项目来说是免费的。虽然这个问题是关于寻找产品的,但我认为在它被删除之前,我可以提供一些替代方案。 - Loïc Faure-Lacroix
@DaggNabbit 如果你使用过这个产品或者阅读了文档,那么就很清楚了。 - Matt Ball
@MattBall Raven: “context/wrap - Raven.context允许您包装任何函数以立即执行。在幕后,Raven只是将您的代码包装在try...catch块中。”是否有任何方法可以创建一个总体包装器? - Da3
1
@Da3 你可以创建一个脚本加载器函数,而不是以通常的方式加载脚本。它可以使用XHR获取脚本,在它们周围添加try ... catch,并评估它们或将它们放入脚本标签中。这将带来一系列其他问题,比如遇到同源策略,并使堆栈跟踪中的文件名无用。另一个选择可能是设置一个服务器端脚本加载器代理,执行相同的操作;这可能会非常有效。 - Dagg Nabbit
1
@Da3 在你的服务器上设置一些东西来处理像 {domain}/jsproxy/{scheme}/{url} 这样的 URL,例如 yourserver.com/jsproxy/http/code.jquery.com/jquery.js。你可以像这个 PHP 示例 一样抓取文件并提供服务,或者你可以将它们缓存到磁盘或内存中,并检查远程资源的更改而不是每次都获取它们。 - Dagg Nabbit
显示剩余10条评论
4个回答

11

目前从“野外”错误中获取堆栈跟踪很困难,因为Error对象对于window.onerror不可用。

window.onerror = function(message, file, line) { }

还有一个新的error事件, 但是该事件目前尚未公开Error对象。

window.addEventListener('error', function(errorEvent) { })

很快,window.onerror 将会得到一个包含错误对象的第五个参数,你可以使用 stacktrace.jswindow.onerror 期间获取堆栈跟踪。

<script src="stacktrace.js"></script>
<script>
window.onerror = function(message, file, line, column, error) {
    try {
        var trace = printStackTrace({e: error}).join('\n');
        var url = 'http://yourserver.com/?jserror=' + encodeURIComponent(trace);
        var p = new printStackTrace.implementation();
        var xhr = p.createXMLHTTPObject();

        xhr.open('GET', url, true);
        xhr.send(null);
    } catch (e) { }
}
</script>

在某个时间点,错误API可能会被标准化,但目前每个实现都不同,因此最好使用类似stacktracejs的东西来获取堆栈跟踪,因为这样做需要为每个浏览器分别编写代码路径。


window.onerror错误对象仅适用于Chrome浏览器。据我所知,其他浏览器都没有承诺支持它。 - Todd H. Gardner
@ToddGardner 说得好。考虑到现在 onerror 的无用性,我预计他们最终会效仿,但你永远不知道。 - Dagg Nabbit
我相信Mozilla会做到,可能IE12也会。但不幸的是,我们还需要一段时间来处理那些不能支持它的旧浏览器 :( - Todd H. Gardner
1
针对参考此内容的人更新 - 在大多数或所有主要浏览器的最新版本中,window.onerror 现在会接收到一个错误(Error)。 - Eric Wendelin

8

我是上文提到的TrackJS的联合创始人。你说得对,有时候获取堆栈跟踪需要花费一些功夫。在某种程度上,异步函数必须包裹在try/catch块中 - 但我们会自动完成这个过程!

在TrackJS 2.0+中,传递给回调函数(addEventListenersetTimeout等)的任何函数都会自动被包裹在try/catch块中。我们发现,通过这种方式可以几乎捕获所有错误。

对于那些我们可能未能捕获的少数情况,您始终可以自己尝试使用try/catch语句。我们提供了一些有用的包装器,以帮助您进行尝试,例如:

function foo() {
  // does stuff that might blow up
}

trackJs.watch(foo);

1
在TrackJS 2.0+中,您传递到回调函数(addEventListener、setTimeout等)的任何函数都将自动包装在try/catch中[...]。这对性能有什么影响? - Gajus
1
@Gajus,只有包装函数的开销,例如:function foo() {...} function bar() { return foo(); }增量成本仅为调用 bar() 而不是 foo() - Todd H. Gardner

4
在最新的浏览器中,window.onerror 的错误对象有第五个参数。 在 addEventListener 中,你可以通过 event.error 获取错误对象。
// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) {
    console.log(message, "from", error.stack);
    // You can send data to your server
    // sendData(data);
};
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (event) {
    console.log(e.error.message, "from", event.error.stack);
    // You can send data to your server
    // sendData(data);
})

您可以使用以下方式使用图像标签发送数据
function sendData(data) {
    var img = newImage(),
        src = http://yourserver.com/jserror + '&data=' + encodeURIComponent(JSON.stringify(data));

    img.crossOrigin = 'anonymous';
    img.onload = function success() {
        console.log('success', data);
    };
    img.onerror = img.onabort = function failure() {
        console.error('failure', data);
    };
    img.src = src;
}

如果您正在寻找开源项目,那么可以查看TraceKit。TraceKit会尽可能地提取有用信息并对其进行规范化处理。您可以注册错误报告的订阅者:
TraceKit.report.subscribe(function yourLogger(errorReport) {
    // sendData(data);
});

然而,您需要进行后端以收集数据并进行前端以可视化数据。
免责声明:我是https://www.atatus.com/的Web开发人员,在这里您可以跟踪所有JavaScript错误,并根据浏览器、用户、URL、标签等各种维度过滤错误。

0
@Da3 你问到了关于appenlight和堆栈跟踪的问题。是的,只要你将异常包装在try/catch块中,它就可以收集完整的堆栈跟踪信息。否则,它将尝试从window.onerror中读取信息,但这非常有限。这是浏览器的限制(可能会在未来得到修复)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接