@splitsoftware/splitio-commons 1.6.2-rc.0 → 1.6.2-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +4 -0
- package/cjs/consent/sdkUserConsent.js +2 -2
- package/cjs/evaluator/index.js +15 -16
- package/cjs/integrations/ga/GaToSplit.js +8 -5
- package/cjs/listeners/browser.js +2 -1
- package/cjs/logger/constants.js +2 -1
- package/cjs/sdkClient/client.js +19 -7
- package/cjs/sdkClient/sdkClient.js +3 -1
- package/cjs/sdkFactory/index.js +24 -7
- package/cjs/sdkManager/index.js +3 -11
- package/cjs/services/splitApi.js +24 -4
- package/cjs/storages/AbstractSplitsCacheAsync.js +8 -10
- package/cjs/storages/AbstractSplitsCacheSync.js +8 -10
- package/cjs/storages/KeyBuilderSS.js +54 -9
- package/cjs/storages/dataLoader.js +1 -1
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +5 -7
- package/cjs/storages/inLocalStorage/index.js +5 -1
- package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
- package/cjs/storages/inMemory/InMemoryStorage.js +6 -2
- package/cjs/storages/inMemory/InMemoryStorageCS.js +6 -2
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +7 -10
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -5
- package/cjs/storages/inMemory/UniqueKeysCacheInMemory.js +73 -0
- package/cjs/storages/inMemory/UniqueKeysCacheInMemoryCS.js +78 -0
- package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +50 -0
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +15 -9
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +100 -0
- package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +59 -0
- package/cjs/storages/inRedis/constants.js +4 -1
- package/cjs/storages/inRedis/index.js +17 -2
- package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +43 -0
- package/cjs/storages/pluggable/SplitsCachePluggable.js +14 -9
- package/cjs/storages/pluggable/TelemetryCachePluggable.js +126 -0
- package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +50 -0
- package/cjs/storages/pluggable/index.js +42 -17
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/cjs/sync/submitters/submitterManager.js +3 -0
- package/cjs/sync/submitters/telemetrySubmitter.js +8 -4
- package/cjs/sync/submitters/uniqueKeysSubmitter.js +27 -0
- package/cjs/trackers/impressionsTracker.js +22 -41
- package/cjs/trackers/strategy/strategyDebug.js +25 -0
- package/cjs/trackers/strategy/strategyNone.js +29 -0
- package/cjs/trackers/strategy/strategyOptimized.js +35 -0
- package/cjs/trackers/telemetryTracker.js +6 -0
- package/cjs/trackers/uniqueKeysTracker.js +38 -0
- package/cjs/utils/constants/index.js +4 -2
- package/cjs/utils/lang/maps.js +15 -7
- package/cjs/utils/redis/RedisMock.js +31 -0
- package/cjs/utils/settingsValidation/impressionsMode.js +2 -2
- package/esm/consent/sdkUserConsent.js +2 -2
- package/esm/evaluator/index.js +15 -16
- package/esm/integrations/ga/GaToSplit.js +8 -5
- package/esm/listeners/browser.js +3 -2
- package/esm/logger/constants.js +1 -0
- package/esm/sdkClient/client.js +19 -7
- package/esm/sdkClient/sdkClient.js +3 -1
- package/esm/sdkFactory/index.js +24 -7
- package/esm/sdkManager/index.js +3 -11
- package/esm/services/splitApi.js +24 -4
- package/esm/storages/AbstractSplitsCacheAsync.js +8 -10
- package/esm/storages/AbstractSplitsCacheSync.js +8 -10
- package/esm/storages/KeyBuilderSS.js +50 -8
- package/esm/storages/dataLoader.js +1 -1
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -7
- package/esm/storages/inLocalStorage/index.js +6 -2
- package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
- package/esm/storages/inMemory/InMemoryStorage.js +8 -4
- package/esm/storages/inMemory/InMemoryStorageCS.js +7 -3
- package/esm/storages/inMemory/SplitsCacheInMemory.js +7 -10
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +9 -5
- package/esm/storages/inMemory/UniqueKeysCacheInMemory.js +70 -0
- package/esm/storages/inMemory/UniqueKeysCacheInMemoryCS.js +75 -0
- package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +47 -0
- package/esm/storages/inRedis/SplitsCacheInRedis.js +15 -9
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +100 -0
- package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +56 -0
- package/esm/storages/inRedis/constants.js +3 -0
- package/esm/storages/inRedis/index.js +18 -3
- package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +40 -0
- package/esm/storages/pluggable/SplitsCachePluggable.js +14 -9
- package/esm/storages/pluggable/TelemetryCachePluggable.js +126 -0
- package/esm/storages/pluggable/UniqueKeysCachePluggable.js +47 -0
- package/esm/storages/pluggable/index.js +43 -18
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
- package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/esm/sync/submitters/submitterManager.js +3 -0
- package/esm/sync/submitters/telemetrySubmitter.js +9 -5
- package/esm/sync/submitters/uniqueKeysSubmitter.js +23 -0
- package/esm/trackers/impressionsTracker.js +22 -41
- package/esm/trackers/strategy/strategyDebug.js +21 -0
- package/esm/trackers/strategy/strategyNone.js +25 -0
- package/esm/trackers/strategy/strategyOptimized.js +31 -0
- package/esm/trackers/telemetryTracker.js +6 -0
- package/esm/trackers/uniqueKeysTracker.js +34 -0
- package/esm/utils/constants/index.js +2 -0
- package/esm/utils/lang/maps.js +15 -7
- package/esm/utils/redis/RedisMock.js +28 -0
- package/esm/utils/settingsValidation/impressionsMode.js +3 -3
- package/package.json +1 -2
- package/src/consent/sdkUserConsent.ts +2 -2
- package/src/evaluator/index.ts +14 -15
- package/src/integrations/ga/GaToSplit.ts +9 -5
- package/src/integrations/types.ts +2 -1
- package/src/listeners/browser.ts +3 -2
- package/src/logger/constants.ts +1 -0
- package/src/sdkClient/client.ts +21 -8
- package/src/sdkClient/sdkClient.ts +3 -1
- package/src/sdkFactory/index.ts +28 -8
- package/src/sdkFactory/types.ts +7 -4
- package/src/sdkManager/index.ts +3 -12
- package/src/services/splitApi.ts +26 -4
- package/src/services/types.ts +8 -2
- package/src/storages/AbstractSplitsCacheAsync.ts +13 -15
- package/src/storages/AbstractSplitsCacheSync.ts +15 -17
- package/src/storages/KeyBuilderSS.ts +61 -9
- package/src/storages/dataLoader.ts +1 -1
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +8 -11
- package/src/storages/inLocalStorage/index.ts +5 -2
- package/src/storages/inMemory/ImpressionCountsCacheInMemory.ts +16 -1
- package/src/storages/inMemory/InMemoryStorage.ts +7 -4
- package/src/storages/inMemory/InMemoryStorageCS.ts +6 -3
- package/src/storages/inMemory/SplitsCacheInMemory.ts +10 -14
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +10 -6
- package/src/storages/inMemory/UniqueKeysCacheInMemory.ts +82 -0
- package/src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts +88 -0
- package/src/storages/inRedis/EventsCacheInRedis.ts +1 -1
- package/src/storages/inRedis/ImpressionCountsCacheInRedis.ts +53 -0
- package/src/storages/inRedis/SplitsCacheInRedis.ts +21 -17
- package/src/storages/inRedis/TelemetryCacheInRedis.ts +122 -2
- package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +65 -0
- package/src/storages/inRedis/constants.ts +3 -0
- package/src/storages/inRedis/index.ts +15 -5
- package/src/storages/pluggable/ImpressionCountsCachePluggable.ts +47 -0
- package/src/storages/pluggable/SplitsCachePluggable.ts +20 -17
- package/src/storages/pluggable/TelemetryCachePluggable.ts +147 -2
- package/src/storages/pluggable/UniqueKeysCachePluggable.ts +56 -0
- package/src/storages/pluggable/index.ts +44 -19
- package/src/storages/types.ts +50 -29
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +5 -6
- package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -2
- package/src/sync/submitters/submitterManager.ts +2 -0
- package/src/sync/submitters/telemetrySubmitter.ts +15 -8
- package/src/sync/submitters/types.ts +38 -7
- package/src/sync/submitters/uniqueKeysSubmitter.ts +36 -0
- package/src/trackers/impressionsTracker.ts +27 -48
- package/src/trackers/strategy/strategyDebug.ts +28 -0
- package/src/trackers/strategy/strategyNone.ts +34 -0
- package/src/trackers/strategy/strategyOptimized.ts +42 -0
- package/src/trackers/telemetryTracker.ts +7 -2
- package/src/trackers/types.ts +32 -0
- package/src/trackers/uniqueKeysTracker.ts +48 -0
- package/src/types.ts +1 -1
- package/src/utils/constants/index.ts +2 -0
- package/src/utils/lang/maps.ts +20 -8
- package/src/utils/redis/RedisMock.ts +33 -0
- package/src/utils/settingsValidation/impressionsMode.ts +3 -3
- package/src/utils/settingsValidation/index.ts +1 -0
- package/types/integrations/types.d.ts +2 -1
- package/types/logger/browser/{debugLogger.d.ts → DebugLogger.d.ts} +0 -0
- package/types/logger/browser/{errorLogger.d.ts → ErrorLogger.d.ts} +0 -0
- package/types/logger/browser/{infoLogger.d.ts → InfoLogger.d.ts} +0 -0
- package/types/logger/browser/{warnLogger.d.ts → WarnLogger.d.ts} +0 -0
- package/types/logger/constants.d.ts +1 -0
- package/types/sdkFactory/types.d.ts +4 -2
- package/types/services/types.d.ts +6 -2
- package/types/storages/AbstractSplitsCacheAsync.d.ts +7 -6
- package/types/storages/AbstractSplitsCacheSync.d.ts +6 -6
- package/types/storages/KeyBuilderSS.d.ts +9 -2
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +3 -4
- package/types/storages/inMemory/ImpressionCountsCacheInMemory.d.ts +5 -1
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +3 -2
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -3
- package/types/storages/inMemory/uniqueKeysCacheInMemory.d.ts +35 -0
- package/types/storages/inMemory/uniqueKeysCacheInMemoryCS.d.ts +37 -0
- package/types/storages/inRedis/EventsCacheInRedis.d.ts +1 -1
- package/types/storages/inRedis/ImpressionCountsCacheInRedis.d.ts +14 -0
- package/types/storages/inRedis/SplitsCacheInRedis.d.ts +6 -5
- package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +16 -1
- package/types/storages/inRedis/constants.d.ts +3 -0
- package/types/storages/inRedis/uniqueKeysCacheInRedis.d.ts +15 -0
- package/types/storages/pluggable/ImpressionCountsCachePluggable.d.ts +14 -0
- package/types/storages/pluggable/SplitsCachePluggable.d.ts +6 -5
- package/types/storages/pluggable/TelemetryCachePluggable.d.ts +17 -1
- package/types/storages/pluggable/UniqueKeysCachePluggable.d.ts +14 -0
- package/types/storages/types.d.ts +38 -25
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
- package/types/sync/submitters/telemetrySubmitter.d.ts +1 -1
- package/types/sync/submitters/types.d.ts +30 -7
- package/types/sync/submitters/uniqueKeysSubmitter.d.ts +0 -8
- package/types/trackers/impressionsTracker.d.ts +4 -6
- package/types/trackers/types.d.ts +27 -0
- package/types/trackers/uniqueKeysTracker.d.ts +3 -3
- package/types/types.d.ts +1 -1
- package/types/utils/constants/index.d.ts +2 -0
- package/types/utils/lang/maps.d.ts +6 -2
- package/types/utils/redis/RedisMock.d.ts +4 -0
- package/src/splitio.d.ts +0 -1602
- package/types/integrations/ga/GaToSplitPlugin.d.ts +0 -3
- package/types/integrations/ga/SplitToGaPlugin.d.ts +0 -4
- package/types/integrations/ga/autoRequire.d.ts +0 -4
- package/types/logger/codes.d.ts +0 -2
- package/types/logger/codesConstants.d.ts +0 -117
- package/types/logger/codesConstantsBrowser.d.ts +0 -2
- package/types/logger/codesConstantsNode.d.ts +0 -14
- package/types/logger/codesDebug.d.ts +0 -1
- package/types/logger/codesDebugBrowser.d.ts +0 -1
- package/types/logger/codesDebugNode.d.ts +0 -1
- package/types/logger/codesError.d.ts +0 -1
- package/types/logger/codesErrorNode.d.ts +0 -1
- package/types/logger/codesInfo.d.ts +0 -1
- package/types/logger/codesWarn.d.ts +0 -1
- package/types/logger/codesWarnNode.d.ts +0 -1
- package/types/logger/debugLogger.d.ts +0 -2
- package/types/logger/errorLogger.d.ts +0 -2
- package/types/logger/infoLogger.d.ts +0 -2
- package/types/logger/messages/debugBrowser.d.ts +0 -1
- package/types/logger/messages/debugNode.d.ts +0 -1
- package/types/logger/messages/errorNode.d.ts +0 -1
- package/types/logger/messages/warnNode.d.ts +0 -1
- package/types/logger/noopLogger.d.ts +0 -2
- package/types/logger/warnLogger.d.ts +0 -2
- package/types/sdkClient/types.d.ts +0 -18
- package/types/sdkFactory/userConsentProps.d.ts +0 -6
- package/types/sdkManager/sdkManagerMethod.d.ts +0 -6
- package/types/storages/getRegisteredSegments.d.ts +0 -10
- package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
- package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
- package/types/storages/inMemory/index.d.ts +0 -10
- package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
- package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
- package/types/storages/parseSegments.d.ts +0 -6
- package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
- package/types/sync/polling/syncTasks/splitsSyncTask.copy.d.ts +0 -35
- package/types/sync/polling/syncTasks/splitsSyncTask.morelikeoriginal.d.ts +0 -35
- package/types/sync/streaming/AuthClient/indexV1.d.ts +0 -12
- package/types/sync/streaming/AuthClient/indexV2.d.ts +0 -8
- package/types/sync/streaming/pushManagerCS.d.ts +0 -1
- package/types/sync/streaming/pushManagerNoUsers.d.ts +0 -13
- package/types/sync/streaming/pushManagerSS.d.ts +0 -1
- package/types/sync/submitters/eventsSyncTask.d.ts +0 -8
- package/types/sync/submitters/impressionCountsSyncTask.d.ts +0 -13
- package/types/sync/submitters/impressionsSyncTask.d.ts +0 -14
- package/types/sync/submitters/metricsSyncTask.d.ts +0 -12
- package/types/sync/submitters/submitterSyncTask.d.ts +0 -10
- package/types/sync/submitters/telemetrySyncTask.d.ts +0 -0
- package/types/sync/syncManagerFromFile.d.ts +0 -2
- package/types/sync/syncManagerFromObject.d.ts +0 -2
- package/types/sync/syncManagerOffline.d.ts +0 -9
- package/types/sync/syncTaskComposite.d.ts +0 -5
- package/types/trackers/telemetryRecorder.d.ts +0 -0
- package/types/utils/EventEmitter.d.ts +0 -4
- package/types/utils/consent.d.ts +0 -2
- package/types/utils/lang/errors.d.ts +0 -10
- package/types/utils/murmur3/commons.d.ts +0 -12
- package/types/utils/settingsValidation/buildMetadata.d.ts +0 -3
- package/types/utils/settingsValidation/localhost/index.d.ts +0 -9
- package/types/utils/settingsValidation/logger.d.ts +0 -11
- package/types/utils/settingsValidation/runtime/browser.d.ts +0 -2
- package/types/utils/settingsValidation/runtime/node.d.ts +0 -2
- package/types/utils/settingsValidation/userConsent.d.ts +0 -5
- package/types/utils/timeTracker/index.d.ts +0 -1
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import { parseExceptionField, parseLatencyField, parseMetadata } from '../KeyBuilderSS';
|
|
1
2
|
import { findLatencyIndex } from '../findLatencyIndex';
|
|
3
|
+
import { getTelemetryConfigStats } from '../../sync/submitters/telemetrySubmitter';
|
|
4
|
+
import { CONSUMER_MODE, STORAGE_PLUGGABLE } from '../../utils/constants';
|
|
5
|
+
import { isString, isNaNNumber } from '../../utils/lang';
|
|
6
|
+
import { _Map } from '../../utils/lang/maps';
|
|
7
|
+
import { MAX_LATENCY_BUCKET_COUNT, newBuckets } from '../inMemory/TelemetryCacheInMemory';
|
|
2
8
|
var TelemetryCachePluggable = /** @class */ (function () {
|
|
3
9
|
/**
|
|
4
10
|
* Create a Telemetry cache that uses a storage wrapper.
|
|
@@ -19,6 +25,126 @@ var TelemetryCachePluggable = /** @class */ (function () {
|
|
|
19
25
|
return this.wrapper.incr(this.keys.buildExceptionKey(method))
|
|
20
26
|
.catch(function () { });
|
|
21
27
|
};
|
|
28
|
+
TelemetryCachePluggable.prototype.recordConfig = function () {
|
|
29
|
+
var value = JSON.stringify(getTelemetryConfigStats(CONSUMER_MODE, STORAGE_PLUGGABLE));
|
|
30
|
+
return this.wrapper.set(this.keys.buildInitKey(), value).catch(function () { });
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Pop telemetry latencies.
|
|
34
|
+
* The returned promise rejects if wrapper operations fail.
|
|
35
|
+
*/
|
|
36
|
+
TelemetryCachePluggable.prototype.popLatencies = function () {
|
|
37
|
+
var _this = this;
|
|
38
|
+
return this.wrapper.getKeysByPrefix(this.keys.latencyPrefix).then(function (latencyKeys) {
|
|
39
|
+
return latencyKeys.length ?
|
|
40
|
+
_this.wrapper.getMany(latencyKeys).then(function (latencies) {
|
|
41
|
+
var result = new _Map();
|
|
42
|
+
for (var i = 0; i < latencyKeys.length; i++) {
|
|
43
|
+
var field = latencyKeys[i].split('::')[1];
|
|
44
|
+
var parsedField = parseLatencyField(field);
|
|
45
|
+
if (isString(parsedField)) {
|
|
46
|
+
_this.log.error("Ignoring invalid latency field: " + field + ": " + parsedField);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
var count = parseInt(latencies[i]);
|
|
51
|
+
if (isNaNNumber(count)) {
|
|
52
|
+
_this.log.error("Ignoring latency with invalid count: " + latencies[i]);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
var metadata = parsedField[0], method = parsedField[1], bucket = parsedField[2];
|
|
56
|
+
if (bucket >= MAX_LATENCY_BUCKET_COUNT) {
|
|
57
|
+
_this.log.error("Ignoring latency with invalid bucket: " + bucket);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (!result.has(metadata))
|
|
61
|
+
result.set(metadata, {
|
|
62
|
+
t: newBuckets(),
|
|
63
|
+
ts: newBuckets(),
|
|
64
|
+
tc: newBuckets(),
|
|
65
|
+
tcs: newBuckets(),
|
|
66
|
+
tr: newBuckets(),
|
|
67
|
+
});
|
|
68
|
+
result.get(metadata)[method][bucket] = count;
|
|
69
|
+
}
|
|
70
|
+
return Promise.all(latencyKeys.map(function (latencyKey) { return _this.wrapper.del(latencyKey); })).then(function () { return result; });
|
|
71
|
+
}) :
|
|
72
|
+
// If latencyKeys is empty, return an empty map.
|
|
73
|
+
new _Map();
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Pop telemetry exceptions.
|
|
78
|
+
* The returned promise rejects if wrapper operations fail.
|
|
79
|
+
*/
|
|
80
|
+
TelemetryCachePluggable.prototype.popExceptions = function () {
|
|
81
|
+
var _this = this;
|
|
82
|
+
return this.wrapper.getKeysByPrefix(this.keys.exceptionPrefix).then(function (exceptionKeys) {
|
|
83
|
+
return exceptionKeys.length ?
|
|
84
|
+
_this.wrapper.getMany(exceptionKeys).then(function (exceptions) {
|
|
85
|
+
var result = new _Map();
|
|
86
|
+
for (var i = 0; i < exceptionKeys.length; i++) {
|
|
87
|
+
var field = exceptionKeys[i].split('::')[1];
|
|
88
|
+
var parsedField = parseExceptionField(field);
|
|
89
|
+
if (isString(parsedField)) {
|
|
90
|
+
_this.log.error("Ignoring invalid exception field: " + field + ": " + parsedField);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// @ts-ignore
|
|
94
|
+
var count = parseInt(exceptions[i]);
|
|
95
|
+
if (isNaNNumber(count)) {
|
|
96
|
+
_this.log.error("Ignoring exception with invalid count: " + exceptions[i]);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
var metadata = parsedField[0], method = parsedField[1];
|
|
100
|
+
if (!result.has(metadata))
|
|
101
|
+
result.set(metadata, {
|
|
102
|
+
t: 0,
|
|
103
|
+
ts: 0,
|
|
104
|
+
tc: 0,
|
|
105
|
+
tcs: 0,
|
|
106
|
+
tr: 0,
|
|
107
|
+
});
|
|
108
|
+
result.get(metadata)[method] = count;
|
|
109
|
+
}
|
|
110
|
+
return Promise.all(exceptionKeys.map(function (exceptionKey) { return _this.wrapper.del(exceptionKey); })).then(function () { return result; });
|
|
111
|
+
}) :
|
|
112
|
+
// If exceptionKeys is empty, return an empty map.
|
|
113
|
+
new _Map();
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Pop telemetry configs.
|
|
118
|
+
* The returned promise rejects if wrapper operations fail.
|
|
119
|
+
*/
|
|
120
|
+
TelemetryCachePluggable.prototype.popConfigs = function () {
|
|
121
|
+
var _this = this;
|
|
122
|
+
return this.wrapper.getKeysByPrefix(this.keys.initPrefix).then(function (configKeys) {
|
|
123
|
+
return configKeys.length ?
|
|
124
|
+
_this.wrapper.getMany(configKeys).then(function (configs) {
|
|
125
|
+
var result = new _Map();
|
|
126
|
+
for (var i = 0; i < configKeys.length; i++) {
|
|
127
|
+
var field = configKeys[i].split('::')[1];
|
|
128
|
+
var parsedField = parseMetadata(field);
|
|
129
|
+
if (isString(parsedField)) {
|
|
130
|
+
_this.log.error("Ignoring invalid config field: " + field + ": " + parsedField);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
var metadata = parsedField[0];
|
|
134
|
+
try { // @ts-ignore
|
|
135
|
+
var config = JSON.parse(configs[i]);
|
|
136
|
+
result.set(metadata, config);
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
_this.log.error("Ignoring invalid config: " + configs[i]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return Promise.all(configKeys.map(function (configKey) { return _this.wrapper.del(configKey); })).then(function () { return result; });
|
|
143
|
+
}) :
|
|
144
|
+
// If configKeys is empty, return an empty map.
|
|
145
|
+
new _Map();
|
|
146
|
+
});
|
|
147
|
+
};
|
|
22
148
|
return TelemetryCachePluggable;
|
|
23
149
|
}());
|
|
24
150
|
export { TelemetryCachePluggable };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { __extends } from "tslib";
|
|
2
|
+
import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
|
|
3
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
4
|
+
import { DEFAULT_CACHE_SIZE, REFRESH_RATE } from '../inRedis/constants';
|
|
5
|
+
import { LOG_PREFIX } from './constants';
|
|
6
|
+
var UniqueKeysCachePluggable = /** @class */ (function (_super) {
|
|
7
|
+
__extends(UniqueKeysCachePluggable, _super);
|
|
8
|
+
function UniqueKeysCachePluggable(log, key, wrapper, uniqueKeysQueueSize, refreshRate) {
|
|
9
|
+
if (uniqueKeysQueueSize === void 0) { uniqueKeysQueueSize = DEFAULT_CACHE_SIZE; }
|
|
10
|
+
if (refreshRate === void 0) { refreshRate = REFRESH_RATE; }
|
|
11
|
+
var _this = _super.call(this, uniqueKeysQueueSize) || this;
|
|
12
|
+
_this.log = log;
|
|
13
|
+
_this.key = key;
|
|
14
|
+
_this.wrapper = wrapper;
|
|
15
|
+
_this.refreshRate = refreshRate;
|
|
16
|
+
_this.onFullQueue = function () { _this.storeUniqueKeys(); };
|
|
17
|
+
return _this;
|
|
18
|
+
}
|
|
19
|
+
UniqueKeysCachePluggable.prototype.storeUniqueKeys = function () {
|
|
20
|
+
var _this = this;
|
|
21
|
+
var featureNames = Object.keys(this.uniqueKeysTracker);
|
|
22
|
+
if (!featureNames.length)
|
|
23
|
+
return Promise.resolve(false);
|
|
24
|
+
var pipeline = featureNames.reduce(function (pipeline, featureName) {
|
|
25
|
+
var featureKeys = setToArray(_this.uniqueKeysTracker[featureName]);
|
|
26
|
+
var uniqueKeysPayload = {
|
|
27
|
+
f: featureName,
|
|
28
|
+
ks: featureKeys
|
|
29
|
+
};
|
|
30
|
+
return pipeline.then(function () { return _this.wrapper.pushItems(_this.key, [JSON.stringify(uniqueKeysPayload)]); });
|
|
31
|
+
}, Promise.resolve());
|
|
32
|
+
this.clear();
|
|
33
|
+
return pipeline.catch(function (err) {
|
|
34
|
+
_this.log.error(LOG_PREFIX + "Error in uniqueKeys pipeline: " + err + ".");
|
|
35
|
+
return false;
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
UniqueKeysCachePluggable.prototype.start = function () {
|
|
39
|
+
this.intervalId = setInterval(this.storeUniqueKeys.bind(this), this.refreshRate);
|
|
40
|
+
};
|
|
41
|
+
UniqueKeysCachePluggable.prototype.stop = function () {
|
|
42
|
+
clearInterval(this.intervalId);
|
|
43
|
+
return this.storeUniqueKeys();
|
|
44
|
+
};
|
|
45
|
+
return UniqueKeysCachePluggable;
|
|
46
|
+
}(UniqueKeysCacheInMemory));
|
|
47
|
+
export { UniqueKeysCachePluggable };
|
|
@@ -7,10 +7,16 @@ import { EventsCachePluggable } from './EventsCachePluggable';
|
|
|
7
7
|
import { wrapperAdapter, METHODS_TO_PROMISE_WRAP } from './wrapperAdapter';
|
|
8
8
|
import { isObject } from '../../utils/lang';
|
|
9
9
|
import { validatePrefix } from '../KeyBuilder';
|
|
10
|
-
import { CONSUMER_PARTIAL_MODE, STORAGE_PLUGGABLE } from '../../utils/constants';
|
|
10
|
+
import { CONSUMER_PARTIAL_MODE, DEBUG, NONE, STORAGE_PLUGGABLE } from '../../utils/constants';
|
|
11
11
|
import { ImpressionsCacheInMemory } from '../inMemory/ImpressionsCacheInMemory';
|
|
12
12
|
import { EventsCacheInMemory } from '../inMemory/EventsCacheInMemory';
|
|
13
13
|
import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCacheInMemory';
|
|
14
|
+
import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
|
|
15
|
+
import { TelemetryCachePluggable } from './TelemetryCachePluggable';
|
|
16
|
+
import { ImpressionCountsCachePluggable } from './ImpressionCountsCachePluggable';
|
|
17
|
+
import { UniqueKeysCachePluggable } from './UniqueKeysCachePluggable';
|
|
18
|
+
import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
|
|
19
|
+
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
14
20
|
var NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
|
|
15
21
|
var NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
|
|
16
22
|
/**
|
|
@@ -27,15 +33,6 @@ function validatePluggableStorageOptions(options) {
|
|
|
27
33
|
if (missingMethods.length)
|
|
28
34
|
throw new Error(NO_VALID_WRAPPER_INTERFACE + " The following methods are missing or invalid: " + missingMethods);
|
|
29
35
|
}
|
|
30
|
-
// subscription to wrapper connect event in order to emit SDK_READY event
|
|
31
|
-
function wrapperConnect(wrapper, onReadyCb) {
|
|
32
|
-
wrapper.connect().then(function () {
|
|
33
|
-
onReadyCb();
|
|
34
|
-
// At the moment, we don't synchronize config with pluggable storage
|
|
35
|
-
}).catch(function (e) {
|
|
36
|
-
onReadyCb(e || new Error('Error connecting wrapper'));
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
36
|
// Async return type in `client.track` method on consumer partial mode
|
|
40
37
|
// No need to promisify impressions cache
|
|
41
38
|
function promisifyEventsTrack(events) {
|
|
@@ -51,28 +48,56 @@ function promisifyEventsTrack(events) {
|
|
|
51
48
|
export function PluggableStorage(options) {
|
|
52
49
|
validatePluggableStorageOptions(options);
|
|
53
50
|
var prefix = validatePrefix(options.prefix);
|
|
54
|
-
function PluggableStorageFactory(
|
|
55
|
-
var log =
|
|
51
|
+
function PluggableStorageFactory(params) {
|
|
52
|
+
var log = params.log, metadata = params.metadata, onReadyCb = params.onReadyCb, mode = params.mode, eventsQueueSize = params.eventsQueueSize, impressionsQueueSize = params.impressionsQueueSize, impressionsMode = params.impressionsMode, matchingKey = params.matchingKey;
|
|
56
53
|
var keys = new KeyBuilderSS(prefix, metadata);
|
|
57
54
|
var wrapper = wrapperAdapter(log, options.wrapper);
|
|
58
55
|
var isPartialConsumer = mode === CONSUMER_PARTIAL_MODE;
|
|
56
|
+
var telemetry = shouldRecordTelemetry(params) ?
|
|
57
|
+
isPartialConsumer ? new TelemetryCacheInMemory() : new TelemetryCachePluggable(log, keys, wrapper) :
|
|
58
|
+
undefined;
|
|
59
|
+
var impressionCountsCache = impressionsMode !== DEBUG ?
|
|
60
|
+
isPartialConsumer ? new ImpressionCountsCacheInMemory() : new ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper) :
|
|
61
|
+
undefined;
|
|
62
|
+
var uniqueKeysCache = impressionsMode === NONE ?
|
|
63
|
+
isPartialConsumer ?
|
|
64
|
+
matchingKey === undefined ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() :
|
|
65
|
+
new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper) :
|
|
66
|
+
undefined;
|
|
59
67
|
// Connects to wrapper and emits SDK_READY event on main client
|
|
60
|
-
|
|
68
|
+
var connectPromise = wrapper.connect().then(function () {
|
|
69
|
+
onReadyCb();
|
|
70
|
+
// Start periodic flush of async storages
|
|
71
|
+
if (impressionCountsCache && impressionCountsCache.start)
|
|
72
|
+
impressionCountsCache.start();
|
|
73
|
+
if (uniqueKeysCache && uniqueKeysCache.start)
|
|
74
|
+
uniqueKeysCache.start();
|
|
75
|
+
// If mode is not defined, it means that the synchronizer is running and so we don't have to record telemetry
|
|
76
|
+
if (telemetry && telemetry.recordConfig && mode)
|
|
77
|
+
telemetry.recordConfig();
|
|
78
|
+
}).catch(function (e) {
|
|
79
|
+
e = e || new Error('Error connecting wrapper');
|
|
80
|
+
onReadyCb(e);
|
|
81
|
+
return e;
|
|
82
|
+
});
|
|
61
83
|
return {
|
|
62
84
|
splits: new SplitsCachePluggable(log, keys, wrapper),
|
|
63
85
|
segments: new SegmentsCachePluggable(log, keys, wrapper),
|
|
64
86
|
impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
|
|
65
|
-
impressionCounts:
|
|
87
|
+
impressionCounts: impressionCountsCache,
|
|
66
88
|
events: isPartialConsumer ? promisifyEventsTrack(new EventsCacheInMemory(eventsQueueSize)) : new EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata),
|
|
67
|
-
|
|
68
|
-
|
|
89
|
+
telemetry: telemetry,
|
|
90
|
+
uniqueKeys: uniqueKeysCache,
|
|
69
91
|
// Disconnect the underlying storage
|
|
70
92
|
destroy: function () {
|
|
71
|
-
return
|
|
93
|
+
return Promise.all([
|
|
94
|
+
impressionCountsCache && impressionCountsCache.stop && impressionCountsCache.stop(),
|
|
95
|
+
uniqueKeysCache && uniqueKeysCache.stop && uniqueKeysCache.stop(),
|
|
96
|
+
]).then(function () { return wrapper.disconnect(); });
|
|
72
97
|
},
|
|
73
98
|
// emits SDK_READY event on shared clients and returns a reference to the storage
|
|
74
99
|
shared: function (_, onReadyCb) {
|
|
75
|
-
|
|
100
|
+
connectPromise.then(onReadyCb);
|
|
76
101
|
return __assign(__assign({}, this), {
|
|
77
102
|
// no-op destroy, to disconnect the wrapper only when the main client is destroyed
|
|
78
103
|
destroy: function () { } });
|
|
@@ -24,8 +24,7 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
|
|
|
24
24
|
log.debug(SYNC_OFFLINE_DATA, [JSON.stringify(splitsMock)]);
|
|
25
25
|
forOwn(splitsMock, function (val, name) {
|
|
26
26
|
splits.push([
|
|
27
|
-
name,
|
|
28
|
-
JSON.stringify({
|
|
27
|
+
name, {
|
|
29
28
|
name: name,
|
|
30
29
|
status: 'ACTIVE',
|
|
31
30
|
killed: false,
|
|
@@ -34,7 +33,7 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
|
|
|
34
33
|
conditions: val.conditions || [],
|
|
35
34
|
configurations: val.configurations,
|
|
36
35
|
trafficTypeName: val.trafficTypeName
|
|
37
|
-
}
|
|
36
|
+
}
|
|
38
37
|
]);
|
|
39
38
|
});
|
|
40
39
|
return Promise.all([
|
|
@@ -37,7 +37,7 @@ export function computeSplitsMutation(entries) {
|
|
|
37
37
|
var segments = new _Set();
|
|
38
38
|
var computed = entries.reduce(function (accum, split) {
|
|
39
39
|
if (split.status === 'ACTIVE') {
|
|
40
|
-
accum.added.push([split.name,
|
|
40
|
+
accum.added.push([split.name, split]);
|
|
41
41
|
parseSegments(split).forEach(function (segmentName) {
|
|
42
42
|
segments.add(segmentName);
|
|
43
43
|
});
|
|
@@ -2,6 +2,7 @@ import { eventsSubmitterFactory } from './eventsSubmitter';
|
|
|
2
2
|
import { impressionsSubmitterFactory } from './impressionsSubmitter';
|
|
3
3
|
import { impressionCountsSubmitterFactory } from './impressionCountsSubmitter';
|
|
4
4
|
import { telemetrySubmitterFactory } from './telemetrySubmitter';
|
|
5
|
+
import { uniqueKeysSubmitterFactory } from './uniqueKeysSubmitter';
|
|
5
6
|
export function submitterManagerFactory(params) {
|
|
6
7
|
var submitters = [
|
|
7
8
|
impressionsSubmitterFactory(params),
|
|
@@ -11,6 +12,8 @@ export function submitterManagerFactory(params) {
|
|
|
11
12
|
if (impressionCountsSubmitter)
|
|
12
13
|
submitters.push(impressionCountsSubmitter);
|
|
13
14
|
var telemetrySubmitter = telemetrySubmitterFactory(params);
|
|
15
|
+
if (params.uniqueKeysTracker)
|
|
16
|
+
submitters.push(uniqueKeysSubmitterFactory(params));
|
|
14
17
|
return {
|
|
15
18
|
// `onlyTelemetry` true if SDK is created with userConsent not GRANTED
|
|
16
19
|
start: function (onlyTelemetry) {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
var _a, _b, _c;
|
|
2
2
|
import { submitterFactory, firstPushWindowDecorator } from './submitter';
|
|
3
|
-
import { QUEUED, DEDUPED, DROPPED, CONSUMER_MODE, CONSUMER_ENUM, STANDALONE_MODE, CONSUMER_PARTIAL_MODE, STANDALONE_ENUM, CONSUMER_PARTIAL_ENUM, OPTIMIZED, DEBUG, DEBUG_ENUM, OPTIMIZED_ENUM, CONSENT_GRANTED, CONSENT_DECLINED, CONSENT_UNKNOWN } from '../../utils/constants';
|
|
3
|
+
import { QUEUED, DEDUPED, DROPPED, CONSUMER_MODE, CONSUMER_ENUM, STANDALONE_MODE, CONSUMER_PARTIAL_MODE, STANDALONE_ENUM, CONSUMER_PARTIAL_ENUM, OPTIMIZED, DEBUG, NONE, DEBUG_ENUM, OPTIMIZED_ENUM, NONE_ENUM, CONSENT_GRANTED, CONSENT_DECLINED, CONSENT_UNKNOWN } from '../../utils/constants';
|
|
4
4
|
import { SDK_READY, SDK_READY_FROM_CACHE } from '../../readiness/constants';
|
|
5
5
|
import { base } from '../../utils/settingsValidation';
|
|
6
6
|
import { usedKeysMap } from '../../utils/inputValidation/apiKey';
|
|
7
7
|
import { timer } from '../../utils/timeTracker/timer';
|
|
8
8
|
import { objectAssign } from '../../utils/lang/objectAssign';
|
|
9
|
+
import { isStorageSync } from '../../trackers/impressionObserver/utils';
|
|
9
10
|
/**
|
|
10
11
|
* Converts data from telemetry cache into /metrics/usage request payload.
|
|
11
12
|
*/
|
|
@@ -26,9 +27,9 @@ export function telemetryCacheStatsAdapter(telemetry, splits, segments) {
|
|
|
26
27
|
iQ: telemetry.getImpressionStats(QUEUED),
|
|
27
28
|
iDe: telemetry.getImpressionStats(DEDUPED),
|
|
28
29
|
iDr: telemetry.getImpressionStats(DROPPED),
|
|
29
|
-
spC: splits.getSplitNames().length,
|
|
30
|
-
seC: segments.getRegisteredSegments().length,
|
|
31
|
-
skC: segments.getKeysCount(),
|
|
30
|
+
spC: splits && splits.getSplitNames().length,
|
|
31
|
+
seC: segments && segments.getRegisteredSegments().length,
|
|
32
|
+
skC: segments && segments.getKeysCount(),
|
|
32
33
|
sL: telemetry.getSessionLength(),
|
|
33
34
|
eQ: telemetry.getEventStats(QUEUED),
|
|
34
35
|
eD: telemetry.getEventStats(DROPPED),
|
|
@@ -46,6 +47,7 @@ var OPERATION_MODE_MAP = (_a = {},
|
|
|
46
47
|
var IMPRESSIONS_MODE_MAP = (_b = {},
|
|
47
48
|
_b[OPTIMIZED] = OPTIMIZED_ENUM,
|
|
48
49
|
_b[DEBUG] = DEBUG_ENUM,
|
|
50
|
+
_b[NONE] = NONE_ENUM,
|
|
49
51
|
_b);
|
|
50
52
|
var USER_CONSENT_MAP = (_c = {},
|
|
51
53
|
_c[CONSENT_UNKNOWN] = 1,
|
|
@@ -119,7 +121,9 @@ export function telemetrySubmitterFactory(params) {
|
|
|
119
121
|
return; // No submitter created if telemetry cache is not defined
|
|
120
122
|
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
|
|
121
123
|
var startTime = timer(now);
|
|
122
|
-
var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage,
|
|
124
|
+
var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage,
|
|
125
|
+
// @TODO cannot provide splits and segments cache if they are async, because `submitterFactory` expects a sync storage source
|
|
126
|
+
isStorageSync(params.settings) ? telemetryCacheStatsAdapter(telemetry, splits, segments) : telemetryCacheStatsAdapter(telemetry), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
|
|
123
127
|
readiness.gate.once(SDK_READY_FROM_CACHE, function () {
|
|
124
128
|
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
125
129
|
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
|
|
2
|
+
import { submitterFactory } from './submitter';
|
|
3
|
+
var DATA_NAME = 'unique keys';
|
|
4
|
+
var UNIQUE_KEYS_RATE = 900000; // 15 minutes
|
|
5
|
+
/**
|
|
6
|
+
* Submitter that periodically posts impression counts
|
|
7
|
+
*/
|
|
8
|
+
export function uniqueKeysSubmitterFactory(params) {
|
|
9
|
+
var _a = params.settings, log = _a.log, key = _a.core.key, _b = params.splitApi, postUniqueKeysBulkCs = _b.postUniqueKeysBulkCs, postUniqueKeysBulkSs = _b.postUniqueKeysBulkSs, uniqueKeys = params.storage.uniqueKeys;
|
|
10
|
+
var isClientSide = key !== undefined;
|
|
11
|
+
var postUniqueKeysBulk = isClientSide ? postUniqueKeysBulkCs : postUniqueKeysBulkSs;
|
|
12
|
+
var syncTask = submitterFactory(log, postUniqueKeysBulk, uniqueKeys, UNIQUE_KEYS_RATE, DATA_NAME);
|
|
13
|
+
// register unique keys submitter to be executed when uniqueKeys cache is full
|
|
14
|
+
uniqueKeys.setOnFullQueueCb(function () {
|
|
15
|
+
if (syncTask.isRunning()) {
|
|
16
|
+
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
|
|
17
|
+
syncTask.execute();
|
|
18
|
+
}
|
|
19
|
+
// If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
|
|
20
|
+
// Data will be sent when submitter is resumed.
|
|
21
|
+
});
|
|
22
|
+
return syncTask;
|
|
23
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
2
|
import { thenable } from '../utils/promise/thenable';
|
|
3
|
-
import { truncateTimeFrame } from '../utils/time';
|
|
4
3
|
import { IMPRESSIONS_TRACKER_SUCCESS, ERROR_IMPRESSIONS_TRACKER, ERROR_IMPRESSIONS_LISTENER } from '../logger/constants';
|
|
5
4
|
import { CONSENT_DECLINED, DEDUPED, QUEUED } from '../utils/constants';
|
|
6
5
|
/**
|
|
@@ -10,52 +9,34 @@ import { CONSENT_DECLINED, DEDUPED, QUEUED } from '../utils/constants';
|
|
|
10
9
|
* @param metadata runtime metadata (ip, hostname and version)
|
|
11
10
|
* @param impressionListener optional impression listener
|
|
12
11
|
* @param integrationsManager optional integrations manager
|
|
13
|
-
* @param
|
|
14
|
-
* @param countsCache optional cache to save impressions count. If provided, impressions will be deduped (OPTIMIZED mode)
|
|
12
|
+
* @param strategy strategy for impressions tracking.
|
|
15
13
|
*/
|
|
16
|
-
export function impressionsTrackerFactory(settings, impressionsCache, integrationsManager,
|
|
17
|
-
// if observer is provided, it implies `shouldAddPreviousTime` flag (i.e., if impressions previous time should be added or not)
|
|
18
|
-
observer,
|
|
19
|
-
// if countsCache is provided, it implies `isOptimized` flag (i.e., if impressions should be deduped or not)
|
|
20
|
-
countsCache, telemetryCache) {
|
|
14
|
+
export function impressionsTrackerFactory(settings, impressionsCache, strategy, integrationsManager, telemetryCache) {
|
|
21
15
|
var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
|
|
22
16
|
return {
|
|
23
17
|
track: function (impressions, attributes) {
|
|
24
18
|
if (settings.userConsent === CONSENT_DECLINED)
|
|
25
19
|
return;
|
|
26
20
|
var impressionsCount = impressions.length;
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
var _a = strategy.process(impressions), impressionsToStore = _a.impressionsToStore, impressionsToListener = _a.impressionsToListener, deduped = _a.deduped;
|
|
22
|
+
var impressionsToListenerCount = impressionsToListener.length;
|
|
23
|
+
if (impressionsToStore.length > 0) {
|
|
24
|
+
var res = impressionsCache.track(impressionsToStore);
|
|
25
|
+
// If we're on an async storage, handle error and log it.
|
|
26
|
+
if (thenable(res)) {
|
|
27
|
+
res.then(function () {
|
|
28
|
+
log.info(IMPRESSIONS_TRACKER_SUCCESS, [impressionsCount]);
|
|
29
|
+
}).catch(function (err) {
|
|
30
|
+
log.error(ERROR_IMPRESSIONS_TRACKER, [impressionsCount, err]);
|
|
31
|
+
});
|
|
33
32
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
impressionsToStore.push(impression);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
var res = impressionsCache.track(impressionsToStore);
|
|
45
|
-
// If we're on an async storage, handle error and log it.
|
|
46
|
-
if (thenable(res)) {
|
|
47
|
-
res.then(function () {
|
|
48
|
-
log.info(IMPRESSIONS_TRACKER_SUCCESS, [impressionsCount]);
|
|
49
|
-
}).catch(function (err) {
|
|
50
|
-
log.error(ERROR_IMPRESSIONS_TRACKER, [impressionsCount, err]);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
// Record when impressionsCache is sync only (standalone mode)
|
|
55
|
-
// @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
|
|
56
|
-
if (telemetryCache) {
|
|
57
|
-
telemetryCache.recordImpressionStats(QUEUED, impressionsToStore.length);
|
|
58
|
-
telemetryCache.recordImpressionStats(DEDUPED, impressions.length - impressionsToStore.length);
|
|
33
|
+
else {
|
|
34
|
+
// Record when impressionsCache is sync only (standalone mode)
|
|
35
|
+
// @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
|
|
36
|
+
if (telemetryCache) {
|
|
37
|
+
telemetryCache.recordImpressionStats(QUEUED, impressionsToStore.length);
|
|
38
|
+
telemetryCache.recordImpressionStats(DEDUPED, deduped);
|
|
39
|
+
}
|
|
59
40
|
}
|
|
60
41
|
}
|
|
61
42
|
// @TODO next block might be handled by the integration manager. In that case, the metadata object doesn't need to be passed in the constructor
|
|
@@ -63,7 +44,7 @@ countsCache, telemetryCache) {
|
|
|
63
44
|
var _loop_1 = function (i) {
|
|
64
45
|
var impressionData = {
|
|
65
46
|
// copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
|
|
66
|
-
impression: objectAssign({},
|
|
47
|
+
impression: objectAssign({}, impressionsToListener[i]),
|
|
67
48
|
attributes: attributes,
|
|
68
49
|
ip: ip,
|
|
69
50
|
hostname: hostname,
|
|
@@ -83,7 +64,7 @@ countsCache, telemetryCache) {
|
|
|
83
64
|
}
|
|
84
65
|
}, 0);
|
|
85
66
|
};
|
|
86
|
-
for (var i = 0; i <
|
|
67
|
+
for (var i = 0; i < impressionsToListenerCount; i++) {
|
|
87
68
|
_loop_1(i);
|
|
88
69
|
}
|
|
89
70
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
|
|
3
|
+
*
|
|
4
|
+
* @param impressionsObserver impression observer. Previous time (pt property) is included in impression instances
|
|
5
|
+
* @returns IStrategyResult
|
|
6
|
+
*/
|
|
7
|
+
export function strategyDebugFactory(impressionsObserver) {
|
|
8
|
+
return {
|
|
9
|
+
process: function (impressions) {
|
|
10
|
+
impressions.forEach(function (impression) {
|
|
11
|
+
// Adds previous time if it is enabled
|
|
12
|
+
impression.pt = impressionsObserver.testAndSet(impression);
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
impressionsToStore: impressions,
|
|
16
|
+
impressionsToListener: impressions,
|
|
17
|
+
deduped: 0
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* None strategy for impressions tracker.
|
|
3
|
+
*
|
|
4
|
+
* @param impressionsCounter cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
|
|
5
|
+
* @param uniqueKeysTracker unique keys tracker in charge of tracking the unique keys per split.
|
|
6
|
+
* @returns IStrategyResult
|
|
7
|
+
*/
|
|
8
|
+
export function strategyNoneFactory(impressionsCounter, uniqueKeysTracker) {
|
|
9
|
+
return {
|
|
10
|
+
process: function (impressions) {
|
|
11
|
+
impressions.forEach(function (impression) {
|
|
12
|
+
var now = Date.now();
|
|
13
|
+
// Increments impression counter per featureName
|
|
14
|
+
impressionsCounter.track(impression.feature, now, 1);
|
|
15
|
+
// Keep track by unique key
|
|
16
|
+
uniqueKeysTracker.track(impression.keyName, impression.feature);
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
impressionsToStore: [],
|
|
20
|
+
impressionsToListener: impressions,
|
|
21
|
+
deduped: 0
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { truncateTimeFrame } from '../../utils/time';
|
|
2
|
+
/**
|
|
3
|
+
* Optimized strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
|
|
4
|
+
*
|
|
5
|
+
* @param impressionsObserver impression observer. previous time (pt property) is included in impression instances
|
|
6
|
+
* @param impressionsCounter cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
|
|
7
|
+
* @returns IStrategyResult
|
|
8
|
+
*/
|
|
9
|
+
export function strategyOptimizedFactory(impressionsObserver, impressionsCounter) {
|
|
10
|
+
return {
|
|
11
|
+
process: function (impressions) {
|
|
12
|
+
var impressionsToStore = [];
|
|
13
|
+
impressions.forEach(function (impression) {
|
|
14
|
+
impression.pt = impressionsObserver.testAndSet(impression);
|
|
15
|
+
var now = Date.now();
|
|
16
|
+
// Increments impression counter per featureName
|
|
17
|
+
if (impression.pt)
|
|
18
|
+
impressionsCounter.track(impression.feature, now, 1);
|
|
19
|
+
// Checks if the impression should be added in queue to be sent
|
|
20
|
+
if (!impression.pt || impression.pt < truncateTimeFrame(now)) {
|
|
21
|
+
impressionsToStore.push(impression);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
impressionsToStore: impressionsToStore,
|
|
26
|
+
impressionsToListener: impressions,
|
|
27
|
+
deduped: impressions.length - impressionsToStore.length
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -46,6 +46,11 @@ export function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
46
46
|
if (e === TOKEN_REFRESH)
|
|
47
47
|
telemetryCache.recordTokenRefreshes();
|
|
48
48
|
}
|
|
49
|
+
},
|
|
50
|
+
addTag: function (tag) {
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
if (telemetryCache.addTag)
|
|
53
|
+
telemetryCache.addTag(tag);
|
|
49
54
|
}
|
|
50
55
|
};
|
|
51
56
|
}
|
|
@@ -56,6 +61,7 @@ export function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
56
61
|
trackHttp: noopTrack,
|
|
57
62
|
sessionLength: function () { },
|
|
58
63
|
streamingEvent: function () { },
|
|
64
|
+
addTag: function () { }
|
|
59
65
|
};
|
|
60
66
|
}
|
|
61
67
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { LOG_PREFIX_UNIQUE_KEYS_TRACKER } from '../logger/constants';
|
|
2
|
+
var noopFilterAdapter = {
|
|
3
|
+
add: function () { return true; },
|
|
4
|
+
contains: function () { return true; },
|
|
5
|
+
clear: function () { }
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Trackes uniques keys
|
|
9
|
+
* Unique Keys Tracker will be in charge of checking if the MTK was already sent to the BE in the last period
|
|
10
|
+
* or schedule to be sent; if not it will be added in an internal cache and sent in the next post.
|
|
11
|
+
*
|
|
12
|
+
* @param log Logger instance
|
|
13
|
+
* @param uniqueKeysCache cache to save unique keys
|
|
14
|
+
* @param filterAdapter filter adapter
|
|
15
|
+
*/
|
|
16
|
+
export function uniqueKeysTrackerFactory(log, uniqueKeysCache, filterAdapter) {
|
|
17
|
+
if (filterAdapter === void 0) { filterAdapter = noopFilterAdapter; }
|
|
18
|
+
var intervalId;
|
|
19
|
+
if (filterAdapter.refreshRate) {
|
|
20
|
+
intervalId = setInterval(filterAdapter.clear, filterAdapter.refreshRate);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
track: function (key, featureName) {
|
|
24
|
+
if (!filterAdapter.add(key, featureName)) {
|
|
25
|
+
log.debug(LOG_PREFIX_UNIQUE_KEYS_TRACKER + "The feature " + featureName + " and key " + key + " exist in the filter");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
uniqueKeysCache.track(key, featureName);
|
|
29
|
+
},
|
|
30
|
+
stop: function () {
|
|
31
|
+
clearInterval(intervalId);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|