【问题标题】:How do I load Sentry before the main JS bundle loads?如何在主 JS 包加载之前加载 Sentry?
【发布时间】:2020-05-23 06:50:00
【问题描述】:

我使用 Sentry 来跟踪客户端错误。但是,我今天在 Edge 浏览器中加载了我的 Web 应用程序,却发现一个空白页面。 Edge 引发了 TextEncoder is not defined 错误,因为我的包中的一个库引用了它不支持的 TextEncoder。 Sentry 没有报错,因为错误发生在 Sentry 初始化之前。

我使用 vue-cli 创建了一个 Vue 项目,其中 Sentry 在主文件顶部附近被初始化:

import { init } from '@sentry/browser';
import { environment } from '@/constants';
import { Vue as VueIntegration } from '@sentry/integrations';

export default function(Vue) {
  const debug = environment !== 'production';

  init({
    dsn: 'redacted',
    environment,
    debug,
    integrations: [new VueIntegration({ Vue, logErrors: debug })],
  });
}

我一直在考虑使用<body> 标记开头附近的脚本标记手动初始化 Sentry。然而,我使用VueIntegration 插件的事实使事情复杂化了。两次初始化 Sentry 是否安全?一次是在加载主包之前,一次是像我在上面的示例中所做的那样?

我注意到文档中有关于 managing multiple Sentry clients 的内容,但我不确定这是否与我的具体案例相关。

我的一个想法只是一个准系统 window.onerror 钩子,然后再加载其他任何东西,但我不确定如何在不拉入 @sentry/browser 包的情况下与 Sentry 交互。理想情况下,我会使用简单的 XHR 请求和我的 DSN 与他们的服务进行通信。

我的问题是在主 JS 包中初始化 Sentry 之前跟踪发生的错误的推荐方法是什么?

【问题讨论】:

  • 我很好奇为什么这个请求会因固执己见而关闭?我真的只是在问如何跟踪在主单页应用程序包加载之前/期间发生的错误。您可以将 Sentry 替换为 并根据需要删除 Edge 的背景故事。

标签: vue.js webpack vue-cli sentry


【解决方案1】:

我最终通过添加一个准系统window.onerror 钩子来解决它,该钩子在主包到达之前内联加载。错误会立即发送到我们的 API,然后发送到我们的 Slack #alerts 频道。我添加了速率限制,这样人们就不会滥用它(太多)。

index.html(由vue-cli生成,新的script标签除外):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
/>
    <title>App title</title>
  </head>
  <body>
    <script>
      // This gives us basic error tracking until the main app bundle loads and
      // initializes Sentry. Allows us to catch errors that would surface before
      // Sentry has a chance to catch them like Edge's `TextEncoder is not defined`.
      (function() {
        function sendBasicClientError(message, error) {
          var xhr = new XMLHttpRequest();
          var domain =
            window.location.hostname === 'localhost'
              ? 'http://localhost:5000'
              : 'https://example.com';

          xhr.open('POST', domain + '/api/v1/basic_client_errors');
          xhr.setRequestHeader(
            'Content-Type',
            'application/vnd.api+json; charset=utf-8'
          );
          xhr.send(
            JSON.stringify({
              data: {
                type: 'basic_client_error',
                attributes: {
                  error_message: 'Init error: ' + message + ' ' + navigator.userAgent,
                  error: error
                    ? JSON.parse(
                        JSON.stringify(error, Object.getOwnPropertyNames(error))
                      )
                    : null,
                },
              },
            })
          );
        }

        window.onerror = function(message, filename, lineno, colno, error) {
          sendBasicClientError(
            message + ' ' + filename + ':' + lineno + ':' + colno,
            error
          );
        };
      })();
    </script>

    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

在 Sentry 加载之前,我们清除了钩子:

// Clears the simple `window.onerror` from `index.html` so that Sentry can
// take over now that it's ready.
window.onerror = () => {};

init({
  dsn: 'redacted',
  environment,
  debug,
  integrations: [new VueIntegration({ Vue, logErrors: debug })],
});

Rails 控制器:

module Api
  module V1
    class BasicClientErrorsController < ApplicationController
      def create
        # Can comment out if not using the `pundit` gem.
        skip_authorization

        # We use `sidekiq` and `slack-ruby-client` gems here.
        # Substitute whatever internal error tracking tool you use.               
        SlackNotifierWorker.perform_async(
          basic_client_error_params[:error_message], 
          '#alerts'
        )

        head :accepted
      end

      private

      def basic_client_error_params
        # We use the `restful-jsonapi` gem to parse the JSON:API format.
        restify_param(:basic_client_error).require(:basic_client_error).permit(
          :error_message
        )
      end
    end
  end
end

使用rack-attack gem 限制速率:

Rack::Attack.throttle('limit public basic client errors endpoint', limit: 1, period: 60.seconds.to_i) do |req|
  req.ip if req.path.end_with?('/basic_client_errors') && req.post?
end

【讨论】:

    【解决方案2】:

    你试过这个Laxy loading Sentry 吗?

    这里有提到,如果将data-lazy设置为no,或者使用forceLoad,它会尽快尝试获取Sentry SDK。

    这个问题应该由加载器处理,如here所述:

    当前限制 因为我们异步注入我们的 SDK,我们只会为您监控全局错误和未处理的承诺,直到 SDK 完全加载。这意味着我们可能会在下载过程中错过面包屑。

    例如,用户点击您网站上的按钮正在发出 XHR 请求。我们不会错过任何错误,只有面包屑,直到 SDK 完全加载。您可以通过手动调用 forceLoad 或设置 data-lazy="no" 来减少此时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-16
      相关资源
      最近更新 更多