@splitsoftware/splitio-commons
Version:
Split JavaScript SDK common components
70 lines (61 loc) • 2.94 kB
text/typescript
import { objectAssign } from '../utils/lang/objectAssign';
import { thenable } from '../utils/promise/thenable';
import { IEventsCacheBase, ITelemetryCacheAsync, ITelemetryCacheSync } from '../storages/types';
import { IEventsHandler, IEventTracker } from './types';
import { ISettings } from '../types';
import SplitIO from '../../types/splitio';
import { EVENTS_TRACKER_SUCCESS, ERROR_EVENTS_TRACKER } from '../logger/constants';
import { CONSENT_DECLINED, DROPPED, QUEUED } from '../utils/constants';
import { isConsumerMode } from '../utils/settingsValidation/mode';
/**
* Event tracker stores events in cache and pass them to the integrations manager if provided.
*
* @param eventsCache - cache to save events
* @param integrationsManager - optional event handler used for integrations
*/
export function eventTrackerFactory(
settings: ISettings,
eventsCache: IEventsCacheBase,
integrationsManager?: IEventsHandler,
telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync
): IEventTracker {
const { log, mode } = settings;
const isAsync = isConsumerMode(mode);
function queueEventsCallback(eventData: SplitIO.EventData, tracked: boolean) {
const { eventTypeId, trafficTypeName, key, value, timestamp, properties } = eventData;
// Logging every prop would be too much.
const msg = `event of type "${eventTypeId}" for traffic type "${trafficTypeName}". Key: ${key}. Value: ${value}. Timestamp: ${timestamp}. ${properties ? 'With properties.' : 'With no properties.'}`;
if (tracked) {
log.info(EVENTS_TRACKER_SUCCESS, [msg]);
if (integrationsManager) {
// Wrap in a timeout because we don't want it to be blocking.
setTimeout(() => {
// copy of event, to avoid unexpected behavior if modified by integrations
const eventDataCopy = objectAssign({}, eventData);
if (properties) eventDataCopy.properties = objectAssign({}, properties);
// integrationsManager does not throw errors (they are internally handled by each integration module)
integrationsManager.handleEvent(eventDataCopy);
});
}
} else {
log.error(ERROR_EVENTS_TRACKER, [msg]);
}
return tracked;
}
return {
track(eventData: SplitIO.EventData, size?: number) {
if (settings.userConsent === CONSENT_DECLINED) {
return isAsync ? Promise.resolve(false) : false;
}
const tracked = eventsCache.track(eventData, size);
if (thenable(tracked)) {
return tracked.then(queueEventsCallback.bind(null, eventData));
} else {
// Record when eventsCache is sync only (standalone mode)
// @TODO we are not dropping events on full queue yet, so `tracked` is always true ATM
if (telemetryCache) (telemetryCache as ITelemetryCacheSync).recordEventStats(tracked ? QUEUED : DROPPED, 1);
return queueEventsCallback(eventData, tracked);
}
}
};
}