Как загрузить Sentry до загрузки основного JS комплекта? - PullRequest
0 голосов
/ 07 февраля 2020

Я использую Sentry для отслеживания ошибок на стороне клиента. Однако сегодня я загрузил свое веб-приложение в браузер Edge, чтобы найти пустую страницу. 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 })],
  });
}

Я думал об инициализации Sentry вручную с помощью тега script около начала тега <body>. Однако тот факт, что я использую плагин VueIntegration, усложняет ситуацию. Будет ли безопасно инициализировать Sentry дважды? Один раз перед загрузкой основного пакета и один раз, как я делаю в приведенном выше примере?

Я заметил, что в документации есть что-то о управлении несколькими клиентами Sentry , но я не уверен, что это так имеет отношение к моему конкретному c случаю.

Одна из идей, которые у меня есть, - это просто скребок window.onerror до того, как что-либо еще загрузится, но я не совсем уверен, как взаимодействовать с Sentry, не вытягивая их @sentry/browser пакет. В идеале я бы просто связывался с их службой, используя простой запрос XHR и мой DSN.

Мой вопрос , каков рекомендуемый способ отслеживания ошибок, возникающих до инициализации Sentry в основном комплекте JS

1 Ответ

1 голос
/ 11 февраля 2020

В итоге я решил эту проблему, добавив базовый хук 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
...