@splitsoftware/splitio-commons 1.3.2-rc.2 → 1.3.2-rc.5
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 +5 -0
- package/cjs/listeners/browser.js +6 -1
- package/cjs/readiness/sdkReadinessManager.js +7 -7
- package/cjs/storages/KeyBuilderSS.js +9 -5
- package/cjs/storages/inRedis/RedisAdapter.js +1 -1
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +7 -0
- package/cjs/storages/inRedis/index.js +4 -1
- package/cjs/storages/pluggable/index.js +2 -1
- package/cjs/sync/submitters/telemetrySubmitter.js +27 -14
- package/cjs/trackers/telemetryTracker.js +2 -2
- package/cjs/utils/timeTracker/now/node.js +1 -1
- package/esm/listeners/browser.js +6 -1
- package/esm/readiness/sdkReadinessManager.js +7 -7
- package/esm/storages/KeyBuilderSS.js +9 -5
- package/esm/storages/inRedis/RedisAdapter.js +1 -1
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +7 -0
- package/esm/storages/inRedis/index.js +4 -1
- package/esm/storages/pluggable/index.js +2 -1
- package/esm/sync/submitters/telemetrySubmitter.js +26 -14
- package/esm/trackers/telemetryTracker.js +2 -2
- package/esm/utils/timeTracker/now/node.js +1 -1
- package/package.json +1 -1
- package/src/listeners/browser.ts +6 -1
- package/src/readiness/sdkReadinessManager.ts +7 -5
- package/src/readiness/types.ts +7 -1
- package/src/storages/KeyBuilderSS.ts +12 -6
- package/src/storages/inRedis/RedisAdapter.ts +1 -1
- package/src/storages/inRedis/TelemetryCacheInRedis.ts +7 -0
- package/src/storages/inRedis/index.ts +5 -1
- package/src/storages/pluggable/index.ts +2 -1
- package/src/sync/submitters/telemetrySubmitter.ts +29 -15
- package/src/sync/submitters/types.ts +11 -6
- package/src/trackers/telemetryTracker.ts +2 -2
- package/src/utils/murmur3/utfx.ts +1 -2
- package/src/utils/timeTracker/now/node.ts +1 -1
- package/types/readiness/sdkReadinessManager.d.ts +1 -3
- package/types/readiness/types.d.ts +6 -1
- package/types/storages/KeyBuilderSS.d.ts +3 -2
- package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +1 -0
- package/types/sync/submitters/telemetrySubmitter.d.ts +3 -2
- package/types/sync/submitters/types.d.ts +8 -5
package/CHANGES.txt
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
1.4.0 (May XX, 2022)
|
|
2
|
+
- Added `scheduler.telemetryRefreshRate` property to SDK configuration, and deprecated `scheduler.metricsRefreshRate` property.
|
|
3
|
+
- Updated SDK telemetry storage, metrics and updater to be more effective and send less often.
|
|
4
|
+
- Bugfixing - Updated default values for `scheduler.impressionsRefreshRate` config parameter: 300s for OPTIMIZED impression mode and 60s for DEBUG impression mode.
|
|
5
|
+
|
|
1
6
|
1.3.1 (April 19, 2022)
|
|
2
7
|
- Bugfixing - Added peer dependencies to avoid issues when requiring some third-party dependencies used by modules of the package (Related to issue https://github.com/splitio/javascript-client/issues/662).
|
|
3
8
|
- Bugfixing - Updated `ready` method to rejects the promise with an Error object instead of a string value (Related to issue https://github.com/splitio/javascript-client/issues/654).
|
package/cjs/listeners/browser.js
CHANGED
|
@@ -7,6 +7,7 @@ var constants_1 = require("../utils/constants");
|
|
|
7
7
|
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
8
8
|
var constants_2 = require("../logger/constants");
|
|
9
9
|
var consent_1 = require("../consent");
|
|
10
|
+
var telemetrySubmitter_1 = require("../sync/submitters/telemetrySubmitter");
|
|
10
11
|
// 'unload' event is used instead of 'beforeunload', since 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
11
12
|
var UNLOAD_DOM_EVENT = 'unload';
|
|
12
13
|
var EVENT_NAME = 'for unload page event.';
|
|
@@ -63,7 +64,11 @@ var BrowserSignalListener = /** @class */ (function () {
|
|
|
63
64
|
this._flushData(eventsUrl + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
|
|
64
65
|
if (this.storage.impressionCounts)
|
|
65
66
|
this._flushData(eventsUrl + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, impressionCountsSubmitter_1.fromImpressionCountsCollector);
|
|
66
|
-
|
|
67
|
+
if (this.storage.telemetry) {
|
|
68
|
+
var telemetryUrl = this.settings.urls.telemetry;
|
|
69
|
+
var telemetryCacheAdapter = (0, telemetrySubmitter_1.telemetryCacheStatsAdapter)(this.storage.telemetry, this.storage.splits, this.storage.segments);
|
|
70
|
+
this._flushData(telemetryUrl + '/v1/metrics/usage/beacon', telemetryCacheAdapter, this.serviceApi.postMetricsUsage);
|
|
71
|
+
}
|
|
67
72
|
}
|
|
68
73
|
// Close streaming connection
|
|
69
74
|
if (this.syncManager.pushManager)
|
|
@@ -13,15 +13,13 @@ var REMOVE_LISTENER_EVENT = 'removeListener';
|
|
|
13
13
|
* It also updates logs related warnings and errors.
|
|
14
14
|
*
|
|
15
15
|
* @param readyTimeout time in millis to emit SDK_READY_TIME_OUT event
|
|
16
|
-
* @param internalReadyCbCount offset value of SDK_READY listeners that are added/removed internally
|
|
17
|
-
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
18
16
|
* @param readinessManager optional readinessManager to use. only used internally for `shared` method
|
|
19
17
|
*/
|
|
20
|
-
function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout,
|
|
18
|
+
function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager) {
|
|
21
19
|
if (readyTimeout === void 0) { readyTimeout = 0; }
|
|
22
|
-
if (internalReadyCbCount === void 0) { internalReadyCbCount = 0; }
|
|
23
20
|
if (readinessManager === void 0) { readinessManager = (0, readinessManager_1.readinessManagerFactory)(EventEmitter, readyTimeout); }
|
|
24
21
|
/** Ready callback warning */
|
|
22
|
+
var internalReadyCbCount = 0;
|
|
25
23
|
var readyCbCount = 0;
|
|
26
24
|
readinessManager.gate.on(REMOVE_LISTENER_EVENT, function (event) {
|
|
27
25
|
if (event === constants_1.SDK_READY)
|
|
@@ -62,10 +60,12 @@ function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, internalRea
|
|
|
62
60
|
}
|
|
63
61
|
return {
|
|
64
62
|
readinessManager: readinessManager,
|
|
65
|
-
shared: function (readyTimeout
|
|
63
|
+
shared: function (readyTimeout) {
|
|
66
64
|
if (readyTimeout === void 0) { readyTimeout = 0; }
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager.shared(readyTimeout));
|
|
66
|
+
},
|
|
67
|
+
incInternalReadyCbCount: function () {
|
|
68
|
+
internalReadyCbCount++;
|
|
69
69
|
},
|
|
70
70
|
sdkStatus: (0, objectAssign_1.objectAssign)(
|
|
71
71
|
// Expose Event Emitter functionality
|
|
@@ -20,23 +20,27 @@ var KeyBuilderSS = /** @class */ (function (_super) {
|
|
|
20
20
|
KeyBuilderSS.prototype.buildRegisteredSegmentsKey = function () {
|
|
21
21
|
return this.prefix + ".segments.registered";
|
|
22
22
|
};
|
|
23
|
-
KeyBuilderSS.prototype.buildVersionablePrefix = function () {
|
|
24
|
-
return this.metadata.s + "/" + this.metadata.n + "/" + this.metadata.i;
|
|
25
|
-
};
|
|
26
23
|
KeyBuilderSS.prototype.buildImpressionsKey = function () {
|
|
27
24
|
return this.prefix + ".impressions";
|
|
28
25
|
};
|
|
29
26
|
KeyBuilderSS.prototype.buildEventsKey = function () {
|
|
30
27
|
return this.prefix + ".events";
|
|
31
28
|
};
|
|
29
|
+
KeyBuilderSS.prototype.searchPatternForSplitKeys = function () {
|
|
30
|
+
return this.buildSplitKeyPrefix() + "*";
|
|
31
|
+
};
|
|
32
|
+
/* Telemetry keys */
|
|
32
33
|
KeyBuilderSS.prototype.buildLatencyKey = function (method, bucket) {
|
|
33
34
|
return this.prefix + ".telemetry.latencies::" + this.buildVersionablePrefix() + "/" + methodNames[method] + "/" + bucket;
|
|
34
35
|
};
|
|
35
36
|
KeyBuilderSS.prototype.buildExceptionKey = function (method) {
|
|
36
37
|
return this.prefix + ".telemetry.exceptions::" + this.buildVersionablePrefix() + "/" + methodNames[method];
|
|
37
38
|
};
|
|
38
|
-
KeyBuilderSS.prototype.
|
|
39
|
-
return this.
|
|
39
|
+
KeyBuilderSS.prototype.buildInitKey = function () {
|
|
40
|
+
return this.prefix + ".telemetry.init::" + this.buildVersionablePrefix();
|
|
41
|
+
};
|
|
42
|
+
KeyBuilderSS.prototype.buildVersionablePrefix = function () {
|
|
43
|
+
return this.metadata.s + "/" + this.metadata.n + "/" + this.metadata.i;
|
|
40
44
|
};
|
|
41
45
|
return KeyBuilderSS;
|
|
42
46
|
}(KeyBuilder_1.KeyBuilder));
|
|
@@ -9,7 +9,7 @@ var thenable_1 = require("../../utils/promise/thenable");
|
|
|
9
9
|
var timeout_1 = require("../../utils/promise/timeout");
|
|
10
10
|
var LOG_PREFIX = 'storage:redis-adapter: ';
|
|
11
11
|
// If we ever decide to fully wrap every method, there's a Commander.getBuiltinCommands from ioredis.
|
|
12
|
-
var METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'pipeline', 'expire', 'mget', 'lrange', 'ltrim'];
|
|
12
|
+
var METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'pipeline', 'expire', 'mget', 'lrange', 'ltrim', 'hset'];
|
|
13
13
|
// Not part of the settings since it'll vary on each storage. We should be removing storage specific logic from elsewhere.
|
|
14
14
|
var DEFAULT_OPTIONS = {
|
|
15
15
|
connectionTimeout: 10000,
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TelemetryCacheInRedis = void 0;
|
|
4
4
|
var findLatencyIndex_1 = require("../findLatencyIndex");
|
|
5
|
+
var telemetrySubmitter_1 = require("../../sync/submitters/telemetrySubmitter");
|
|
6
|
+
var constants_1 = require("../../utils/constants");
|
|
5
7
|
var TelemetryCacheInRedis = /** @class */ (function () {
|
|
6
8
|
/**
|
|
7
9
|
* Create a Telemetry cache that uses Redis as storage.
|
|
@@ -24,6 +26,11 @@ var TelemetryCacheInRedis = /** @class */ (function () {
|
|
|
24
26
|
return this.redis.hincrby(key, field, 1)
|
|
25
27
|
.catch(function () { });
|
|
26
28
|
};
|
|
29
|
+
TelemetryCacheInRedis.prototype.recordConfig = function () {
|
|
30
|
+
var _a = this.keys.buildInitKey().split('::'), key = _a[0], field = _a[1];
|
|
31
|
+
var value = JSON.stringify((0, telemetrySubmitter_1.getTelemetryConfigStats)(constants_1.CONSUMER_MODE, constants_1.STORAGE_REDIS));
|
|
32
|
+
return this.redis.hset(key, field, value).catch(function () { });
|
|
33
|
+
};
|
|
27
34
|
return TelemetryCacheInRedis;
|
|
28
35
|
}());
|
|
29
36
|
exports.TelemetryCacheInRedis = TelemetryCacheInRedis;
|
|
@@ -21,16 +21,19 @@ function InRedisStorage(options) {
|
|
|
21
21
|
var log = _a.log, metadata = _a.metadata, onReadyCb = _a.onReadyCb;
|
|
22
22
|
var keys = new KeyBuilderSS_1.KeyBuilderSS(prefix, metadata);
|
|
23
23
|
var redisClient = new RedisAdapter_1.RedisAdapter(log, options.options || {});
|
|
24
|
+
var telemetry = new TelemetryCacheInRedis_1.TelemetryCacheInRedis(log, keys, redisClient);
|
|
24
25
|
// subscription to Redis connect event in order to emit SDK_READY event on consumer mode
|
|
25
26
|
redisClient.on('connect', function () {
|
|
26
27
|
onReadyCb();
|
|
28
|
+
// Synchronize config
|
|
29
|
+
telemetry.recordConfig();
|
|
27
30
|
});
|
|
28
31
|
return {
|
|
29
32
|
splits: new SplitsCacheInRedis_1.SplitsCacheInRedis(log, keys, redisClient),
|
|
30
33
|
segments: new SegmentsCacheInRedis_1.SegmentsCacheInRedis(log, keys, redisClient),
|
|
31
34
|
impressions: new ImpressionsCacheInRedis_1.ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
|
|
32
35
|
events: new EventsCacheInRedis_1.EventsCacheInRedis(log, keys.buildEventsKey(), redisClient, metadata),
|
|
33
|
-
telemetry:
|
|
36
|
+
telemetry: telemetry,
|
|
34
37
|
// When using REDIS we should:
|
|
35
38
|
// 1- Disconnect from the storage
|
|
36
39
|
destroy: function () {
|
|
@@ -34,6 +34,7 @@ function validatePluggableStorageOptions(options) {
|
|
|
34
34
|
function wrapperConnect(wrapper, onReadyCb) {
|
|
35
35
|
wrapper.connect().then(function () {
|
|
36
36
|
onReadyCb();
|
|
37
|
+
// At the moment, we don't synchronize config with pluggable storage
|
|
37
38
|
}).catch(function (e) {
|
|
38
39
|
onReadyCb(e || new Error('Error connecting wrapper'));
|
|
39
40
|
});
|
|
@@ -66,7 +67,7 @@ function PluggableStorage(options) {
|
|
|
66
67
|
impressions: isPartialConsumer ? new ImpressionsCacheInMemory_1.ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable_1.ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
|
|
67
68
|
impressionCounts: optimize ? new ImpressionCountsCacheInMemory_1.ImpressionCountsCacheInMemory() : undefined,
|
|
68
69
|
events: isPartialConsumer ? promisifyEventsTrack(new EventsCacheInMemory_1.EventsCacheInMemory(eventsQueueSize)) : new EventsCachePluggable_1.EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata),
|
|
69
|
-
// @TODO Not using TelemetryCachePluggable yet
|
|
70
|
+
// @TODO Not using TelemetryCachePluggable yet because it's not supported by the Split Synchronizer, and needs to drop or queue operations while the wrapper is not ready
|
|
70
71
|
// telemetry: isPartialConsumer ? new TelemetryCacheInMemory() : new TelemetryCachePluggable(log, keys, wrapper),
|
|
71
72
|
// Disconnect the underlying storage
|
|
72
73
|
destroy: function () {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _a, _b;
|
|
2
|
+
var _a, _b, _c;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.telemetrySubmitterFactory = exports.telemetryCacheConfigAdapter = exports.telemetryCacheStatsAdapter = void 0;
|
|
4
|
+
exports.telemetrySubmitterFactory = exports.telemetryCacheConfigAdapter = exports.getTelemetryConfigStats = exports.telemetryCacheStatsAdapter = void 0;
|
|
5
5
|
var submitter_1 = require("./submitter");
|
|
6
6
|
var constants_1 = require("../../utils/constants");
|
|
7
7
|
var constants_2 = require("../../readiness/constants");
|
|
8
8
|
var settingsValidation_1 = require("../../utils/settingsValidation");
|
|
9
9
|
var apiKey_1 = require("../../utils/inputValidation/apiKey");
|
|
10
10
|
var timer_1 = require("../../utils/timeTracker/timer");
|
|
11
|
+
var objectAssign_1 = require("../../utils/lang/objectAssign");
|
|
11
12
|
/**
|
|
12
13
|
* Converts data from telemetry cache into /metrics/usage request payload.
|
|
13
14
|
*/
|
|
@@ -50,6 +51,11 @@ var IMPRESSIONS_MODE_MAP = (_b = {},
|
|
|
50
51
|
_b[constants_1.OPTIMIZED] = constants_1.OPTIMIZED_ENUM,
|
|
51
52
|
_b[constants_1.DEBUG] = constants_1.DEBUG_ENUM,
|
|
52
53
|
_b);
|
|
54
|
+
var USER_CONSENT_MAP = (_c = {},
|
|
55
|
+
_c[constants_1.CONSENT_UNKNOWN] = 1,
|
|
56
|
+
_c[constants_1.CONSENT_GRANTED] = 2,
|
|
57
|
+
_c[constants_1.CONSENT_DECLINED] = 3,
|
|
58
|
+
_c);
|
|
53
59
|
function getActiveFactories() {
|
|
54
60
|
return Object.keys(apiKey_1.usedKeysMap).length;
|
|
55
61
|
}
|
|
@@ -58,6 +64,15 @@ function getRedundantActiveFactories() {
|
|
|
58
64
|
return acum + apiKey_1.usedKeysMap[apiKey] - 1;
|
|
59
65
|
}, 0);
|
|
60
66
|
}
|
|
67
|
+
function getTelemetryConfigStats(mode, storageType) {
|
|
68
|
+
return {
|
|
69
|
+
oM: OPERATION_MODE_MAP[mode],
|
|
70
|
+
st: storageType.toLowerCase(),
|
|
71
|
+
aF: getActiveFactories(),
|
|
72
|
+
rF: getRedundantActiveFactories(),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
exports.getTelemetryConfigStats = getTelemetryConfigStats;
|
|
61
76
|
/**
|
|
62
77
|
* Converts data from telemetry cache and settings into /metrics/config request payload.
|
|
63
78
|
*/
|
|
@@ -67,16 +82,14 @@ function telemetryCacheConfigAdapter(telemetry, settings) {
|
|
|
67
82
|
clear: function () { },
|
|
68
83
|
state: function () {
|
|
69
84
|
var urls = settings.urls, scheduler = settings.scheduler;
|
|
70
|
-
return {
|
|
71
|
-
oM: OPERATION_MODE_MAP[settings.mode],
|
|
72
|
-
st: settings.storage.type.toLowerCase(),
|
|
85
|
+
return (0, objectAssign_1.objectAssign)(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
73
86
|
sE: settings.streamingEnabled,
|
|
74
87
|
rR: {
|
|
75
|
-
sp: scheduler.featuresRefreshRate,
|
|
76
|
-
se: scheduler.segmentsRefreshRate,
|
|
77
|
-
im: scheduler.impressionsRefreshRate,
|
|
78
|
-
ev: scheduler.eventsPushRate,
|
|
79
|
-
te: scheduler.telemetryRefreshRate,
|
|
88
|
+
sp: scheduler.featuresRefreshRate / 1000,
|
|
89
|
+
se: scheduler.segmentsRefreshRate / 1000,
|
|
90
|
+
im: scheduler.impressionsRefreshRate / 1000,
|
|
91
|
+
ev: scheduler.eventsPushRate / 1000,
|
|
92
|
+
te: scheduler.telemetryRefreshRate / 1000,
|
|
80
93
|
},
|
|
81
94
|
uO: {
|
|
82
95
|
s: urls.sdk !== settingsValidation_1.base.urls.sdk,
|
|
@@ -90,14 +103,13 @@ function telemetryCacheConfigAdapter(telemetry, settings) {
|
|
|
90
103
|
iM: IMPRESSIONS_MODE_MAP[settings.sync.impressionsMode],
|
|
91
104
|
iL: settings.impressionListener ? true : false,
|
|
92
105
|
hP: false,
|
|
93
|
-
aF: getActiveFactories(),
|
|
94
|
-
rF: getRedundantActiveFactories(),
|
|
95
106
|
tR: telemetry.getTimeUntilReady(),
|
|
96
107
|
tC: telemetry.getTimeUntilReadyFromCache(),
|
|
97
108
|
nR: telemetry.getNonReadyUsage(),
|
|
98
109
|
t: telemetry.popTags(),
|
|
99
110
|
i: settings.integrations && settings.integrations.map(function (int) { return int.type; }),
|
|
100
|
-
|
|
111
|
+
uC: settings.userConsent ? USER_CONSENT_MAP[settings.userConsent] : 0
|
|
112
|
+
});
|
|
101
113
|
}
|
|
102
114
|
};
|
|
103
115
|
}
|
|
@@ -109,12 +121,13 @@ function telemetrySubmitterFactory(params) {
|
|
|
109
121
|
var _a = params.storage, splits = _a.splits, segments = _a.segments, telemetry = _a.telemetry;
|
|
110
122
|
if (!telemetry)
|
|
111
123
|
return; // No submitter created if telemetry cache is not defined
|
|
112
|
-
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, now = params.platform.now, readiness = params.readiness;
|
|
124
|
+
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, now = params.platform.now, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
|
|
113
125
|
var startTime = (0, timer_1.timer)(now || Date.now);
|
|
114
126
|
var submitter = (0, submitter_1.firstPushWindowDecorator)((0, submitter_1.submitterFactory)(log, splitApi.postMetricsUsage, telemetryCacheStatsAdapter(telemetry, splits, segments), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
|
|
115
127
|
readiness.gate.once(constants_2.SDK_READY_FROM_CACHE, function () {
|
|
116
128
|
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
117
129
|
});
|
|
130
|
+
sdkReadinessManager.incInternalReadyCbCount();
|
|
118
131
|
readiness.gate.once(constants_2.SDK_READY, function () {
|
|
119
132
|
telemetry.recordTimeUntilReady(startTime());
|
|
120
133
|
// Post config data when the SDK is ready and if the telemetry submitter was started
|
|
@@ -29,7 +29,7 @@ function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
29
29
|
if (error && error.statusCode)
|
|
30
30
|
telemetryCache.recordHttpError(operation, error.statusCode);
|
|
31
31
|
else
|
|
32
|
-
telemetryCache.recordSuccessfulSync(operation, now());
|
|
32
|
+
telemetryCache.recordSuccessfulSync(operation, Date.now());
|
|
33
33
|
};
|
|
34
34
|
},
|
|
35
35
|
sessionLength: function () {
|
|
@@ -44,7 +44,7 @@ function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
44
44
|
telemetryCache.recordStreamingEvents({
|
|
45
45
|
e: e,
|
|
46
46
|
d: d,
|
|
47
|
-
t: now()
|
|
47
|
+
t: Date.now()
|
|
48
48
|
});
|
|
49
49
|
if (e === constants_1.TOKEN_REFRESH)
|
|
50
50
|
telemetryCache.recordTokenRefreshes();
|
package/esm/listeners/browser.js
CHANGED
|
@@ -4,6 +4,7 @@ import { OPTIMIZED, DEBUG } from '../utils/constants';
|
|
|
4
4
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
5
5
|
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
|
|
6
6
|
import { isConsentGranted } from '../consent';
|
|
7
|
+
import { telemetryCacheStatsAdapter } from '../sync/submitters/telemetrySubmitter';
|
|
7
8
|
// 'unload' event is used instead of 'beforeunload', since 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
8
9
|
var UNLOAD_DOM_EVENT = 'unload';
|
|
9
10
|
var EVENT_NAME = 'for unload page event.';
|
|
@@ -60,7 +61,11 @@ var BrowserSignalListener = /** @class */ (function () {
|
|
|
60
61
|
this._flushData(eventsUrl + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
|
|
61
62
|
if (this.storage.impressionCounts)
|
|
62
63
|
this._flushData(eventsUrl + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, fromImpressionCountsCollector);
|
|
63
|
-
|
|
64
|
+
if (this.storage.telemetry) {
|
|
65
|
+
var telemetryUrl = this.settings.urls.telemetry;
|
|
66
|
+
var telemetryCacheAdapter = telemetryCacheStatsAdapter(this.storage.telemetry, this.storage.splits, this.storage.segments);
|
|
67
|
+
this._flushData(telemetryUrl + '/v1/metrics/usage/beacon', telemetryCacheAdapter, this.serviceApi.postMetricsUsage);
|
|
68
|
+
}
|
|
64
69
|
}
|
|
65
70
|
// Close streaming connection
|
|
66
71
|
if (this.syncManager.pushManager)
|
|
@@ -10,15 +10,13 @@ var REMOVE_LISTENER_EVENT = 'removeListener';
|
|
|
10
10
|
* It also updates logs related warnings and errors.
|
|
11
11
|
*
|
|
12
12
|
* @param readyTimeout time in millis to emit SDK_READY_TIME_OUT event
|
|
13
|
-
* @param internalReadyCbCount offset value of SDK_READY listeners that are added/removed internally
|
|
14
|
-
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
15
13
|
* @param readinessManager optional readinessManager to use. only used internally for `shared` method
|
|
16
14
|
*/
|
|
17
|
-
export function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout,
|
|
15
|
+
export function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager) {
|
|
18
16
|
if (readyTimeout === void 0) { readyTimeout = 0; }
|
|
19
|
-
if (internalReadyCbCount === void 0) { internalReadyCbCount = 0; }
|
|
20
17
|
if (readinessManager === void 0) { readinessManager = readinessManagerFactory(EventEmitter, readyTimeout); }
|
|
21
18
|
/** Ready callback warning */
|
|
19
|
+
var internalReadyCbCount = 0;
|
|
22
20
|
var readyCbCount = 0;
|
|
23
21
|
readinessManager.gate.on(REMOVE_LISTENER_EVENT, function (event) {
|
|
24
22
|
if (event === SDK_READY)
|
|
@@ -59,10 +57,12 @@ export function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, inte
|
|
|
59
57
|
}
|
|
60
58
|
return {
|
|
61
59
|
readinessManager: readinessManager,
|
|
62
|
-
shared: function (readyTimeout
|
|
60
|
+
shared: function (readyTimeout) {
|
|
63
61
|
if (readyTimeout === void 0) { readyTimeout = 0; }
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager.shared(readyTimeout));
|
|
63
|
+
},
|
|
64
|
+
incInternalReadyCbCount: function () {
|
|
65
|
+
internalReadyCbCount++;
|
|
66
66
|
},
|
|
67
67
|
sdkStatus: objectAssign(
|
|
68
68
|
// Expose Event Emitter functionality
|
|
@@ -17,23 +17,27 @@ var KeyBuilderSS = /** @class */ (function (_super) {
|
|
|
17
17
|
KeyBuilderSS.prototype.buildRegisteredSegmentsKey = function () {
|
|
18
18
|
return this.prefix + ".segments.registered";
|
|
19
19
|
};
|
|
20
|
-
KeyBuilderSS.prototype.buildVersionablePrefix = function () {
|
|
21
|
-
return this.metadata.s + "/" + this.metadata.n + "/" + this.metadata.i;
|
|
22
|
-
};
|
|
23
20
|
KeyBuilderSS.prototype.buildImpressionsKey = function () {
|
|
24
21
|
return this.prefix + ".impressions";
|
|
25
22
|
};
|
|
26
23
|
KeyBuilderSS.prototype.buildEventsKey = function () {
|
|
27
24
|
return this.prefix + ".events";
|
|
28
25
|
};
|
|
26
|
+
KeyBuilderSS.prototype.searchPatternForSplitKeys = function () {
|
|
27
|
+
return this.buildSplitKeyPrefix() + "*";
|
|
28
|
+
};
|
|
29
|
+
/* Telemetry keys */
|
|
29
30
|
KeyBuilderSS.prototype.buildLatencyKey = function (method, bucket) {
|
|
30
31
|
return this.prefix + ".telemetry.latencies::" + this.buildVersionablePrefix() + "/" + methodNames[method] + "/" + bucket;
|
|
31
32
|
};
|
|
32
33
|
KeyBuilderSS.prototype.buildExceptionKey = function (method) {
|
|
33
34
|
return this.prefix + ".telemetry.exceptions::" + this.buildVersionablePrefix() + "/" + methodNames[method];
|
|
34
35
|
};
|
|
35
|
-
KeyBuilderSS.prototype.
|
|
36
|
-
return this.
|
|
36
|
+
KeyBuilderSS.prototype.buildInitKey = function () {
|
|
37
|
+
return this.prefix + ".telemetry.init::" + this.buildVersionablePrefix();
|
|
38
|
+
};
|
|
39
|
+
KeyBuilderSS.prototype.buildVersionablePrefix = function () {
|
|
40
|
+
return this.metadata.s + "/" + this.metadata.n + "/" + this.metadata.i;
|
|
37
41
|
};
|
|
38
42
|
return KeyBuilderSS;
|
|
39
43
|
}(KeyBuilder));
|
|
@@ -6,7 +6,7 @@ import { thenable } from '../../utils/promise/thenable';
|
|
|
6
6
|
import { timeout } from '../../utils/promise/timeout';
|
|
7
7
|
var LOG_PREFIX = 'storage:redis-adapter: ';
|
|
8
8
|
// If we ever decide to fully wrap every method, there's a Commander.getBuiltinCommands from ioredis.
|
|
9
|
-
var METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'pipeline', 'expire', 'mget', 'lrange', 'ltrim'];
|
|
9
|
+
var METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'pipeline', 'expire', 'mget', 'lrange', 'ltrim', 'hset'];
|
|
10
10
|
// Not part of the settings since it'll vary on each storage. We should be removing storage specific logic from elsewhere.
|
|
11
11
|
var DEFAULT_OPTIONS = {
|
|
12
12
|
connectionTimeout: 10000,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { findLatencyIndex } from '../findLatencyIndex';
|
|
2
|
+
import { getTelemetryConfigStats } from '../../sync/submitters/telemetrySubmitter';
|
|
3
|
+
import { CONSUMER_MODE, STORAGE_REDIS } from '../../utils/constants';
|
|
2
4
|
var TelemetryCacheInRedis = /** @class */ (function () {
|
|
3
5
|
/**
|
|
4
6
|
* Create a Telemetry cache that uses Redis as storage.
|
|
@@ -21,6 +23,11 @@ var TelemetryCacheInRedis = /** @class */ (function () {
|
|
|
21
23
|
return this.redis.hincrby(key, field, 1)
|
|
22
24
|
.catch(function () { });
|
|
23
25
|
};
|
|
26
|
+
TelemetryCacheInRedis.prototype.recordConfig = function () {
|
|
27
|
+
var _a = this.keys.buildInitKey().split('::'), key = _a[0], field = _a[1];
|
|
28
|
+
var value = JSON.stringify(getTelemetryConfigStats(CONSUMER_MODE, STORAGE_REDIS));
|
|
29
|
+
return this.redis.hset(key, field, value).catch(function () { });
|
|
30
|
+
};
|
|
24
31
|
return TelemetryCacheInRedis;
|
|
25
32
|
}());
|
|
26
33
|
export { TelemetryCacheInRedis };
|
|
@@ -18,16 +18,19 @@ export function InRedisStorage(options) {
|
|
|
18
18
|
var log = _a.log, metadata = _a.metadata, onReadyCb = _a.onReadyCb;
|
|
19
19
|
var keys = new KeyBuilderSS(prefix, metadata);
|
|
20
20
|
var redisClient = new RedisAdapter(log, options.options || {});
|
|
21
|
+
var telemetry = new TelemetryCacheInRedis(log, keys, redisClient);
|
|
21
22
|
// subscription to Redis connect event in order to emit SDK_READY event on consumer mode
|
|
22
23
|
redisClient.on('connect', function () {
|
|
23
24
|
onReadyCb();
|
|
25
|
+
// Synchronize config
|
|
26
|
+
telemetry.recordConfig();
|
|
24
27
|
});
|
|
25
28
|
return {
|
|
26
29
|
splits: new SplitsCacheInRedis(log, keys, redisClient),
|
|
27
30
|
segments: new SegmentsCacheInRedis(log, keys, redisClient),
|
|
28
31
|
impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
|
|
29
32
|
events: new EventsCacheInRedis(log, keys.buildEventsKey(), redisClient, metadata),
|
|
30
|
-
telemetry:
|
|
33
|
+
telemetry: telemetry,
|
|
31
34
|
// When using REDIS we should:
|
|
32
35
|
// 1- Disconnect from the storage
|
|
33
36
|
destroy: function () {
|
|
@@ -31,6 +31,7 @@ function validatePluggableStorageOptions(options) {
|
|
|
31
31
|
function wrapperConnect(wrapper, onReadyCb) {
|
|
32
32
|
wrapper.connect().then(function () {
|
|
33
33
|
onReadyCb();
|
|
34
|
+
// At the moment, we don't synchronize config with pluggable storage
|
|
34
35
|
}).catch(function (e) {
|
|
35
36
|
onReadyCb(e || new Error('Error connecting wrapper'));
|
|
36
37
|
});
|
|
@@ -63,7 +64,7 @@ export function PluggableStorage(options) {
|
|
|
63
64
|
impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
|
|
64
65
|
impressionCounts: optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
65
66
|
events: isPartialConsumer ? promisifyEventsTrack(new EventsCacheInMemory(eventsQueueSize)) : new EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata),
|
|
66
|
-
// @TODO Not using TelemetryCachePluggable yet
|
|
67
|
+
// @TODO Not using TelemetryCachePluggable yet because it's not supported by the Split Synchronizer, and needs to drop or queue operations while the wrapper is not ready
|
|
67
68
|
// telemetry: isPartialConsumer ? new TelemetryCacheInMemory() : new TelemetryCachePluggable(log, keys, wrapper),
|
|
68
69
|
// Disconnect the underlying storage
|
|
69
70
|
destroy: function () {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
var _a, _b;
|
|
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 } from '../../utils/constants';
|
|
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';
|
|
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
|
+
import { objectAssign } from '../../utils/lang/objectAssign';
|
|
8
9
|
/**
|
|
9
10
|
* Converts data from telemetry cache into /metrics/usage request payload.
|
|
10
11
|
*/
|
|
@@ -46,6 +47,11 @@ var IMPRESSIONS_MODE_MAP = (_b = {},
|
|
|
46
47
|
_b[OPTIMIZED] = OPTIMIZED_ENUM,
|
|
47
48
|
_b[DEBUG] = DEBUG_ENUM,
|
|
48
49
|
_b);
|
|
50
|
+
var USER_CONSENT_MAP = (_c = {},
|
|
51
|
+
_c[CONSENT_UNKNOWN] = 1,
|
|
52
|
+
_c[CONSENT_GRANTED] = 2,
|
|
53
|
+
_c[CONSENT_DECLINED] = 3,
|
|
54
|
+
_c);
|
|
49
55
|
function getActiveFactories() {
|
|
50
56
|
return Object.keys(usedKeysMap).length;
|
|
51
57
|
}
|
|
@@ -54,6 +60,14 @@ function getRedundantActiveFactories() {
|
|
|
54
60
|
return acum + usedKeysMap[apiKey] - 1;
|
|
55
61
|
}, 0);
|
|
56
62
|
}
|
|
63
|
+
export function getTelemetryConfigStats(mode, storageType) {
|
|
64
|
+
return {
|
|
65
|
+
oM: OPERATION_MODE_MAP[mode],
|
|
66
|
+
st: storageType.toLowerCase(),
|
|
67
|
+
aF: getActiveFactories(),
|
|
68
|
+
rF: getRedundantActiveFactories(),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
57
71
|
/**
|
|
58
72
|
* Converts data from telemetry cache and settings into /metrics/config request payload.
|
|
59
73
|
*/
|
|
@@ -63,16 +77,14 @@ export function telemetryCacheConfigAdapter(telemetry, settings) {
|
|
|
63
77
|
clear: function () { },
|
|
64
78
|
state: function () {
|
|
65
79
|
var urls = settings.urls, scheduler = settings.scheduler;
|
|
66
|
-
return {
|
|
67
|
-
oM: OPERATION_MODE_MAP[settings.mode],
|
|
68
|
-
st: settings.storage.type.toLowerCase(),
|
|
80
|
+
return objectAssign(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
69
81
|
sE: settings.streamingEnabled,
|
|
70
82
|
rR: {
|
|
71
|
-
sp: scheduler.featuresRefreshRate,
|
|
72
|
-
se: scheduler.segmentsRefreshRate,
|
|
73
|
-
im: scheduler.impressionsRefreshRate,
|
|
74
|
-
ev: scheduler.eventsPushRate,
|
|
75
|
-
te: scheduler.telemetryRefreshRate,
|
|
83
|
+
sp: scheduler.featuresRefreshRate / 1000,
|
|
84
|
+
se: scheduler.segmentsRefreshRate / 1000,
|
|
85
|
+
im: scheduler.impressionsRefreshRate / 1000,
|
|
86
|
+
ev: scheduler.eventsPushRate / 1000,
|
|
87
|
+
te: scheduler.telemetryRefreshRate / 1000,
|
|
76
88
|
},
|
|
77
89
|
uO: {
|
|
78
90
|
s: urls.sdk !== base.urls.sdk,
|
|
@@ -86,14 +98,13 @@ export function telemetryCacheConfigAdapter(telemetry, settings) {
|
|
|
86
98
|
iM: IMPRESSIONS_MODE_MAP[settings.sync.impressionsMode],
|
|
87
99
|
iL: settings.impressionListener ? true : false,
|
|
88
100
|
hP: false,
|
|
89
|
-
aF: getActiveFactories(),
|
|
90
|
-
rF: getRedundantActiveFactories(),
|
|
91
101
|
tR: telemetry.getTimeUntilReady(),
|
|
92
102
|
tC: telemetry.getTimeUntilReadyFromCache(),
|
|
93
103
|
nR: telemetry.getNonReadyUsage(),
|
|
94
104
|
t: telemetry.popTags(),
|
|
95
105
|
i: settings.integrations && settings.integrations.map(function (int) { return int.type; }),
|
|
96
|
-
|
|
106
|
+
uC: settings.userConsent ? USER_CONSENT_MAP[settings.userConsent] : 0
|
|
107
|
+
});
|
|
97
108
|
}
|
|
98
109
|
};
|
|
99
110
|
}
|
|
@@ -104,12 +115,13 @@ export function telemetrySubmitterFactory(params) {
|
|
|
104
115
|
var _a = params.storage, splits = _a.splits, segments = _a.segments, telemetry = _a.telemetry;
|
|
105
116
|
if (!telemetry)
|
|
106
117
|
return; // No submitter created if telemetry cache is not defined
|
|
107
|
-
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, now = params.platform.now, readiness = params.readiness;
|
|
118
|
+
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, now = params.platform.now, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
|
|
108
119
|
var startTime = timer(now || Date.now);
|
|
109
120
|
var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage, telemetryCacheStatsAdapter(telemetry, splits, segments), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
|
|
110
121
|
readiness.gate.once(SDK_READY_FROM_CACHE, function () {
|
|
111
122
|
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
112
123
|
});
|
|
124
|
+
sdkReadinessManager.incInternalReadyCbCount();
|
|
113
125
|
readiness.gate.once(SDK_READY, function () {
|
|
114
126
|
telemetry.recordTimeUntilReady(startTime());
|
|
115
127
|
// Post config data when the SDK is ready and if the telemetry submitter was started
|
|
@@ -26,7 +26,7 @@ export function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
26
26
|
if (error && error.statusCode)
|
|
27
27
|
telemetryCache.recordHttpError(operation, error.statusCode);
|
|
28
28
|
else
|
|
29
|
-
telemetryCache.recordSuccessfulSync(operation, now());
|
|
29
|
+
telemetryCache.recordSuccessfulSync(operation, Date.now());
|
|
30
30
|
};
|
|
31
31
|
},
|
|
32
32
|
sessionLength: function () {
|
|
@@ -41,7 +41,7 @@ export function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
41
41
|
telemetryCache.recordStreamingEvents({
|
|
42
42
|
e: e,
|
|
43
43
|
d: d,
|
|
44
|
-
t: now()
|
|
44
|
+
t: Date.now()
|
|
45
45
|
});
|
|
46
46
|
if (e === TOKEN_REFRESH)
|
|
47
47
|
telemetryCache.recordTokenRefreshes();
|
package/package.json
CHANGED
package/src/listeners/browser.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
12
12
|
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
|
|
13
13
|
import { ISyncManager } from '../sync/types';
|
|
14
14
|
import { isConsentGranted } from '../consent';
|
|
15
|
+
import { telemetryCacheStatsAdapter } from '../sync/submitters/telemetrySubmitter';
|
|
15
16
|
|
|
16
17
|
// 'unload' event is used instead of 'beforeunload', since 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
17
18
|
const UNLOAD_DOM_EVENT = 'unload';
|
|
@@ -77,7 +78,11 @@ export class BrowserSignalListener implements ISignalListener {
|
|
|
77
78
|
this._flushData(eventsUrl + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
|
|
78
79
|
this._flushData(eventsUrl + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
|
|
79
80
|
if (this.storage.impressionCounts) this._flushData(eventsUrl + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, fromImpressionCountsCollector);
|
|
80
|
-
|
|
81
|
+
if (this.storage.telemetry) {
|
|
82
|
+
const telemetryUrl = this.settings.urls.telemetry;
|
|
83
|
+
const telemetryCacheAdapter = telemetryCacheStatsAdapter(this.storage.telemetry, this.storage.splits, this.storage.segments);
|
|
84
|
+
this._flushData(telemetryUrl + '/v1/metrics/usage/beacon', telemetryCacheAdapter, this.serviceApi.postMetricsUsage);
|
|
85
|
+
}
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
// Close streaming connection
|
|
@@ -15,18 +15,16 @@ const REMOVE_LISTENER_EVENT = 'removeListener';
|
|
|
15
15
|
* It also updates logs related warnings and errors.
|
|
16
16
|
*
|
|
17
17
|
* @param readyTimeout time in millis to emit SDK_READY_TIME_OUT event
|
|
18
|
-
* @param internalReadyCbCount offset value of SDK_READY listeners that are added/removed internally
|
|
19
|
-
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
20
18
|
* @param readinessManager optional readinessManager to use. only used internally for `shared` method
|
|
21
19
|
*/
|
|
22
20
|
export function sdkReadinessManagerFactory(
|
|
23
21
|
log: ILogger,
|
|
24
22
|
EventEmitter: new () => IEventEmitter,
|
|
25
23
|
readyTimeout = 0,
|
|
26
|
-
internalReadyCbCount = 0,
|
|
27
24
|
readinessManager = readinessManagerFactory(EventEmitter, readyTimeout)): ISdkReadinessManager {
|
|
28
25
|
|
|
29
26
|
/** Ready callback warning */
|
|
27
|
+
let internalReadyCbCount = 0;
|
|
30
28
|
let readyCbCount = 0;
|
|
31
29
|
readinessManager.gate.on(REMOVE_LISTENER_EVENT, (event: any) => {
|
|
32
30
|
if (event === SDK_READY) readyCbCount--;
|
|
@@ -74,8 +72,12 @@ export function sdkReadinessManagerFactory(
|
|
|
74
72
|
return {
|
|
75
73
|
readinessManager,
|
|
76
74
|
|
|
77
|
-
shared(readyTimeout = 0
|
|
78
|
-
return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout,
|
|
75
|
+
shared(readyTimeout = 0) {
|
|
76
|
+
return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager.shared(readyTimeout));
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
incInternalReadyCbCount() {
|
|
80
|
+
internalReadyCbCount++;
|
|
79
81
|
},
|
|
80
82
|
|
|
81
83
|
sdkStatus: objectAssign(
|
package/src/readiness/types.ts
CHANGED
|
@@ -66,6 +66,12 @@ export interface ISdkReadinessManager {
|
|
|
66
66
|
readinessManager: IReadinessManager
|
|
67
67
|
sdkStatus: IStatusInterface
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Increment internalReadyCbCount, an offset value of SDK_READY listeners that are added/removed internally
|
|
71
|
+
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
72
|
+
*/
|
|
73
|
+
incInternalReadyCbCount(): void
|
|
74
|
+
|
|
69
75
|
/** for client-side */
|
|
70
|
-
shared(readyTimeout?: number
|
|
76
|
+
shared(readyTimeout?: number): ISdkReadinessManager
|
|
71
77
|
}
|
|
@@ -23,10 +23,6 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
23
23
|
return `${this.prefix}.segments.registered`;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
private buildVersionablePrefix() {
|
|
27
|
-
return `${this.metadata.s}/${this.metadata.n}/${this.metadata.i}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
26
|
buildImpressionsKey() {
|
|
31
27
|
return `${this.prefix}.impressions`;
|
|
32
28
|
}
|
|
@@ -35,6 +31,12 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
35
31
|
return `${this.prefix}.events`;
|
|
36
32
|
}
|
|
37
33
|
|
|
34
|
+
searchPatternForSplitKeys() {
|
|
35
|
+
return `${this.buildSplitKeyPrefix()}*`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Telemetry keys */
|
|
39
|
+
|
|
38
40
|
buildLatencyKey(method: Method, bucket: number) {
|
|
39
41
|
return `${this.prefix}.telemetry.latencies::${this.buildVersionablePrefix()}/${methodNames[method]}/${bucket}`;
|
|
40
42
|
}
|
|
@@ -43,8 +45,12 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
43
45
|
return `${this.prefix}.telemetry.exceptions::${this.buildVersionablePrefix()}/${methodNames[method]}`;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
return `${this.
|
|
48
|
+
buildInitKey() {
|
|
49
|
+
return `${this.prefix}.telemetry.init::${this.buildVersionablePrefix()}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private buildVersionablePrefix() {
|
|
53
|
+
return `${this.metadata.s}/${this.metadata.n}/${this.metadata.i}`;
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
}
|
|
@@ -8,7 +8,7 @@ import { timeout } from '../../utils/promise/timeout';
|
|
|
8
8
|
const LOG_PREFIX = 'storage:redis-adapter: ';
|
|
9
9
|
|
|
10
10
|
// If we ever decide to fully wrap every method, there's a Commander.getBuiltinCommands from ioredis.
|
|
11
|
-
const METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'pipeline', 'expire', 'mget', 'lrange', 'ltrim'];
|
|
11
|
+
const METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'pipeline', 'expire', 'mget', 'lrange', 'ltrim', 'hset'];
|
|
12
12
|
|
|
13
13
|
// Not part of the settings since it'll vary on each storage. We should be removing storage specific logic from elsewhere.
|
|
14
14
|
const DEFAULT_OPTIONS = {
|
|
@@ -4,6 +4,8 @@ import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
|
4
4
|
import { ITelemetryCacheAsync } from '../types';
|
|
5
5
|
import { findLatencyIndex } from '../findLatencyIndex';
|
|
6
6
|
import { Redis } from 'ioredis';
|
|
7
|
+
import { getTelemetryConfigStats } from '../../sync/submitters/telemetrySubmitter';
|
|
8
|
+
import { CONSUMER_MODE, STORAGE_REDIS } from '../../utils/constants';
|
|
7
9
|
|
|
8
10
|
export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
9
11
|
|
|
@@ -26,4 +28,9 @@ export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
26
28
|
.catch(() => { /* Handle rejections for telemetry */ });
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
recordConfig() {
|
|
32
|
+
const [key, field] = this.keys.buildInitKey().split('::');
|
|
33
|
+
const value = JSON.stringify(getTelemetryConfigStats(CONSUMER_MODE, STORAGE_REDIS));
|
|
34
|
+
return this.redis.hset(key, field, value).catch(() => { /* Handle rejections for telemetry */ });
|
|
35
|
+
}
|
|
29
36
|
}
|
|
@@ -26,10 +26,14 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
26
26
|
|
|
27
27
|
const keys = new KeyBuilderSS(prefix, metadata);
|
|
28
28
|
const redisClient = new RedisAdapter(log, options.options || {});
|
|
29
|
+
const telemetry = new TelemetryCacheInRedis(log, keys, redisClient);
|
|
29
30
|
|
|
30
31
|
// subscription to Redis connect event in order to emit SDK_READY event on consumer mode
|
|
31
32
|
redisClient.on('connect', () => {
|
|
32
33
|
onReadyCb();
|
|
34
|
+
|
|
35
|
+
// Synchronize config
|
|
36
|
+
telemetry.recordConfig();
|
|
33
37
|
});
|
|
34
38
|
|
|
35
39
|
return {
|
|
@@ -37,7 +41,7 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
37
41
|
segments: new SegmentsCacheInRedis(log, keys, redisClient),
|
|
38
42
|
impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
|
|
39
43
|
events: new EventsCacheInRedis(log, keys.buildEventsKey(), redisClient, metadata),
|
|
40
|
-
telemetry
|
|
44
|
+
telemetry,
|
|
41
45
|
|
|
42
46
|
// When using REDIS we should:
|
|
43
47
|
// 1- Disconnect from the storage
|
|
@@ -39,6 +39,7 @@ function validatePluggableStorageOptions(options: any) {
|
|
|
39
39
|
function wrapperConnect(wrapper: IPluggableStorageWrapper, onReadyCb: (error?: any) => void) {
|
|
40
40
|
wrapper.connect().then(() => {
|
|
41
41
|
onReadyCb();
|
|
42
|
+
// At the moment, we don't synchronize config with pluggable storage
|
|
42
43
|
}).catch((e) => {
|
|
43
44
|
onReadyCb(e || new Error('Error connecting wrapper'));
|
|
44
45
|
});
|
|
@@ -77,7 +78,7 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
77
78
|
impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
|
|
78
79
|
impressionCounts: optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
79
80
|
events: isPartialConsumer ? promisifyEventsTrack(new EventsCacheInMemory(eventsQueueSize)) : new EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata),
|
|
80
|
-
// @TODO Not using TelemetryCachePluggable yet
|
|
81
|
+
// @TODO Not using TelemetryCachePluggable yet because it's not supported by the Split Synchronizer, and needs to drop or queue operations while the wrapper is not ready
|
|
81
82
|
// telemetry: isPartialConsumer ? new TelemetryCacheInMemory() : new TelemetryCachePluggable(log, keys, wrapper),
|
|
82
83
|
|
|
83
84
|
// Disconnect the underlying storage
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { ISegmentsCacheSync, ISplitsCacheSync, ITelemetryCacheSync } from '../../storages/types';
|
|
2
2
|
import { submitterFactory, firstPushWindowDecorator } from './submitter';
|
|
3
|
-
import { TelemetryUsageStatsPayload, TelemetryConfigStatsPayload } from './types';
|
|
4
|
-
import { QUEUED, DEDUPED, DROPPED, CONSUMER_MODE, CONSUMER_ENUM, STANDALONE_MODE, CONSUMER_PARTIAL_MODE, STANDALONE_ENUM, CONSUMER_PARTIAL_ENUM, OPTIMIZED, DEBUG, DEBUG_ENUM, OPTIMIZED_ENUM } from '../../utils/constants';
|
|
3
|
+
import { TelemetryUsageStatsPayload, TelemetryConfigStatsPayload, TelemetryConfigStats } from './types';
|
|
4
|
+
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';
|
|
5
5
|
import { SDK_READY, SDK_READY_FROM_CACHE } from '../../readiness/constants';
|
|
6
|
-
import { ISettings } from '../../types';
|
|
6
|
+
import { ConsentStatus, ISettings, SDKMode } from '../../types';
|
|
7
7
|
import { base } from '../../utils/settingsValidation';
|
|
8
8
|
import { usedKeysMap } from '../../utils/inputValidation/apiKey';
|
|
9
9
|
import { timer } from '../../utils/timeTracker/timer';
|
|
10
10
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
11
|
+
import { objectAssign } from '../../utils/lang/objectAssign';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Converts data from telemetry cache into /metrics/usage request payload.
|
|
@@ -54,6 +55,12 @@ const IMPRESSIONS_MODE_MAP = {
|
|
|
54
55
|
[DEBUG]: DEBUG_ENUM
|
|
55
56
|
} as Record<ISettings['sync']['impressionsMode'], (0 | 1)>;
|
|
56
57
|
|
|
58
|
+
const USER_CONSENT_MAP = {
|
|
59
|
+
[CONSENT_UNKNOWN]: 1,
|
|
60
|
+
[CONSENT_GRANTED]: 2,
|
|
61
|
+
[CONSENT_DECLINED]: 3
|
|
62
|
+
} as Record<ConsentStatus, number>;
|
|
63
|
+
|
|
57
64
|
function getActiveFactories() {
|
|
58
65
|
return Object.keys(usedKeysMap).length;
|
|
59
66
|
}
|
|
@@ -64,6 +71,15 @@ function getRedundantActiveFactories() {
|
|
|
64
71
|
}, 0);
|
|
65
72
|
}
|
|
66
73
|
|
|
74
|
+
export function getTelemetryConfigStats(mode: SDKMode, storageType: string): TelemetryConfigStats {
|
|
75
|
+
return {
|
|
76
|
+
oM: OPERATION_MODE_MAP[mode], // @ts-ignore lower case of storage type
|
|
77
|
+
st: storageType.toLowerCase(),
|
|
78
|
+
aF: getActiveFactories(),
|
|
79
|
+
rF: getRedundantActiveFactories(),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
67
83
|
/**
|
|
68
84
|
* Converts data from telemetry cache and settings into /metrics/config request payload.
|
|
69
85
|
*/
|
|
@@ -75,16 +91,14 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett
|
|
|
75
91
|
state(): TelemetryConfigStatsPayload {
|
|
76
92
|
const { urls, scheduler } = settings;
|
|
77
93
|
|
|
78
|
-
return {
|
|
79
|
-
oM: OPERATION_MODE_MAP[settings.mode], // @ts-ignore lower case of storage type
|
|
80
|
-
st: settings.storage.type.toLowerCase(),
|
|
94
|
+
return objectAssign(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
81
95
|
sE: settings.streamingEnabled,
|
|
82
96
|
rR: {
|
|
83
|
-
sp: scheduler.featuresRefreshRate,
|
|
84
|
-
se: scheduler.segmentsRefreshRate,
|
|
85
|
-
im: scheduler.impressionsRefreshRate,
|
|
86
|
-
ev: scheduler.eventsPushRate,
|
|
87
|
-
te: scheduler.telemetryRefreshRate,
|
|
97
|
+
sp: scheduler.featuresRefreshRate / 1000,
|
|
98
|
+
se: scheduler.segmentsRefreshRate / 1000,
|
|
99
|
+
im: scheduler.impressionsRefreshRate / 1000,
|
|
100
|
+
ev: scheduler.eventsPushRate / 1000,
|
|
101
|
+
te: scheduler.telemetryRefreshRate / 1000,
|
|
88
102
|
}, // refreshRates
|
|
89
103
|
uO: {
|
|
90
104
|
s: urls.sdk !== base.urls.sdk,
|
|
@@ -98,14 +112,13 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett
|
|
|
98
112
|
iM: IMPRESSIONS_MODE_MAP[settings.sync.impressionsMode],
|
|
99
113
|
iL: settings.impressionListener ? true : false,
|
|
100
114
|
hP: false, // @TODO proxy not supported
|
|
101
|
-
aF: getActiveFactories(),
|
|
102
|
-
rF: getRedundantActiveFactories(),
|
|
103
115
|
tR: telemetry.getTimeUntilReady() as number,
|
|
104
116
|
tC: telemetry.getTimeUntilReadyFromCache(),
|
|
105
117
|
nR: telemetry.getNonReadyUsage(),
|
|
106
118
|
t: telemetry.popTags(),
|
|
107
119
|
i: settings.integrations && settings.integrations.map(int => int.type),
|
|
108
|
-
|
|
120
|
+
uC: settings.userConsent ? USER_CONSENT_MAP[settings.userConsent] : 0
|
|
121
|
+
});
|
|
109
122
|
}
|
|
110
123
|
};
|
|
111
124
|
}
|
|
@@ -117,7 +130,7 @@ export function telemetrySubmitterFactory(params: ISdkFactoryContextSync) {
|
|
|
117
130
|
const { storage: { splits, segments, telemetry } } = params;
|
|
118
131
|
if (!telemetry) return; // No submitter created if telemetry cache is not defined
|
|
119
132
|
|
|
120
|
-
const { settings, settings: { log, scheduler: { telemetryRefreshRate } }, splitApi, platform: { now }, readiness } = params;
|
|
133
|
+
const { settings, settings: { log, scheduler: { telemetryRefreshRate } }, splitApi, platform: { now }, readiness, sdkReadinessManager } = params;
|
|
121
134
|
const startTime = timer(now || Date.now);
|
|
122
135
|
|
|
123
136
|
const submitter = firstPushWindowDecorator(
|
|
@@ -129,6 +142,7 @@ export function telemetrySubmitterFactory(params: ISdkFactoryContextSync) {
|
|
|
129
142
|
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
130
143
|
});
|
|
131
144
|
|
|
145
|
+
sdkReadinessManager.incInternalReadyCbCount();
|
|
132
146
|
readiness.gate.once(SDK_READY, () => {
|
|
133
147
|
telemetry.recordTimeUntilReady(startTime());
|
|
134
148
|
|
|
@@ -165,10 +165,17 @@ export type UrlOverrides = {
|
|
|
165
165
|
t: boolean, // telemetry
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
// '
|
|
169
|
-
export type
|
|
170
|
-
oM
|
|
168
|
+
// 'telemetry.init' Redis/Pluggable key
|
|
169
|
+
export type TelemetryConfigStats = {
|
|
170
|
+
oM: OperationMode, // operationMode
|
|
171
171
|
st: 'memory' | 'redis' | 'pluggable' | 'localstorage', // storage
|
|
172
|
+
aF: number, // activeFactories
|
|
173
|
+
rF: number, // redundantActiveFactories
|
|
174
|
+
t?: Array<string>, // tags
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 'metrics/config' JSON request body
|
|
178
|
+
export type TelemetryConfigStatsPayload = TelemetryConfigStats & {
|
|
172
179
|
sE: boolean, // streamingEnabled
|
|
173
180
|
rR: RefreshRates, // refreshRates
|
|
174
181
|
uO: UrlOverrides, // urlOverrides
|
|
@@ -177,11 +184,9 @@ export type TelemetryConfigStatsPayload = {
|
|
|
177
184
|
iM: ImpressionsMode, // impressionsMode
|
|
178
185
|
iL: boolean, // impressionsListenerEnabled
|
|
179
186
|
hP: boolean, // httpProxyDetected
|
|
180
|
-
aF: number, // activeFactories
|
|
181
|
-
rF: number, // redundantActiveFactories
|
|
182
187
|
tR: number, // timeUntilSDKReady
|
|
183
188
|
tC?: number, // timeUntilSDKReadyFromCache
|
|
184
189
|
nR: number, // SDKNotReadyUsage
|
|
185
|
-
t?: Array<string>, // tags
|
|
186
190
|
i?: Array<string>, // integrations
|
|
191
|
+
uC: number, // userConsent
|
|
187
192
|
}
|
|
@@ -33,7 +33,7 @@ export function telemetryTrackerFactory(
|
|
|
33
33
|
return (error) => {
|
|
34
34
|
(telemetryCache as ITelemetryCacheSync).recordHttpLatency(operation, httpTime());
|
|
35
35
|
if (error && error.statusCode) (telemetryCache as ITelemetryCacheSync).recordHttpError(operation, error.statusCode);
|
|
36
|
-
else (telemetryCache as ITelemetryCacheSync).recordSuccessfulSync(operation, now());
|
|
36
|
+
else (telemetryCache as ITelemetryCacheSync).recordSuccessfulSync(operation, Date.now());
|
|
37
37
|
};
|
|
38
38
|
},
|
|
39
39
|
sessionLength() { // @ts-ignore ITelemetryCacheAsync doesn't implement the method
|
|
@@ -44,7 +44,7 @@ export function telemetryTrackerFactory(
|
|
|
44
44
|
(telemetryCache as ITelemetryCacheSync).recordAuthRejections();
|
|
45
45
|
} else {
|
|
46
46
|
(telemetryCache as ITelemetryCacheSync).recordStreamingEvents({
|
|
47
|
-
e, d, t: now()
|
|
47
|
+
e, d, t: Date.now()
|
|
48
48
|
});
|
|
49
49
|
if (e === TOKEN_REFRESH) (telemetryCache as ITelemetryCacheSync).recordTokenRefreshes();
|
|
50
50
|
}
|
|
@@ -6,8 +6,6 @@ import { ILogger } from '../logger/types';
|
|
|
6
6
|
* It also updates logs related warnings and errors.
|
|
7
7
|
*
|
|
8
8
|
* @param readyTimeout time in millis to emit SDK_READY_TIME_OUT event
|
|
9
|
-
* @param internalReadyCbCount offset value of SDK_READY listeners that are added/removed internally
|
|
10
|
-
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
11
9
|
* @param readinessManager optional readinessManager to use. only used internally for `shared` method
|
|
12
10
|
*/
|
|
13
|
-
export declare function sdkReadinessManagerFactory(log: ILogger, EventEmitter: new () => IEventEmitter, readyTimeout?: number,
|
|
11
|
+
export declare function sdkReadinessManagerFactory(log: ILogger, EventEmitter: new () => IEventEmitter, readyTimeout?: number, readinessManager?: import("./types").IReadinessManager): ISdkReadinessManager;
|
|
@@ -49,7 +49,12 @@ export interface IReadinessManager {
|
|
|
49
49
|
export interface ISdkReadinessManager {
|
|
50
50
|
readinessManager: IReadinessManager;
|
|
51
51
|
sdkStatus: IStatusInterface;
|
|
52
|
+
/**
|
|
53
|
+
* Increment internalReadyCbCount, an offset value of SDK_READY listeners that are added/removed internally
|
|
54
|
+
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
55
|
+
*/
|
|
56
|
+
incInternalReadyCbCount(): void;
|
|
52
57
|
/** for client-side */
|
|
53
|
-
shared(readyTimeout?: number
|
|
58
|
+
shared(readyTimeout?: number): ISdkReadinessManager;
|
|
54
59
|
}
|
|
55
60
|
export {};
|
|
@@ -5,10 +5,11 @@ export declare class KeyBuilderSS extends KeyBuilder {
|
|
|
5
5
|
protected readonly metadata: IMetadata;
|
|
6
6
|
constructor(prefix: string, metadata: IMetadata);
|
|
7
7
|
buildRegisteredSegmentsKey(): string;
|
|
8
|
-
private buildVersionablePrefix;
|
|
9
8
|
buildImpressionsKey(): string;
|
|
10
9
|
buildEventsKey(): string;
|
|
10
|
+
searchPatternForSplitKeys(): string;
|
|
11
11
|
buildLatencyKey(method: Method, bucket: number): string;
|
|
12
12
|
buildExceptionKey(method: Method): string;
|
|
13
|
-
|
|
13
|
+
buildInitKey(): string;
|
|
14
|
+
private buildVersionablePrefix;
|
|
14
15
|
}
|
|
@@ -16,4 +16,5 @@ export declare class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
16
16
|
constructor(log: ILogger, keys: KeyBuilderSS, redis: Redis);
|
|
17
17
|
recordLatency(method: Method, latencyMs: number): Promise<number | void>;
|
|
18
18
|
recordException(method: Method): Promise<number | void>;
|
|
19
|
+
recordConfig(): Promise<number | void>;
|
|
19
20
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ISegmentsCacheSync, ISplitsCacheSync, ITelemetryCacheSync } from '../../storages/types';
|
|
2
|
-
import { TelemetryUsageStatsPayload, TelemetryConfigStatsPayload } from './types';
|
|
3
|
-
import { ISettings } from '../../types';
|
|
2
|
+
import { TelemetryUsageStatsPayload, TelemetryConfigStatsPayload, TelemetryConfigStats } from './types';
|
|
3
|
+
import { ISettings, SDKMode } from '../../types';
|
|
4
4
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
5
5
|
/**
|
|
6
6
|
* Converts data from telemetry cache into /metrics/usage request payload.
|
|
@@ -10,6 +10,7 @@ export declare function telemetryCacheStatsAdapter(telemetry: ITelemetryCacheSyn
|
|
|
10
10
|
clear(): void;
|
|
11
11
|
state(): TelemetryUsageStatsPayload;
|
|
12
12
|
};
|
|
13
|
+
export declare function getTelemetryConfigStats(mode: SDKMode, storageType: string): TelemetryConfigStats;
|
|
13
14
|
/**
|
|
14
15
|
* Converts data from telemetry cache and settings into /metrics/config request payload.
|
|
15
16
|
*/
|
|
@@ -146,9 +146,14 @@ export declare type UrlOverrides = {
|
|
|
146
146
|
st: boolean;
|
|
147
147
|
t: boolean;
|
|
148
148
|
};
|
|
149
|
-
export declare type
|
|
150
|
-
oM
|
|
149
|
+
export declare type TelemetryConfigStats = {
|
|
150
|
+
oM: OperationMode;
|
|
151
151
|
st: 'memory' | 'redis' | 'pluggable' | 'localstorage';
|
|
152
|
+
aF: number;
|
|
153
|
+
rF: number;
|
|
154
|
+
t?: Array<string>;
|
|
155
|
+
};
|
|
156
|
+
export declare type TelemetryConfigStatsPayload = TelemetryConfigStats & {
|
|
152
157
|
sE: boolean;
|
|
153
158
|
rR: RefreshRates;
|
|
154
159
|
uO: UrlOverrides;
|
|
@@ -157,11 +162,9 @@ export declare type TelemetryConfigStatsPayload = {
|
|
|
157
162
|
iM: ImpressionsMode;
|
|
158
163
|
iL: boolean;
|
|
159
164
|
hP: boolean;
|
|
160
|
-
aF: number;
|
|
161
|
-
rF: number;
|
|
162
165
|
tR: number;
|
|
163
166
|
tC?: number;
|
|
164
167
|
nR: number;
|
|
165
|
-
t?: Array<string>;
|
|
166
168
|
i?: Array<string>;
|
|
169
|
+
uC: number;
|
|
167
170
|
};
|