@splitsoftware/splitio-commons 1.3.1 → 1.3.2-rc.2
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/cjs/consent/sdkUserConsent.js +1 -1
- package/cjs/listeners/browser.js +5 -4
- package/cjs/logger/constants.js +2 -1
- package/cjs/logger/messages/error.js +2 -1
- package/cjs/logger/messages/info.js +3 -3
- package/cjs/logger/messages/warn.js +2 -2
- package/cjs/sdkClient/client.js +17 -3
- package/cjs/sdkClient/sdkClient.js +4 -1
- package/cjs/sdkFactory/index.js +16 -19
- package/cjs/services/splitApi.js +15 -14
- package/cjs/services/splitHttpClient.js +4 -1
- package/cjs/storages/AbstractSegmentsCacheSync.js +0 -5
- package/cjs/storages/KeyBuilderSS.js +12 -19
- package/cjs/storages/findLatencyIndex.js +11 -6
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +13 -1
- package/cjs/storages/inLocalStorage/index.js +4 -1
- package/cjs/storages/inMemory/InMemoryStorage.js +2 -0
- package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -0
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +6 -0
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +6 -0
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +165 -0
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +29 -0
- package/cjs/storages/inRedis/index.js +2 -4
- package/cjs/storages/pluggable/TelemetryCachePluggable.js +27 -0
- package/cjs/storages/pluggable/index.js +2 -1
- package/cjs/sync/polling/pollingManagerCS.js +1 -1
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +0 -3
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -8
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +3 -6
- package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +20 -13
- package/cjs/sync/streaming/SSEHandler/index.js +21 -15
- package/cjs/sync/streaming/pushManager.js +7 -4
- package/cjs/sync/submitters/eventsSubmitter.js +28 -0
- package/cjs/sync/submitters/{impressionCountsSyncTask.js → impressionCountsSubmitter.js} +10 -7
- package/cjs/sync/submitters/{impressionsSyncTask.js → impressionsSubmitter.js} +8 -8
- package/cjs/sync/submitters/submitter.js +66 -0
- package/cjs/sync/submitters/submitterManager.js +12 -10
- package/cjs/sync/submitters/telemetrySubmitter.js +128 -0
- package/cjs/sync/syncManagerOnline.js +6 -2
- package/cjs/trackers/eventTracker.js +5 -1
- package/cjs/trackers/impressionsTracker.js +9 -1
- package/cjs/trackers/telemetryTracker.js +65 -0
- package/cjs/utils/constants/index.js +40 -1
- package/cjs/utils/inputValidation/apiKey.js +12 -11
- package/cjs/utils/settingsValidation/index.js +35 -11
- package/cjs/utils/settingsValidation/url.js +4 -0
- package/cjs/utils/timeTracker/index.js +1 -0
- package/cjs/utils/timeTracker/timer.js +2 -2
- package/esm/consent/sdkUserConsent.js +1 -1
- package/esm/listeners/browser.js +3 -2
- package/esm/logger/constants.js +1 -0
- package/esm/logger/messages/error.js +2 -1
- package/esm/logger/messages/info.js +3 -3
- package/esm/logger/messages/warn.js +2 -2
- package/esm/sdkClient/client.js +18 -4
- package/esm/sdkClient/sdkClient.js +4 -1
- package/esm/sdkFactory/index.js +16 -19
- package/esm/services/splitApi.js +15 -14
- package/esm/services/splitHttpClient.js +4 -1
- package/esm/storages/AbstractSegmentsCacheSync.js +0 -5
- package/esm/storages/KeyBuilderSS.js +12 -19
- package/esm/storages/findLatencyIndex.js +11 -6
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +13 -1
- package/esm/storages/inLocalStorage/index.js +5 -2
- package/esm/storages/inMemory/InMemoryStorage.js +3 -1
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -1
- package/esm/storages/inMemory/MySegmentsCacheInMemory.js +6 -0
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +6 -0
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +161 -0
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +26 -0
- package/esm/storages/inRedis/index.js +2 -4
- package/esm/storages/pluggable/TelemetryCachePluggable.js +24 -0
- package/esm/storages/pluggable/index.js +2 -1
- package/esm/sync/polling/pollingManagerCS.js +1 -1
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +0 -3
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -8
- package/esm/sync/polling/updaters/splitChangesUpdater.js +3 -6
- package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +8 -1
- package/esm/sync/streaming/SSEHandler/index.js +21 -15
- package/esm/sync/streaming/pushManager.js +7 -4
- package/esm/sync/submitters/eventsSubmitter.js +24 -0
- package/esm/sync/submitters/{impressionCountsSyncTask.js → impressionCountsSubmitter.js} +8 -5
- package/esm/sync/submitters/{impressionsSyncTask.js → impressionsSubmitter.js} +6 -6
- package/esm/sync/submitters/submitter.js +61 -0
- package/esm/sync/submitters/submitterManager.js +12 -10
- package/esm/sync/submitters/telemetrySubmitter.js +122 -0
- package/esm/sync/syncManagerOnline.js +6 -2
- package/esm/trackers/eventTracker.js +6 -2
- package/esm/trackers/impressionsTracker.js +10 -2
- package/esm/trackers/telemetryTracker.js +61 -0
- package/esm/utils/constants/index.js +38 -0
- package/esm/utils/inputValidation/apiKey.js +2 -1
- package/esm/utils/settingsValidation/index.js +34 -10
- package/esm/utils/settingsValidation/url.js +4 -0
- package/esm/utils/timeTracker/index.js +1 -0
- package/esm/utils/timeTracker/timer.js +2 -2
- package/package.json +1 -1
- package/src/consent/sdkUserConsent.ts +1 -1
- package/src/listeners/browser.ts +3 -2
- package/src/logger/constants.ts +1 -0
- package/src/logger/messages/error.ts +2 -1
- package/src/logger/messages/info.ts +3 -3
- package/src/logger/messages/warn.ts +2 -2
- package/src/sdkClient/client.ts +23 -4
- package/src/sdkClient/sdkClient.ts +4 -1
- package/src/sdkFactory/index.ts +22 -24
- package/src/sdkFactory/types.ts +32 -15
- package/src/services/splitApi.ts +17 -14
- package/src/services/splitHttpClient.ts +6 -3
- package/src/services/types.ts +7 -5
- package/src/storages/AbstractSegmentsCacheSync.ts +8 -3
- package/src/storages/KeyBuilderSS.ts +13 -50
- package/src/storages/findLatencyIndex.ts +12 -3
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +13 -1
- package/src/storages/inLocalStorage/index.ts +5 -2
- package/src/storages/inMemory/InMemoryStorage.ts +3 -1
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -1
- package/src/storages/inMemory/MySegmentsCacheInMemory.ts +8 -0
- package/src/storages/inMemory/SegmentsCacheInMemory.ts +6 -0
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +210 -0
- package/src/storages/inRedis/TelemetryCacheInRedis.ts +29 -0
- package/src/storages/inRedis/index.ts +2 -4
- package/src/storages/pluggable/TelemetryCachePluggable.ts +26 -0
- package/src/storages/pluggable/index.ts +2 -1
- package/src/storages/types.ts +84 -32
- package/src/sync/offline/syncManagerOffline.ts +4 -3
- package/src/sync/polling/pollingManagerCS.ts +3 -3
- package/src/sync/polling/pollingManagerSS.ts +2 -2
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +2 -0
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +0 -4
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +2 -10
- package/src/sync/polling/updaters/splitChangesUpdater.ts +3 -6
- package/src/sync/streaming/SSEHandler/NotificationKeeper.ts +11 -1
- package/src/sync/streaming/SSEHandler/index.ts +21 -14
- package/src/sync/streaming/pushManager.ts +11 -7
- package/src/sync/submitters/eventsSubmitter.ts +35 -0
- package/src/sync/submitters/{impressionCountsSyncTask.ts → impressionCountsSubmitter.ts} +15 -15
- package/src/sync/submitters/{impressionsSyncTask.ts → impressionsSubmitter.ts} +12 -16
- package/src/sync/submitters/{submitterSyncTask.ts → submitter.ts} +34 -16
- package/src/sync/submitters/submitterManager.ts +14 -11
- package/src/sync/submitters/telemetrySubmitter.ts +143 -0
- package/src/sync/submitters/types.ts +123 -0
- package/src/sync/syncManagerOnline.ts +13 -7
- package/src/sync/types.ts +0 -15
- package/src/trackers/eventTracker.ts +7 -3
- package/src/trackers/impressionsTracker.ts +11 -3
- package/src/trackers/telemetryTracker.ts +63 -0
- package/src/trackers/types.ts +24 -0
- package/src/types.ts +35 -6
- package/src/utils/constants/index.ts +45 -0
- package/src/utils/inputValidation/apiKey.ts +2 -1
- package/src/utils/settingsValidation/index.ts +35 -11
- package/src/utils/settingsValidation/url.ts +4 -0
- package/src/utils/timeTracker/index.ts +1 -1
- package/src/utils/timeTracker/timer.ts +3 -3
- package/types/logger/constants.d.ts +1 -0
- package/types/sdkFactory/types.d.ts +29 -14
- package/types/services/splitApi.d.ts +2 -1
- package/types/services/types.d.ts +8 -5
- package/types/storages/AbstractSegmentsCacheSync.d.ts +7 -3
- package/types/storages/KeyBuilderSS.d.ts +3 -3
- package/types/storages/findLatencyIndex.d.ts +7 -1
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +2 -0
- package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +2 -0
- package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +1 -0
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -2
- package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +3 -3
- package/types/storages/pluggable/TelemetryCachePluggable.d.ts +2 -2
- package/types/storages/types.d.ts +71 -22
- package/types/sync/offline/syncManagerOffline.d.ts +3 -2
- package/types/sync/polling/pollingManagerCS.d.ts +2 -2
- package/types/sync/polling/pollingManagerSS.d.ts +2 -2
- package/types/sync/polling/syncTasks/splitsSyncTask.d.ts +1 -1
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
- package/types/sync/streaming/SSEHandler/NotificationKeeper.d.ts +2 -1
- package/types/sync/streaming/SSEHandler/index.d.ts +2 -1
- package/types/sync/streaming/pushManager.d.ts +2 -2
- package/types/sync/submitters/eventsSubmitter.d.ts +5 -0
- package/types/sync/submitters/impressionCountsSubmitter.d.ts +10 -0
- package/types/sync/submitters/impressionsSubmitter.d.ts +11 -0
- package/types/sync/submitters/submitter.d.ts +12 -0
- package/types/sync/submitters/submitterManager.d.ts +2 -2
- package/types/sync/submitters/telemetrySubmitter.d.ts +24 -0
- package/types/sync/submitters/telemetrySyncTask.d.ts +0 -27
- package/types/sync/submitters/types.d.ts +107 -0
- package/types/sync/syncManagerOnline.d.ts +3 -2
- package/types/sync/types.d.ts +0 -13
- package/types/trackers/eventTracker.d.ts +2 -2
- package/types/trackers/impressionsTracker.d.ts +2 -2
- package/types/trackers/telemetryTracker.d.ts +2 -3
- package/types/trackers/types.d.ts +22 -0
- package/types/types.d.ts +33 -4
- package/types/utils/constants/index.d.ts +37 -0
- package/types/utils/inputValidation/apiKey.d.ts +1 -0
- package/types/utils/settingsValidation/index.d.ts +40 -0
- package/types/utils/timeTracker/index.d.ts +1 -1
- package/types/utils/timeTracker/timer.d.ts +1 -1
- package/cjs/storages/inMemory/CountsCacheInMemory.js +0 -38
- package/cjs/storages/inMemory/LatenciesCacheInMemory.js +0 -43
- package/cjs/storages/inRedis/CountsCacheInRedis.js +0 -16
- package/cjs/storages/inRedis/LatenciesCacheInRedis.js +0 -18
- package/cjs/sync/submitters/eventsSyncTask.js +0 -44
- package/cjs/sync/submitters/metricsSyncTask.js +0 -31
- package/cjs/sync/submitters/submitterSyncTask.js +0 -44
- package/esm/storages/inMemory/CountsCacheInMemory.js +0 -35
- package/esm/storages/inMemory/LatenciesCacheInMemory.js +0 -40
- package/esm/storages/inRedis/CountsCacheInRedis.js +0 -13
- package/esm/storages/inRedis/LatenciesCacheInRedis.js +0 -15
- package/esm/sync/submitters/eventsSyncTask.js +0 -40
- package/esm/sync/submitters/metricsSyncTask.js +0 -26
- package/esm/sync/submitters/submitterSyncTask.js +0 -40
- package/src/storages/inMemory/CountsCacheInMemory.ts +0 -37
- package/src/storages/inMemory/LatenciesCacheInMemory.ts +0 -45
- package/src/storages/inRedis/CountsCacheInRedis.ts +0 -20
- package/src/storages/inRedis/LatenciesCacheInRedis.ts +0 -23
- package/src/sync/submitters/eventsSyncTask.ts +0 -57
- package/src/sync/submitters/metricsSyncTask.ts +0 -49
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ISegmentChangesFetcher } from '../fetchers/types';
|
|
2
2
|
import { ISegmentsCacheBase } from '../../../storages/types';
|
|
3
3
|
import { IReadinessManager } from '../../../readiness/types';
|
|
4
|
-
import {
|
|
4
|
+
import { MaybeThenable } from '../../../dtos/types';
|
|
5
5
|
import { findIndex } from '../../../utils/lang';
|
|
6
6
|
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
7
7
|
import { ILogger } from '../../../logger/types';
|
|
@@ -30,14 +30,6 @@ export function segmentChangesUpdaterFactory(
|
|
|
30
30
|
|
|
31
31
|
let readyOnAlreadyExistentState = true;
|
|
32
32
|
|
|
33
|
-
/** telemetry decorator for `segmentChangesFetcher` promise */
|
|
34
|
-
function _promiseDecorator(promise: Promise<ISegmentChangesResponse[]>) {
|
|
35
|
-
return promise;
|
|
36
|
-
// @TODO handle telemetry?
|
|
37
|
-
// const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always.
|
|
38
|
-
// splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
33
|
/**
|
|
42
34
|
* Segments updater returns a promise that resolves with a `false` boolean value if it fails at least to fetch a segment or synchronize it with the storage.
|
|
43
35
|
* Thus, a false result doesn't imply that SDK_SEGMENTS_ARRIVED was not emitted.
|
|
@@ -67,7 +59,7 @@ export function segmentChangesUpdaterFactory(
|
|
|
67
59
|
// if fetchOnlyNew flag, avoid processing already fetched segments
|
|
68
60
|
if (fetchOnlyNew && since !== -1) return -1;
|
|
69
61
|
|
|
70
|
-
return segmentChangesFetcher(since, segmentName, noCache
|
|
62
|
+
return segmentChangesFetcher(since, segmentName, noCache).then(function (changes) {
|
|
71
63
|
let changeNumber = -1;
|
|
72
64
|
const results: MaybeThenable<boolean | void>[] = [];
|
|
73
65
|
changes.forEach(x => {
|
|
@@ -93,18 +93,15 @@ export function splitChangesUpdaterFactory(
|
|
|
93
93
|
splitsEventEmitter?: ISplitsEventEmitter,
|
|
94
94
|
requestTimeoutBeforeReady: number = 0,
|
|
95
95
|
retriesOnFailureBeforeReady: number = 0,
|
|
96
|
+
isClientSide?: boolean
|
|
96
97
|
): ISplitChangesUpdater {
|
|
97
98
|
|
|
98
99
|
let startingUp = true;
|
|
99
100
|
|
|
100
|
-
/** timeout
|
|
101
|
+
/** timeout decorator for `splitChangesFetcher` promise */
|
|
101
102
|
function _promiseDecorator<T>(promise: Promise<T>) {
|
|
102
103
|
if (startingUp && requestTimeoutBeforeReady) promise = timeout(requestTimeoutBeforeReady, promise);
|
|
103
104
|
return promise;
|
|
104
|
-
|
|
105
|
-
// @TODO telemetry
|
|
106
|
-
// const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always.
|
|
107
|
-
// splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise);
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
/**
|
|
@@ -144,7 +141,7 @@ export function splitChangesUpdaterFactory(
|
|
|
144
141
|
|
|
145
142
|
if (splitsEventEmitter) {
|
|
146
143
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
147
|
-
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && checkAllSegmentsExist(segments)))
|
|
144
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && (isClientSide || checkAllSegmentsExist(segments))))
|
|
148
145
|
.catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
149
146
|
.then(emitSplitsArrivedEvent => {
|
|
150
147
|
// emit SDK events
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { ITelemetryTracker } from '../../../trackers/types';
|
|
2
|
+
import { CONNECTION_ESTABLISHED, DISABLED, ENABLED, OCCUPANCY_PRI, OCCUPANCY_SEC, PAUSED, STREAMING_STATUS } from '../../../utils/constants';
|
|
3
|
+
import { StreamingEventType } from '../../submitters/types';
|
|
1
4
|
import { ControlType, PUSH_SUBSYSTEM_UP, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN } from '../constants';
|
|
2
5
|
import { IPushEventEmitter } from '../types';
|
|
3
6
|
|
|
4
7
|
const CONTROL_CHANNEL_REGEXS = [/control_pri$/, /control_sec$/];
|
|
8
|
+
const STREAMING_EVENT_TYPES: StreamingEventType[] = [OCCUPANCY_PRI, OCCUPANCY_SEC];
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Factory of notification keeper, which process OCCUPANCY and CONTROL notifications and emits the corresponding push events.
|
|
@@ -9,7 +13,7 @@ const CONTROL_CHANNEL_REGEXS = [/control_pri$/, /control_sec$/];
|
|
|
9
13
|
* @param pushEmitter emitter for events related to streaming support
|
|
10
14
|
*/
|
|
11
15
|
// @TODO update logic to handle OCCUPANCY for any region and rename according to new spec (e.g.: PUSH_SUBSYSTEM_UP --> PUSH_SUBSYSTEM_UP)
|
|
12
|
-
export function notificationKeeperFactory(pushEmitter: IPushEventEmitter) {
|
|
16
|
+
export function notificationKeeperFactory(pushEmitter: IPushEventEmitter, telemetryTracker: ITelemetryTracker) {
|
|
13
17
|
|
|
14
18
|
let channels = CONTROL_CHANNEL_REGEXS.map(regex => ({
|
|
15
19
|
regex,
|
|
@@ -30,6 +34,7 @@ export function notificationKeeperFactory(pushEmitter: IPushEventEmitter) {
|
|
|
30
34
|
|
|
31
35
|
return {
|
|
32
36
|
handleOpen() {
|
|
37
|
+
telemetryTracker.streamingEvent(CONNECTION_ESTABLISHED);
|
|
33
38
|
pushEmitter.emit(PUSH_SUBSYSTEM_UP);
|
|
34
39
|
},
|
|
35
40
|
|
|
@@ -41,6 +46,8 @@ export function notificationKeeperFactory(pushEmitter: IPushEventEmitter) {
|
|
|
41
46
|
for (let i = 0; i < channels.length; i++) {
|
|
42
47
|
const c = channels[i];
|
|
43
48
|
if (c.regex.test(channel)) {
|
|
49
|
+
telemetryTracker.streamingEvent(STREAMING_EVENT_TYPES[i], publishers);
|
|
50
|
+
|
|
44
51
|
if (timestamp > c.oTime) {
|
|
45
52
|
c.oTime = timestamp;
|
|
46
53
|
c.hasPublishers = publishers !== 0;
|
|
@@ -76,11 +83,14 @@ export function notificationKeeperFactory(pushEmitter: IPushEventEmitter) {
|
|
|
76
83
|
if (timestamp > c.cTime) {
|
|
77
84
|
c.cTime = timestamp;
|
|
78
85
|
if (controlType === ControlType.STREAMING_DISABLED) {
|
|
86
|
+
telemetryTracker.streamingEvent(STREAMING_STATUS, DISABLED);
|
|
79
87
|
pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
|
|
80
88
|
} else if (hasPublishers) {
|
|
81
89
|
if (controlType === ControlType.STREAMING_PAUSED && hasResumed) {
|
|
90
|
+
telemetryTracker.streamingEvent(STREAMING_STATUS, PAUSED);
|
|
82
91
|
pushEmitter.emit(PUSH_SUBSYSTEM_DOWN);
|
|
83
92
|
} else if (controlType === ControlType.STREAMING_RESUMED && !hasResumed) {
|
|
93
|
+
telemetryTracker.streamingEvent(STREAMING_STATUS, ENABLED);
|
|
84
94
|
pushEmitter.emit(PUSH_SUBSYSTEM_UP);
|
|
85
95
|
}
|
|
86
96
|
// nothing to do when hasPublishers === false:
|
|
@@ -6,18 +6,8 @@ import { ISseEventHandler } from '../SSEClient/types';
|
|
|
6
6
|
import { INotificationError, INotificationMessage } from './types';
|
|
7
7
|
import { ILogger } from '../../../logger/types';
|
|
8
8
|
import { STREAMING_PARSING_ERROR_FAILS, ERROR_STREAMING_SSE, STREAMING_PARSING_MESSAGE_FAILS, STREAMING_NEW_MESSAGE } from '../../../logger/constants';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (error.parsedData && error.parsedData.code) {
|
|
12
|
-
const code = error.parsedData.code;
|
|
13
|
-
// 401 errors due to invalid or expired token (e.g., if refresh token coudn't be executed)
|
|
14
|
-
if (40140 <= code && code <= 40149) return true;
|
|
15
|
-
// Others 4XX errors (e.g., bad request from the SDK)
|
|
16
|
-
if (40000 <= code && code <= 49999) return false;
|
|
17
|
-
}
|
|
18
|
-
// network errors or 5XX HTTP errors
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
9
|
+
import { ABLY_ERROR, NON_REQUESTED, SSE_CONNECTION_ERROR } from '../../../utils/constants';
|
|
10
|
+
import { ITelemetryTracker } from '../../../trackers/types';
|
|
21
11
|
|
|
22
12
|
/**
|
|
23
13
|
* Factory for SSEHandler, which processes SSEClient messages and emits the corresponding push events.
|
|
@@ -25,9 +15,26 @@ function isRetryableError(error: INotificationError) {
|
|
|
25
15
|
* @param log factory logger
|
|
26
16
|
* @param pushEmitter emitter for events related to streaming support
|
|
27
17
|
*/
|
|
28
|
-
export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter): ISseEventHandler {
|
|
18
|
+
export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter, telemetryTracker: ITelemetryTracker): ISseEventHandler {
|
|
29
19
|
|
|
30
|
-
const notificationKeeper = notificationKeeperFactory(pushEmitter);
|
|
20
|
+
const notificationKeeper = notificationKeeperFactory(pushEmitter, telemetryTracker);
|
|
21
|
+
|
|
22
|
+
function isRetryableError(error: INotificationError): boolean {
|
|
23
|
+
if (error.parsedData && error.parsedData.code) {
|
|
24
|
+
// Ably error
|
|
25
|
+
const code = error.parsedData.code;
|
|
26
|
+
telemetryTracker.streamingEvent(ABLY_ERROR, code);
|
|
27
|
+
|
|
28
|
+
// 401 errors due to invalid or expired token (e.g., if refresh token coudn't be executed)
|
|
29
|
+
if (40140 <= code && code <= 40149) return true;
|
|
30
|
+
// Others 4XX errors (e.g., bad request from the SDK)
|
|
31
|
+
if (40000 <= code && code <= 49999) return false;
|
|
32
|
+
} else {
|
|
33
|
+
// network errors or 5XX HTTP errors
|
|
34
|
+
telemetryTracker.streamingEvent(SSE_CONNECTION_ERROR, NON_REQUESTED);
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
31
38
|
|
|
32
39
|
return {
|
|
33
40
|
handleOpen() {
|
|
@@ -18,7 +18,8 @@ import { isInBitmap, parseBitmap, parseKeyList } from './mySegmentsV2utils';
|
|
|
18
18
|
import { ISet, _Set } from '../../utils/lang/sets';
|
|
19
19
|
import { Hash64, hash64 } from '../../utils/murmur3/murmur3_64';
|
|
20
20
|
import { IAuthTokenPushEnabled } from './AuthClient/types';
|
|
21
|
-
import {
|
|
21
|
+
import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
|
|
22
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* PushManager factory:
|
|
@@ -26,11 +27,11 @@ import { ISyncManagerFactoryParams } from '../types';
|
|
|
26
27
|
* - for client-side, with support for multiple clients, if key is provided in settings
|
|
27
28
|
*/
|
|
28
29
|
export function pushManagerFactory(
|
|
29
|
-
params:
|
|
30
|
+
params: ISdkFactoryContextSync,
|
|
30
31
|
pollingManager: IPollingManager,
|
|
31
32
|
): IPushManager | undefined {
|
|
32
33
|
|
|
33
|
-
const { settings, storage, splitApi, readiness, platform } = params;
|
|
34
|
+
const { settings, storage, splitApi, readiness, platform, telemetryTracker } = params;
|
|
34
35
|
|
|
35
36
|
// `userKey` is the matching key of main client in client-side SDK.
|
|
36
37
|
// It can be used to check if running on client-side or server-side SDK.
|
|
@@ -49,7 +50,7 @@ export function pushManagerFactory(
|
|
|
49
50
|
|
|
50
51
|
// init feedback loop
|
|
51
52
|
const pushEmitter = new platform.EventEmitter() as IPushEventEmitter;
|
|
52
|
-
const sseHandler = SSEHandlerFactory(log, pushEmitter);
|
|
53
|
+
const sseHandler = SSEHandlerFactory(log, pushEmitter, telemetryTracker);
|
|
53
54
|
sseClient.setEventHandler(sseHandler);
|
|
54
55
|
|
|
55
56
|
// init workers
|
|
@@ -101,6 +102,8 @@ export function pushManagerFactory(
|
|
|
101
102
|
if (disconnected) return;
|
|
102
103
|
sseClient.open(authData);
|
|
103
104
|
}, connDelay * 1000);
|
|
105
|
+
|
|
106
|
+
telemetryTracker.streamingEvent(TOKEN_REFRESH, decodedToken.exp);
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
function connectPush() {
|
|
@@ -137,6 +140,7 @@ export function pushManagerFactory(
|
|
|
137
140
|
|
|
138
141
|
// Handle 4XX HTTP errors: 401 (invalid API Key) or 400 (using incorrect API Key, i.e., client-side API Key on server-side)
|
|
139
142
|
if (error.statusCode >= 400 && error.statusCode < 500) {
|
|
143
|
+
telemetryTracker.streamingEvent(AUTH_REJECTION);
|
|
140
144
|
pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
|
|
141
145
|
return;
|
|
142
146
|
}
|
|
@@ -179,7 +183,7 @@ export function pushManagerFactory(
|
|
|
179
183
|
stopWorkers();
|
|
180
184
|
});
|
|
181
185
|
|
|
182
|
-
/**
|
|
186
|
+
/** Fallback to polling without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */
|
|
183
187
|
|
|
184
188
|
pushEmitter.on(PUSH_NONRETRYABLE_ERROR, function handleNonRetryableError() {
|
|
185
189
|
disabled = true;
|
|
@@ -188,7 +192,7 @@ export function pushManagerFactory(
|
|
|
188
192
|
pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already
|
|
189
193
|
});
|
|
190
194
|
|
|
191
|
-
/**
|
|
195
|
+
/** Fallback to polling with retry due to recoverable SSE and Authentication errors */
|
|
192
196
|
|
|
193
197
|
pushEmitter.on(PUSH_RETRYABLE_ERROR, function handleRetryableError() { // HTTP or network error in SSE connection
|
|
194
198
|
// SSE connection is closed to avoid repeated errors due to retries
|
|
@@ -316,7 +320,7 @@ export function pushManagerFactory(
|
|
|
316
320
|
},
|
|
317
321
|
|
|
318
322
|
// true/false if start or stop was called last respectively
|
|
319
|
-
isRunning(){
|
|
323
|
+
isRunning() {
|
|
320
324
|
return disconnected === false;
|
|
321
325
|
},
|
|
322
326
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { submitterFactory, firstPushWindowDecorator } from './submitter';
|
|
2
|
+
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
|
|
3
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
4
|
+
|
|
5
|
+
const DATA_NAME = 'events';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Submitter that periodically posts tracked events
|
|
9
|
+
*/
|
|
10
|
+
export function eventsSubmitterFactory(params: ISdkFactoryContextSync) {
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
settings: { log, scheduler: { eventsPushRate }, startup: { eventsFirstPushWindow } },
|
|
14
|
+
splitApi: { postEventsBulk },
|
|
15
|
+
storage: { events },
|
|
16
|
+
} = params;
|
|
17
|
+
|
|
18
|
+
// don't retry events.
|
|
19
|
+
let submitter = submitterFactory(log, postEventsBulk, events, eventsPushRate, DATA_NAME);
|
|
20
|
+
|
|
21
|
+
// Set a timer for the first push window of events.
|
|
22
|
+
if (eventsFirstPushWindow > 0) submitter = firstPushWindowDecorator(submitter, eventsFirstPushWindow);
|
|
23
|
+
|
|
24
|
+
// register events submitter to be executed when events cache is full
|
|
25
|
+
events.setOnFullQueueCb(() => {
|
|
26
|
+
if (submitter.isRunning()) {
|
|
27
|
+
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
|
|
28
|
+
submitter.execute();
|
|
29
|
+
}
|
|
30
|
+
// If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
|
|
31
|
+
// Data will be sent when submitter is resumed.
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return submitter;
|
|
35
|
+
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { IImpressionCountsCacheSync } from '../../storages/types';
|
|
4
|
-
import { submitterSyncTaskFactory } from './submitterSyncTask';
|
|
1
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
2
|
+
import { submitterFactory } from './submitter';
|
|
5
3
|
import { ImpressionCountsPayload } from './types';
|
|
6
|
-
import { ILogger } from '../../logger/types';
|
|
7
4
|
|
|
8
5
|
/**
|
|
9
6
|
* Converts `impressionCounts` data from cache into request payload.
|
|
@@ -32,15 +29,18 @@ export function fromImpressionCountsCollector(impressionsCount: Record<string, n
|
|
|
32
29
|
const IMPRESSIONS_COUNT_RATE = 1800000; // 30 minutes
|
|
33
30
|
|
|
34
31
|
/**
|
|
35
|
-
*
|
|
32
|
+
* Submitter that periodically posts impression counts
|
|
36
33
|
*/
|
|
37
|
-
export function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
export function impressionCountsSubmitterFactory(params: ISdkFactoryContextSync) {
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
settings: { log },
|
|
38
|
+
splitApi: { postTestImpressionsCount },
|
|
39
|
+
storage: { impressionCounts }
|
|
40
|
+
} = params;
|
|
41
|
+
|
|
42
|
+
if (impressionCounts) {
|
|
43
|
+
// retry impressions counts only once.
|
|
44
|
+
return submitterFactory(log, postTestImpressionsCount, impressionCounts, IMPRESSIONS_COUNT_RATE, 'impression counts', fromImpressionCountsCollector, 1);
|
|
45
|
+
}
|
|
46
46
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { groupBy, forOwn } from '../../utils/lang';
|
|
2
|
-
import { ISyncTask, ITimeTracker } from '../types';
|
|
3
|
-
import { IPostTestImpressionsBulk } from '../../services/types';
|
|
4
|
-
import { IImpressionsCacheSync } from '../../storages/types';
|
|
5
2
|
import { ImpressionDTO } from '../../types';
|
|
6
|
-
import {
|
|
3
|
+
import { submitterFactory } from './submitter';
|
|
7
4
|
import { ImpressionsPayload } from './types';
|
|
8
|
-
import { ILogger } from '../../logger/types';
|
|
9
5
|
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
|
|
6
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
10
7
|
|
|
11
8
|
const DATA_NAME = 'impressions';
|
|
12
9
|
|
|
@@ -41,22 +38,21 @@ export function fromImpressionsCollector(sendLabels: boolean, data: ImpressionDT
|
|
|
41
38
|
}
|
|
42
39
|
|
|
43
40
|
/**
|
|
44
|
-
*
|
|
41
|
+
* Submitter that periodically posts impressions data
|
|
45
42
|
*/
|
|
46
|
-
export function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
): ISyncTask {
|
|
43
|
+
export function impressionsSubmitterFactory(params: ISdkFactoryContextSync) {
|
|
44
|
+
|
|
45
|
+
const {
|
|
46
|
+
settings: { log, scheduler: { impressionsRefreshRate }, core: { labelsEnabled } },
|
|
47
|
+
splitApi: { postTestImpressionsBulk },
|
|
48
|
+
storage: { impressions }
|
|
49
|
+
} = params;
|
|
54
50
|
|
|
55
51
|
// retry impressions only once.
|
|
56
|
-
const syncTask =
|
|
52
|
+
const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, DATA_NAME, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);
|
|
57
53
|
|
|
58
54
|
// register impressions submitter to be executed when impressions cache is full
|
|
59
|
-
|
|
55
|
+
impressions.setOnFullQueueCb(() => {
|
|
60
56
|
if (syncTask.isRunning()) {
|
|
61
57
|
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
|
|
62
58
|
syncTask.execute();
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { syncTaskFactory } from '../syncTask';
|
|
2
|
-
import { ISyncTask
|
|
2
|
+
import { ISyncTask } from '../types';
|
|
3
3
|
import { IRecorderCacheProducerSync } from '../../storages/types';
|
|
4
4
|
import { ILogger } from '../../logger/types';
|
|
5
5
|
import { SUBMITTERS_PUSH, SUBMITTERS_PUSH_FAILS, SUBMITTERS_PUSH_RETRY } from '../../logger/constants';
|
|
6
6
|
import { IResponse } from '../../services/types';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Base function to create
|
|
9
|
+
* Base function to create submitters, such as ImpressionsSubmitter and EventsSubmitter
|
|
10
10
|
*/
|
|
11
|
-
export function
|
|
11
|
+
export function submitterFactory<TState>(
|
|
12
12
|
log: ILogger,
|
|
13
13
|
postClient: (body: string) => Promise<IResponse>,
|
|
14
14
|
sourceCache: IRecorderCacheProducerSync<TState>,
|
|
15
15
|
postRate: number,
|
|
16
16
|
dataName: string,
|
|
17
|
-
latencyTracker?: ITimeTracker,
|
|
18
17
|
fromCacheToPayload?: (cacheData: TState) => any,
|
|
19
18
|
maxRetries: number = 0,
|
|
20
|
-
debugLogs?: boolean
|
|
19
|
+
debugLogs?: boolean // true for telemetry submitters
|
|
21
20
|
): ISyncTask<[], void> {
|
|
22
21
|
|
|
23
22
|
let retries = 0;
|
|
@@ -26,33 +25,52 @@ export function submitterSyncTaskFactory<TState extends { length?: number }>(
|
|
|
26
25
|
if (sourceCache.isEmpty()) return Promise.resolve();
|
|
27
26
|
|
|
28
27
|
const data = sourceCache.state();
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
log[debugLogs ? 'debug' : 'info'](SUBMITTERS_PUSH, [
|
|
32
|
-
const latencyTrackerStop = latencyTracker && latencyTracker.start();
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
const dataCountMessage = typeof data.length === 'number' ? `${data.length} ${dataName}` : dataName;
|
|
30
|
+
log[debugLogs ? 'debug' : 'info'](SUBMITTERS_PUSH, [dataCountMessage]);
|
|
33
31
|
|
|
34
32
|
const jsonPayload = JSON.stringify(fromCacheToPayload ? fromCacheToPayload(data) : data);
|
|
35
33
|
if (!maxRetries) sourceCache.clear();
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
return postClient(jsonPayload).then(() => {
|
|
38
36
|
retries = 0;
|
|
39
37
|
sourceCache.clear(); // we clear the queue if request successes.
|
|
40
38
|
}).catch(err => {
|
|
41
39
|
if (!maxRetries) {
|
|
42
|
-
log
|
|
40
|
+
log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
|
|
43
41
|
} else if (retries === maxRetries) {
|
|
44
42
|
retries = 0;
|
|
45
43
|
sourceCache.clear(); // we clear the queue if request fails after retries.
|
|
46
|
-
log
|
|
44
|
+
log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
|
|
47
45
|
} else {
|
|
48
46
|
retries++;
|
|
49
|
-
log
|
|
47
|
+
log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_RETRY, [dataCountMessage, err]);
|
|
50
48
|
}
|
|
51
49
|
});
|
|
52
|
-
|
|
53
|
-
// if latencyTracker provided, attach stop callback to postEventsPromise
|
|
54
|
-
return latencyTrackerStop ? postPromise.then(latencyTrackerStop).catch(latencyTrackerStop) : postPromise;
|
|
55
50
|
}
|
|
56
51
|
|
|
57
52
|
return syncTaskFactory(log, postData, postRate, dataName + ' submitter');
|
|
58
53
|
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Decorates a provided submitter with a first execution window
|
|
57
|
+
*/
|
|
58
|
+
export function firstPushWindowDecorator(submitter: ISyncTask, firstPushWindow: number) {
|
|
59
|
+
let running = false;
|
|
60
|
+
let stopEventPublisherTimeout: ReturnType<typeof setTimeout>;
|
|
61
|
+
const originalStart = submitter.start;
|
|
62
|
+
submitter.start = () => {
|
|
63
|
+
running = true;
|
|
64
|
+
stopEventPublisherTimeout = setTimeout(originalStart, firstPushWindow);
|
|
65
|
+
};
|
|
66
|
+
const originalStop = submitter.stop;
|
|
67
|
+
submitter.stop = () => {
|
|
68
|
+
running = false;
|
|
69
|
+
clearTimeout(stopEventPublisherTimeout);
|
|
70
|
+
originalStop();
|
|
71
|
+
};
|
|
72
|
+
submitter.isRunning = () => {
|
|
73
|
+
return running;
|
|
74
|
+
};
|
|
75
|
+
return submitter;
|
|
76
|
+
}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { syncTaskComposite } from '../syncTaskComposite';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { eventsSubmitterFactory } from './eventsSubmitter';
|
|
3
|
+
import { impressionsSubmitterFactory } from './impressionsSubmitter';
|
|
4
|
+
import { impressionCountsSubmitterFactory } from './impressionCountsSubmitter';
|
|
5
|
+
import { telemetrySubmitterFactory } from './telemetrySubmitter';
|
|
6
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
6
7
|
|
|
7
|
-
export function submitterManagerFactory(params:
|
|
8
|
+
export function submitterManagerFactory(params: ISdkFactoryContextSync) {
|
|
8
9
|
|
|
9
|
-
const { settings, storage, splitApi } = params;
|
|
10
|
-
const log = settings.log;
|
|
11
10
|
const submitters = [
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// @TODO add telemetry submitter
|
|
11
|
+
impressionsSubmitterFactory(params),
|
|
12
|
+
eventsSubmitterFactory(params)
|
|
15
13
|
];
|
|
16
|
-
|
|
14
|
+
|
|
15
|
+
const impressionCountsSubmitter = impressionCountsSubmitterFactory(params);
|
|
16
|
+
if (impressionCountsSubmitter) submitters.push(impressionCountsSubmitter);
|
|
17
|
+
const telemetrySubmitter = telemetrySubmitterFactory(params);
|
|
18
|
+
if (telemetrySubmitter) submitters.push(telemetrySubmitter);
|
|
19
|
+
|
|
17
20
|
return syncTaskComposite(submitters);
|
|
18
21
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { ISegmentsCacheSync, ISplitsCacheSync, ITelemetryCacheSync } from '../../storages/types';
|
|
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';
|
|
5
|
+
import { SDK_READY, SDK_READY_FROM_CACHE } from '../../readiness/constants';
|
|
6
|
+
import { ISettings } from '../../types';
|
|
7
|
+
import { base } from '../../utils/settingsValidation';
|
|
8
|
+
import { usedKeysMap } from '../../utils/inputValidation/apiKey';
|
|
9
|
+
import { timer } from '../../utils/timeTracker/timer';
|
|
10
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Converts data from telemetry cache into /metrics/usage request payload.
|
|
14
|
+
*/
|
|
15
|
+
export function telemetryCacheStatsAdapter(telemetry: ITelemetryCacheSync, splits: ISplitsCacheSync, segments: ISegmentsCacheSync) {
|
|
16
|
+
return {
|
|
17
|
+
isEmpty() { return false; }, // There is always data in telemetry cache
|
|
18
|
+
clear() { }, // No-op
|
|
19
|
+
|
|
20
|
+
// @TODO consider moving inside telemetry cache for code size reduction
|
|
21
|
+
state(): TelemetryUsageStatsPayload {
|
|
22
|
+
return {
|
|
23
|
+
lS: telemetry.getLastSynchronization(),
|
|
24
|
+
mL: telemetry.popLatencies(),
|
|
25
|
+
mE: telemetry.popExceptions(),
|
|
26
|
+
hE: telemetry.popHttpErrors(),
|
|
27
|
+
hL: telemetry.popHttpLatencies(),
|
|
28
|
+
tR: telemetry.popTokenRefreshes(),
|
|
29
|
+
aR: telemetry.popAuthRejections(),
|
|
30
|
+
iQ: telemetry.getImpressionStats(QUEUED),
|
|
31
|
+
iDe: telemetry.getImpressionStats(DEDUPED),
|
|
32
|
+
iDr: telemetry.getImpressionStats(DROPPED),
|
|
33
|
+
spC: splits.getSplitNames().length,
|
|
34
|
+
seC: segments.getRegisteredSegments().length,
|
|
35
|
+
skC: segments.getKeysCount(),
|
|
36
|
+
sL: telemetry.getSessionLength(),
|
|
37
|
+
eQ: telemetry.getEventStats(QUEUED),
|
|
38
|
+
eD: telemetry.getEventStats(DROPPED),
|
|
39
|
+
sE: telemetry.popStreamingEvents(),
|
|
40
|
+
t: telemetry.popTags(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const OPERATION_MODE_MAP = {
|
|
47
|
+
[STANDALONE_MODE]: STANDALONE_ENUM,
|
|
48
|
+
[CONSUMER_MODE]: CONSUMER_ENUM,
|
|
49
|
+
[CONSUMER_PARTIAL_MODE]: CONSUMER_PARTIAL_ENUM
|
|
50
|
+
} as Record<ISettings['mode'], (0 | 1 | 2)>;
|
|
51
|
+
|
|
52
|
+
const IMPRESSIONS_MODE_MAP = {
|
|
53
|
+
[OPTIMIZED]: OPTIMIZED_ENUM,
|
|
54
|
+
[DEBUG]: DEBUG_ENUM
|
|
55
|
+
} as Record<ISettings['sync']['impressionsMode'], (0 | 1)>;
|
|
56
|
+
|
|
57
|
+
function getActiveFactories() {
|
|
58
|
+
return Object.keys(usedKeysMap).length;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getRedundantActiveFactories() {
|
|
62
|
+
return Object.keys(usedKeysMap).reduce((acum, apiKey) => {
|
|
63
|
+
return acum + usedKeysMap[apiKey] - 1;
|
|
64
|
+
}, 0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Converts data from telemetry cache and settings into /metrics/config request payload.
|
|
69
|
+
*/
|
|
70
|
+
export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, settings: ISettings) {
|
|
71
|
+
return {
|
|
72
|
+
isEmpty() { return false; },
|
|
73
|
+
clear() { },
|
|
74
|
+
|
|
75
|
+
state(): TelemetryConfigStatsPayload {
|
|
76
|
+
const { urls, scheduler } = settings;
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
oM: OPERATION_MODE_MAP[settings.mode], // @ts-ignore lower case of storage type
|
|
80
|
+
st: settings.storage.type.toLowerCase(),
|
|
81
|
+
sE: settings.streamingEnabled,
|
|
82
|
+
rR: {
|
|
83
|
+
sp: scheduler.featuresRefreshRate,
|
|
84
|
+
se: scheduler.segmentsRefreshRate,
|
|
85
|
+
im: scheduler.impressionsRefreshRate,
|
|
86
|
+
ev: scheduler.eventsPushRate,
|
|
87
|
+
te: scheduler.telemetryRefreshRate,
|
|
88
|
+
}, // refreshRates
|
|
89
|
+
uO: {
|
|
90
|
+
s: urls.sdk !== base.urls.sdk,
|
|
91
|
+
e: urls.events !== base.urls.events,
|
|
92
|
+
a: urls.auth !== base.urls.auth,
|
|
93
|
+
st: urls.streaming !== base.urls.streaming,
|
|
94
|
+
t: urls.telemetry !== base.urls.telemetry,
|
|
95
|
+
}, // urlOverrides
|
|
96
|
+
iQ: scheduler.impressionsQueueSize,
|
|
97
|
+
eQ: scheduler.eventsQueueSize,
|
|
98
|
+
iM: IMPRESSIONS_MODE_MAP[settings.sync.impressionsMode],
|
|
99
|
+
iL: settings.impressionListener ? true : false,
|
|
100
|
+
hP: false, // @TODO proxy not supported
|
|
101
|
+
aF: getActiveFactories(),
|
|
102
|
+
rF: getRedundantActiveFactories(),
|
|
103
|
+
tR: telemetry.getTimeUntilReady() as number,
|
|
104
|
+
tC: telemetry.getTimeUntilReadyFromCache(),
|
|
105
|
+
nR: telemetry.getNonReadyUsage(),
|
|
106
|
+
t: telemetry.popTags(),
|
|
107
|
+
i: settings.integrations && settings.integrations.map(int => int.type),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Submitter that periodically posts telemetry data
|
|
115
|
+
*/
|
|
116
|
+
export function telemetrySubmitterFactory(params: ISdkFactoryContextSync) {
|
|
117
|
+
const { storage: { splits, segments, telemetry } } = params;
|
|
118
|
+
if (!telemetry) return; // No submitter created if telemetry cache is not defined
|
|
119
|
+
|
|
120
|
+
const { settings, settings: { log, scheduler: { telemetryRefreshRate } }, splitApi, platform: { now }, readiness } = params;
|
|
121
|
+
const startTime = timer(now || Date.now);
|
|
122
|
+
|
|
123
|
+
const submitter = firstPushWindowDecorator(
|
|
124
|
+
submitterFactory(log, splitApi.postMetricsUsage, telemetryCacheStatsAdapter(telemetry, splits, segments), telemetryRefreshRate, 'telemetry stats', undefined, 0, true),
|
|
125
|
+
telemetryRefreshRate
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
readiness.gate.once(SDK_READY_FROM_CACHE, () => {
|
|
129
|
+
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
readiness.gate.once(SDK_READY, () => {
|
|
133
|
+
telemetry.recordTimeUntilReady(startTime());
|
|
134
|
+
|
|
135
|
+
// Post config data when the SDK is ready and if the telemetry submitter was started
|
|
136
|
+
if (submitter.isRunning()) {
|
|
137
|
+
const postMetricsConfigTask = submitterFactory(log, splitApi.postMetricsConfig, telemetryCacheConfigAdapter(telemetry, settings), 0, 'telemetry config', undefined, 0, true);
|
|
138
|
+
postMetricsConfigTask.execute();
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
return submitter;
|
|
143
|
+
}
|