javascript: report upload FileReader errors to Sentry

We have quite a lot of `Error reading file` errors when uploading files.
These errors are generated by ActiveStorage `file_checksum.js` component
but it eats the actual reason of errors.

(See https://github.com/rails/rails/blob/5-2-stable/activestorage/app/javascript/activestorage/file_checksum.js#L38)

We can't really override the class to generate better errors, as they
are deeply nested in ActiveStorage class hierarchy, and not exported to
external code.

Instead, we hook into the FileReader event handler, to insert a logger
when this error occur. The original event handler will also still be
called as usual.

This is intended to be temporary. The debug code will be removed once
we get a better idea of what is going on.
This commit is contained in:
Pierre de La Morinerie 2020-04-20 13:07:44 +00:00
parent 24a14262e7
commit ef009f73e2

View file

@ -1,7 +1,13 @@
import Rails from '@rails/ujs'; import Rails from '@rails/ujs';
import AutoUploadController from './auto-upload-controller.js'; import AutoUploadController from './auto-upload-controller.js';
import { fire } from '@utils';
import { FAILURE_CONNECTIVITY } from '../../shared/activestorage/file-upload-error'; import { FAILURE_CONNECTIVITY } from '../../shared/activestorage/file-upload-error';
//
// DEBUG
//
const originalImpl = FileReader.prototype.addEventListener;
// Manage multiple concurrent uploads. // Manage multiple concurrent uploads.
// //
// When the first upload starts, all the form "Submit" buttons are disabled. // When the first upload starts, all the form "Submit" buttons are disabled.
@ -36,6 +42,25 @@ export default class AutoUploadsControllers {
.querySelectorAll('button[type=submit]') .querySelectorAll('button[type=submit]')
.forEach(submitButton => Rails.disableElement(submitButton)); .forEach(submitButton => Rails.disableElement(submitButton));
} }
//
// DEBUG: hook into FileReader onload event
//
if (FileReader.prototype.addEventListener === originalImpl) {
FileReader.prototype.addEventListener = function() {
// When DirectUploads attempts to add an event listener for "error",
// also insert a custom event listener of our that will report errors to Sentry.
if (arguments[0] == 'error') {
let handler = event => {
let message = `FileReader ${event.target.error.name}: ${event.target.error.message}`;
fire(document, 'sentry:capture-exception', new Error(message));
};
originalImpl.apply(this, ['error', handler]);
}
// Add the originally requested event listener
return originalImpl.apply(this, arguments);
};
}
} }
_decrementInFlightUploads(form) { _decrementInFlightUploads(form) {
@ -48,5 +73,12 @@ export default class AutoUploadsControllers {
.querySelectorAll('button[type=submit]') .querySelectorAll('button[type=submit]')
.forEach(submitButton => Rails.enableElement(submitButton)); .forEach(submitButton => Rails.enableElement(submitButton));
} }
//
// DEBUG: remove the FileReader hook we set before.
//
if (this.inFlightUploadsCount == 0) {
FileReader.prototype.addEventListener = originalImpl;
}
} }
} }