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