fix(analytics) make handler loading more resilient

- Don't initialize handler's is their API key is not set
- Don't swallow exceptions when creating handlers
- Don't remove all handlers if an external one fails
- Dispose the analytics subsystem if no handlers are registered
This commit is contained in:
Saúl Ibarra Corretgé 2020-09-24 11:55:03 +02:00 committed by Saúl Ibarra Corretgé
parent 919be21912
commit b153bf2fb8
1 changed files with 38 additions and 31 deletions

View File

@ -57,12 +57,15 @@ export function resetAnalytics() {
* @param {Store} store - The redux store in which the specified {@code action} is being dispatched. * @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
* @returns {Promise} Resolves with the handlers that have been successfully loaded. * @returns {Promise} Resolves with the handlers that have been successfully loaded.
*/ */
export function createHandlers({ getState }: { getState: Function }) { export async function createHandlers({ getState }: { getState: Function }) {
getJitsiMeetGlobalNS().analyticsHandlers = []; getJitsiMeetGlobalNS().analyticsHandlers = [];
window.analyticsHandlers = []; // Legacy support. window.analyticsHandlers = []; // Legacy support.
if (!isAnalyticsEnabled(getState)) { if (!isAnalyticsEnabled(getState)) {
return Promise.resolve([]); // Avoid all analytics processing if there are no handlers, since no event would be sent.
analytics.dispose();
return [];
} }
const state = getState(); const state = getState();
@ -100,43 +103,47 @@ export function createHandlers({ getState }: { getState: Function }) {
}; };
const handlers = []; const handlers = [];
if (amplitudeAPPKey) {
try { try {
const amplitude = new AmplitudeHandler(handlerConstructorOptions); const amplitude = new AmplitudeHandler(handlerConstructorOptions);
analytics.amplitudeIdentityProps = amplitude.getIdentityProps(); analytics.amplitudeIdentityProps = amplitude.getIdentityProps();
handlers.push(amplitude); handlers.push(amplitude);
// eslint-disable-next-line no-empty } catch (e) {
} catch (e) {} logger.error('Failed to initialize Amplitude handler', e);
}
}
if (matomoEndpoint && matomoSiteID) {
try { try {
const matomo = new MatomoHandler(handlerConstructorOptions); const matomo = new MatomoHandler(handlerConstructorOptions);
handlers.push(matomo); handlers.push(matomo);
// eslint-disable-next-line no-empty } catch (e) {
} catch (e) {} logger.error('Failed to initialize Matomo handler', e);
return (
_loadHandlers(scriptURLs, handlerConstructorOptions)
.then(externalHandlers => {
handlers.push(...externalHandlers);
if (handlers.length === 0) {
// Throwing an error in order to dispose the analytics in the catch clause due to the lack of any
// analytics handlers.
throw new Error('No analytics handlers created!');
} }
}
if (Array.isArray(scriptURLs) && scriptURLs.length > 0) {
let externalHandlers;
try {
externalHandlers = await _loadHandlers(scriptURLs, handlerConstructorOptions);
handlers.push(...externalHandlers);
} catch (e) {
logger.error('Failed to initialize external analytics handlers', e);
}
}
// Avoid all analytics processing if there are no handlers, since no event would be sent.
if (handlers.length === 0) {
analytics.dispose();
}
logger.info(`Initialized ${handlers.length} analytics handlers`);
return handlers; return handlers;
})
.catch(e => {
analytics.dispose();
if (handlers.length !== 0) {
logger.error(e);
}
return [];
}));
} }
/** /**