@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
package/src/sdkClient/client.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { getMatching, getBucketing } from '../utils/key';
|
|
|
4
4
|
import { validateSplitExistance } from '../utils/inputValidation/splitExistance';
|
|
5
5
|
import { validateTrafficTypeExistance } from '../utils/inputValidation/trafficTypeExistance';
|
|
6
6
|
import { SDK_NOT_READY } from '../utils/labels';
|
|
7
|
-
import { CONTROL } from '../utils/constants';
|
|
7
|
+
import { CONTROL, TREATMENT, TREATMENTS, TREATMENT_WITH_CONFIG, TREATMENTS_WITH_CONFIG, TRACK } from '../utils/constants';
|
|
8
8
|
import { IEvaluationResult } from '../evaluator/types';
|
|
9
9
|
import { SplitIO, ImpressionDTO } from '../types';
|
|
10
10
|
import { IMPRESSION, IMPRESSION_QUEUEING } from '../logger/constants';
|
|
@@ -13,16 +13,19 @@ import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
|
13
13
|
/**
|
|
14
14
|
* Creator of base client with getTreatments and track methods.
|
|
15
15
|
*/
|
|
16
|
-
// @TODO missing time tracking to collect telemetry
|
|
17
16
|
export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | SplitIO.IAsyncClient {
|
|
18
|
-
const { sdkReadinessManager: { readinessManager }, storage, settings, impressionsTracker, eventTracker } = params;
|
|
17
|
+
const { sdkReadinessManager: { readinessManager }, storage, settings, impressionsTracker, eventTracker, telemetryTracker } = params;
|
|
19
18
|
const { log, mode } = settings;
|
|
20
19
|
|
|
21
20
|
function getTreatment(key: SplitIO.SplitKey, splitName: string, attributes: SplitIO.Attributes | undefined, withConfig = false) {
|
|
21
|
+
const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENT_WITH_CONFIG : TREATMENT);
|
|
22
|
+
|
|
22
23
|
const wrapUp = (evaluationResult: IEvaluationResult) => {
|
|
23
24
|
const queue: ImpressionDTO[] = [];
|
|
24
25
|
const treatment = processEvaluation(evaluationResult, splitName, key, attributes, withConfig, `getTreatment${withConfig ? 'withConfig' : ''}`, queue);
|
|
25
26
|
impressionsTracker.track(queue, attributes);
|
|
27
|
+
|
|
28
|
+
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
26
29
|
return treatment;
|
|
27
30
|
};
|
|
28
31
|
|
|
@@ -36,6 +39,8 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
function getTreatments(key: SplitIO.SplitKey, splitNames: string[], attributes: SplitIO.Attributes | undefined, withConfig = false) {
|
|
42
|
+
const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENTS_WITH_CONFIG : TREATMENTS);
|
|
43
|
+
|
|
39
44
|
const wrapUp = (evaluationResults: Record<string, IEvaluationResult>) => {
|
|
40
45
|
const queue: ImpressionDTO[] = [];
|
|
41
46
|
const treatments: Record<string, SplitIO.Treatment | SplitIO.TreatmentWithConfig> = {};
|
|
@@ -43,6 +48,8 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
43
48
|
treatments[splitName] = processEvaluation(evaluationResults[splitName], splitName, key, attributes, withConfig, `getTreatments${withConfig ? 'withConfig' : ''}`, queue);
|
|
44
49
|
});
|
|
45
50
|
impressionsTracker.track(queue, attributes);
|
|
51
|
+
|
|
52
|
+
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
46
53
|
return treatments;
|
|
47
54
|
};
|
|
48
55
|
|
|
@@ -101,6 +108,8 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
101
108
|
}
|
|
102
109
|
|
|
103
110
|
function track(key: SplitIO.SplitKey, trafficTypeName: string, eventTypeId: string, value?: number, properties?: SplitIO.Properties, size = 1024) {
|
|
111
|
+
const stopTelemetryTracker = telemetryTracker.trackEval(TRACK);
|
|
112
|
+
|
|
104
113
|
const matchingKey = getMatching(key);
|
|
105
114
|
const timestamp = Date.now();
|
|
106
115
|
const eventData: SplitIO.EventData = {
|
|
@@ -115,7 +124,17 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
115
124
|
// This may be async but we only warn, we don't actually care if it is valid or not in terms of queueing the event.
|
|
116
125
|
validateTrafficTypeExistance(log, readinessManager, storage.splits, mode, trafficTypeName, 'track');
|
|
117
126
|
|
|
118
|
-
|
|
127
|
+
const result = eventTracker.track(eventData, size);
|
|
128
|
+
|
|
129
|
+
if (thenable(result)) {
|
|
130
|
+
return result.then((result) => {
|
|
131
|
+
stopTelemetryTracker();
|
|
132
|
+
return result;
|
|
133
|
+
});
|
|
134
|
+
} else {
|
|
135
|
+
stopTelemetryTracker();
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
119
138
|
}
|
|
120
139
|
|
|
121
140
|
return {
|
|
@@ -9,7 +9,7 @@ import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
|
9
9
|
* Creates an Sdk client, i.e., a base client with status and destroy interface
|
|
10
10
|
*/
|
|
11
11
|
export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: boolean): SplitIO.IClient | SplitIO.IAsyncClient {
|
|
12
|
-
const { sdkReadinessManager, syncManager, storage, signalListener, settings } = params;
|
|
12
|
+
const { sdkReadinessManager, syncManager, storage, signalListener, settings, telemetryTracker } = params;
|
|
13
13
|
|
|
14
14
|
return objectAssign(
|
|
15
15
|
// Proto-linkage of the readiness Event Emitter
|
|
@@ -25,6 +25,9 @@ export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: bo
|
|
|
25
25
|
// Sdk destroy
|
|
26
26
|
{
|
|
27
27
|
destroy() {
|
|
28
|
+
// record stat before flushing data
|
|
29
|
+
if (!isSharedClient) telemetryTracker.sessionLength();
|
|
30
|
+
|
|
28
31
|
// Stop background jobs
|
|
29
32
|
syncManager && syncManager.stop();
|
|
30
33
|
const flush = syncManager ? syncManager.flush() : Promise.resolve();
|
package/src/sdkFactory/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ISdkFactoryParams } from './types';
|
|
1
|
+
import { ISdkFactoryContext, ISdkFactoryContextSync, ISdkFactoryParams } from './types';
|
|
2
2
|
import { sdkReadinessManagerFactory } from '../readiness/sdkReadinessManager';
|
|
3
3
|
import { impressionsTrackerFactory } from '../trackers/impressionsTracker';
|
|
4
4
|
import { eventTrackerFactory } from '../trackers/eventTracker';
|
|
5
|
-
import {
|
|
5
|
+
import { telemetryTrackerFactory } from '../trackers/telemetryTracker';
|
|
6
|
+
import { IStorageFactoryParams } from '../storages/types';
|
|
6
7
|
import { SplitIO } from '../types';
|
|
7
|
-
import { ISplitApi } from '../services/types';
|
|
8
8
|
import { getMatching } from '../utils/key';
|
|
9
9
|
import { shouldBeOptimized } from '../trackers/impressionObserver/utils';
|
|
10
10
|
import { validateAndTrackApiKey } from '../utils/inputValidation/apiKey';
|
|
@@ -24,13 +24,14 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
24
24
|
integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory } = params;
|
|
25
25
|
const log = settings.log;
|
|
26
26
|
|
|
27
|
-
// @TODO handle non-recoverable errors
|
|
27
|
+
// @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid API Key, etc.
|
|
28
|
+
// On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
|
|
29
|
+
|
|
28
30
|
// We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
|
|
29
31
|
validateAndTrackApiKey(log, settings.core.authorizationKey);
|
|
30
32
|
|
|
31
|
-
// @TODO handle non-recoverable error, such as, `fetch` api not available, invalid API Key, etc.
|
|
32
33
|
const sdkReadinessManager = sdkReadinessManagerFactory(log, platform.EventEmitter, settings.startup.readyTimeout);
|
|
33
|
-
const
|
|
34
|
+
const readiness = sdkReadinessManager.readinessManager;
|
|
34
35
|
|
|
35
36
|
// @TODO consider passing the settings object, so that each storage access only what it needs
|
|
36
37
|
const storageFactoryParams: IStorageFactoryParams = {
|
|
@@ -49,8 +50,8 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
49
50
|
// or partial consumer mode, where it only has submitters, and therefore it doesn't emit readiness events.
|
|
50
51
|
onReadyCb: (error) => {
|
|
51
52
|
if (error) return; // Don't emit SDK_READY if storage failed to connect. Error message is logged by wrapperAdapter
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
54
|
+
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
54
55
|
},
|
|
55
56
|
metadata: metadataBuilder(settings),
|
|
56
57
|
log
|
|
@@ -59,29 +60,26 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
59
60
|
const storage = storageFactory(storageFactoryParams);
|
|
60
61
|
// @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
|
|
61
62
|
|
|
62
|
-
// splitApi is used by SyncManager and Browser signal listener
|
|
63
|
-
const splitApi = splitApiFactory && splitApiFactory(settings, platform);
|
|
64
|
-
|
|
65
|
-
const syncManager = syncManagerFactory && syncManagerFactory({
|
|
66
|
-
settings,
|
|
67
|
-
splitApi: splitApi as ISplitApi,
|
|
68
|
-
storage: storage as IStorageSync,
|
|
69
|
-
readiness: sdkReadinessManager.readinessManager,
|
|
70
|
-
platform
|
|
71
|
-
});
|
|
72
|
-
|
|
73
63
|
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage });
|
|
74
64
|
|
|
75
65
|
// trackers
|
|
76
66
|
const observer = impressionsObserverFactory && impressionsObserverFactory();
|
|
77
|
-
const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, integrationsManager, observer, storage.impressionCounts);
|
|
78
|
-
const eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager);
|
|
67
|
+
const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, integrationsManager, observer, storage.impressionCounts, storage.telemetry);
|
|
68
|
+
const eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager, storage.telemetry);
|
|
69
|
+
const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
|
|
70
|
+
|
|
71
|
+
// splitApi is used by SyncManager and Browser signal listener
|
|
72
|
+
const splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
73
|
+
|
|
74
|
+
const ctx: ISdkFactoryContext = { splitApi, eventTracker, impressionsTracker, telemetryTracker, sdkReadinessManager, readiness, settings, storage, platform };
|
|
75
|
+
|
|
76
|
+
const syncManager = syncManagerFactory && syncManagerFactory(ctx as ISdkFactoryContextSync);
|
|
77
|
+
ctx.syncManager = syncManager;
|
|
79
78
|
|
|
80
|
-
// signal listener
|
|
81
79
|
const signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
|
|
80
|
+
ctx.signalListener = signalListener;
|
|
82
81
|
|
|
83
|
-
//
|
|
84
|
-
const ctx = { eventTracker, impressionsTracker, sdkReadinessManager, settings, storage, syncManager, signalListener };
|
|
82
|
+
// SDK client and manager
|
|
85
83
|
const clientMethod = sdkClientMethodFactory(ctx);
|
|
86
84
|
const managerInstance = sdkManagerFactory(log, storage.splits, sdkReadinessManager);
|
|
87
85
|
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -1,33 +1,50 @@
|
|
|
1
1
|
import { IIntegrationManager, IIntegrationFactoryParams } from '../integrations/types';
|
|
2
2
|
import { ISignalListener } from '../listeners/types';
|
|
3
3
|
import { ILogger } from '../logger/types';
|
|
4
|
-
import { ISdkReadinessManager } from '../readiness/types';
|
|
4
|
+
import { IReadinessManager, ISdkReadinessManager } from '../readiness/types';
|
|
5
5
|
import { IFetch, ISplitApi, IEventSourceConstructor } from '../services/types';
|
|
6
6
|
import { IStorageAsync, IStorageSync, ISplitsCacheSync, ISplitsCacheAsync, IStorageFactoryParams } from '../storages/types';
|
|
7
|
-
import { ISyncManager
|
|
7
|
+
import { ISyncManager } from '../sync/types';
|
|
8
8
|
import { IImpressionObserver } from '../trackers/impressionObserver/types';
|
|
9
|
-
import { IImpressionsTracker, IEventTracker } from '../trackers/types';
|
|
9
|
+
import { IImpressionsTracker, IEventTracker, ITelemetryTracker } from '../trackers/types';
|
|
10
10
|
import { SplitIO, ISettings, IEventEmitter } from '../types';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Environment related dependencies.
|
|
14
|
+
* These getters are called a fixed number of times per factory instantiation.
|
|
15
|
+
*/
|
|
16
|
+
export interface IPlatform {
|
|
17
|
+
getOptions?: () => object
|
|
18
|
+
getFetch?: () => (IFetch | undefined)
|
|
19
|
+
getEventSource?: () => (IEventSourceConstructor | undefined)
|
|
20
|
+
EventEmitter: new () => IEventEmitter,
|
|
21
|
+
now?: () => number
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
export interface ISdkFactoryContext {
|
|
13
|
-
|
|
25
|
+
platform: IPlatform,
|
|
14
26
|
sdkReadinessManager: ISdkReadinessManager,
|
|
27
|
+
readiness: IReadinessManager,
|
|
15
28
|
settings: ISettings
|
|
16
29
|
impressionsTracker: IImpressionsTracker,
|
|
17
30
|
eventTracker: IEventTracker,
|
|
31
|
+
telemetryTracker: ITelemetryTracker,
|
|
32
|
+
storage: IStorageSync | IStorageAsync,
|
|
18
33
|
signalListener?: ISignalListener
|
|
34
|
+
splitApi?: ISplitApi
|
|
19
35
|
syncManager?: ISyncManager,
|
|
20
36
|
}
|
|
21
37
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
export interface ISdkFactoryContextSync extends ISdkFactoryContext {
|
|
39
|
+
storage: IStorageSync,
|
|
40
|
+
splitApi: ISplitApi
|
|
41
|
+
syncManager: ISyncManager,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ISdkFactoryContextAsync extends ISdkFactoryContext {
|
|
45
|
+
storage: IStorageAsync,
|
|
46
|
+
splitApi: undefined,
|
|
47
|
+
syncManager: undefined
|
|
31
48
|
}
|
|
32
49
|
|
|
33
50
|
/**
|
|
@@ -47,12 +64,12 @@ export interface ISdkFactoryParams {
|
|
|
47
64
|
|
|
48
65
|
// Factory of Split Api (HTTP Client Service).
|
|
49
66
|
// It is not required when providing an asynchronous storage or offline SyncManager
|
|
50
|
-
splitApiFactory?: (settings: ISettings, platform: IPlatform) => ISplitApi,
|
|
67
|
+
splitApiFactory?: (settings: ISettings, platform: IPlatform, telemetryTracker: ITelemetryTracker) => ISplitApi,
|
|
51
68
|
|
|
52
69
|
// SyncManager factory.
|
|
53
70
|
// Not required when providing an asynchronous storage (consumer mode), but required in standalone mode to avoid SDK timeout.
|
|
54
71
|
// It can create an offline or online sync manager, with or without streaming support.
|
|
55
|
-
syncManagerFactory?: (params:
|
|
72
|
+
syncManagerFactory?: (params: ISdkFactoryContextSync) => ISyncManager,
|
|
56
73
|
|
|
57
74
|
// Sdk manager factory
|
|
58
75
|
sdkManagerFactory: (
|
package/src/services/splitApi.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { ISettings } from '../types';
|
|
|
3
3
|
import { splitHttpClientFactory } from './splitHttpClient';
|
|
4
4
|
import { ISplitApi } from './types';
|
|
5
5
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
6
|
+
import { ITelemetryTracker } from '../trackers/types';
|
|
7
|
+
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
|
|
6
8
|
|
|
7
9
|
const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
8
10
|
|
|
@@ -18,7 +20,8 @@ function userKeyToQueryParam(userKey: string) {
|
|
|
18
20
|
*/
|
|
19
21
|
export function splitApiFactory(
|
|
20
22
|
settings: Pick<ISettings, 'urls' | 'sync' | 'log' | 'version' | 'runtime' | 'core'>,
|
|
21
|
-
platform: Pick<IPlatform, 'getFetch' | 'getOptions'
|
|
23
|
+
platform: Pick<IPlatform, 'getFetch' | 'getOptions'>,
|
|
24
|
+
telemetryTracker: ITelemetryTracker
|
|
22
25
|
): ISplitApi {
|
|
23
26
|
|
|
24
27
|
const urls = settings.urls;
|
|
@@ -44,17 +47,17 @@ export function splitApiFactory(
|
|
|
44
47
|
if (queryParams) // accounting the possibility that `userKeys` and thus `queryParams` are empty
|
|
45
48
|
url += '?' + queryParams;
|
|
46
49
|
}
|
|
47
|
-
return splitHttpClient(url);
|
|
50
|
+
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN));
|
|
48
51
|
},
|
|
49
52
|
|
|
50
53
|
fetchSplitChanges(since: number, noCache?: boolean) {
|
|
51
54
|
const url = `${urls.sdk}/splitChanges?since=${since}${filterQueryString || ''}`;
|
|
52
|
-
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
|
|
55
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS));
|
|
53
56
|
},
|
|
54
57
|
|
|
55
58
|
fetchSegmentChanges(since: number, segmentName: string, noCache?: boolean) {
|
|
56
59
|
const url = `${urls.sdk}/segmentChanges/${segmentName}?since=${since}`;
|
|
57
|
-
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
|
|
60
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SEGMENT));
|
|
58
61
|
},
|
|
59
62
|
|
|
60
63
|
fetchMySegments(userMatchingKey: string, noCache?: boolean) {
|
|
@@ -65,7 +68,7 @@ export function splitApiFactory(
|
|
|
65
68
|
* - match user keys with special characters. E.g.: 'foo%bar', 'foo/bar'
|
|
66
69
|
*/
|
|
67
70
|
const url = `${urls.sdk}/mySegments/${encodeURIComponent(userMatchingKey)}`;
|
|
68
|
-
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
|
|
71
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MY_SEGMENT));
|
|
69
72
|
},
|
|
70
73
|
|
|
71
74
|
/**
|
|
@@ -76,7 +79,7 @@ export function splitApiFactory(
|
|
|
76
79
|
*/
|
|
77
80
|
postEventsBulk(body: string, headers?: Record<string, string>) {
|
|
78
81
|
const url = `${urls.events}/events/bulk`;
|
|
79
|
-
return splitHttpClient(url, { method: 'POST', body, headers });
|
|
82
|
+
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(EVENTS));
|
|
80
83
|
},
|
|
81
84
|
|
|
82
85
|
/**
|
|
@@ -90,7 +93,7 @@ export function splitApiFactory(
|
|
|
90
93
|
return splitHttpClient(url, {
|
|
91
94
|
// Adding extra headers to send impressions in OPTIMIZED or DEBUG modes.
|
|
92
95
|
method: 'POST', body, headers: objectAssign({ SplitSDKImpressionsMode }, headers)
|
|
93
|
-
});
|
|
96
|
+
}, telemetryTracker.trackHttp(IMPRESSIONS));
|
|
94
97
|
},
|
|
95
98
|
|
|
96
99
|
/**
|
|
@@ -101,17 +104,17 @@ export function splitApiFactory(
|
|
|
101
104
|
*/
|
|
102
105
|
postTestImpressionsCount(body: string, headers?: Record<string, string>) {
|
|
103
106
|
const url = `${urls.events}/testImpressions/count`;
|
|
104
|
-
return splitHttpClient(url, { method: 'POST', body, headers });
|
|
107
|
+
return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(IMPRESSIONS_COUNT));
|
|
105
108
|
},
|
|
106
109
|
|
|
107
|
-
|
|
108
|
-
const url = `${urls.
|
|
109
|
-
return splitHttpClient(url, { method: 'POST', body }, true);
|
|
110
|
+
postMetricsConfig(body: string) {
|
|
111
|
+
const url = `${urls.telemetry}/v1/metrics/config`;
|
|
112
|
+
return splitHttpClient(url, { method: 'POST', body }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
110
113
|
},
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
const url = `${urls.
|
|
114
|
-
return splitHttpClient(url, { method: 'POST', body }, true);
|
|
115
|
+
postMetricsUsage(body: string) {
|
|
116
|
+
const url = `${urls.telemetry}/v1/metrics/usage`;
|
|
117
|
+
return splitHttpClient(url, { method: 'POST', body }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
115
118
|
}
|
|
116
119
|
};
|
|
117
120
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IFetch, IRequestOptions, IResponse, ISplitHttpClient } from './types';
|
|
1
|
+
import { IFetch, IRequestOptions, IResponse, ISplitHttpClient, NetworkError } from './types';
|
|
2
2
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
3
3
|
import { ERROR_HTTP, ERROR_CLIENT_CANNOT_GET_READY } from '../logger/constants';
|
|
4
4
|
import { ISettings } from '../types';
|
|
@@ -31,7 +31,7 @@ export function splitHttpClientFactory(settings: Pick<ISettings, 'log' | 'versio
|
|
|
31
31
|
if (ip) headers['SplitSDKMachineIP'] = ip;
|
|
32
32
|
if (hostname) headers['SplitSDKMachineName'] = hostname;
|
|
33
33
|
|
|
34
|
-
return function httpClient(url: string, reqOpts: IRequestOptions = {}, logErrorsAsInfo: boolean = false): Promise<IResponse> {
|
|
34
|
+
return function httpClient(url: string, reqOpts: IRequestOptions = {}, latencyTracker: (error?: NetworkError) => void = () => { }, logErrorsAsInfo: boolean = false): Promise<IResponse> {
|
|
35
35
|
|
|
36
36
|
const request = objectAssign({
|
|
37
37
|
headers: reqOpts.headers ? objectAssign({}, headers, reqOpts.headers) : headers,
|
|
@@ -46,6 +46,7 @@ export function splitHttpClientFactory(settings: Pick<ISettings, 'log' | 'versio
|
|
|
46
46
|
if (!response.ok) {
|
|
47
47
|
return response.text().then(message => Promise.reject({ response, message }));
|
|
48
48
|
}
|
|
49
|
+
latencyTracker();
|
|
49
50
|
return response;
|
|
50
51
|
})
|
|
51
52
|
.catch(error => {
|
|
@@ -68,9 +69,11 @@ export function splitHttpClientFactory(settings: Pick<ISettings, 'log' | 'versio
|
|
|
68
69
|
log[logErrorsAsInfo ? 'info' : 'error'](ERROR_HTTP, [resp ? resp.status : 'NO_STATUS', url, msg]);
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
const networkError:
|
|
72
|
+
const networkError: NetworkError = new Error(msg);
|
|
72
73
|
// passes `undefined` as statusCode if not an HTTP error (resp === undefined)
|
|
73
74
|
networkError.statusCode = resp && resp.status;
|
|
75
|
+
|
|
76
|
+
latencyTracker(networkError);
|
|
74
77
|
throw networkError;
|
|
75
78
|
}) : Promise.reject(new Error(messageNoFetch));
|
|
76
79
|
};
|
package/src/services/types.ts
CHANGED
|
@@ -23,13 +23,15 @@ export type IResponse = {
|
|
|
23
23
|
// }
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export type NetworkError = Error & { statusCode?: number }
|
|
27
|
+
|
|
26
28
|
// Reduced version of Fetch API
|
|
27
29
|
export type IFetch = (url: string, options?: IRequestOptions) => Promise<IResponse>
|
|
28
30
|
|
|
29
31
|
// IFetch specialization
|
|
30
32
|
export type IHealthCheckAPI = () => Promise<boolean>
|
|
31
33
|
|
|
32
|
-
export type ISplitHttpClient = (url: string, options?: IRequestOptions, logErrorsAsInfo?: boolean) => Promise<IResponse>
|
|
34
|
+
export type ISplitHttpClient = (url: string, options?: IRequestOptions, latencyTracker?: (error?: NetworkError) => void, logErrorsAsInfo?: boolean) => Promise<IResponse>
|
|
33
35
|
|
|
34
36
|
export type IFetchAuth = (userKeys?: string[]) => Promise<IResponse>
|
|
35
37
|
|
|
@@ -45,9 +47,9 @@ export type IPostTestImpressionsBulk = (body: string, headers?: Record<string, s
|
|
|
45
47
|
|
|
46
48
|
export type IPostTestImpressionsCount = (body: string, headers?: Record<string, string>) => Promise<IResponse>
|
|
47
49
|
|
|
48
|
-
export type
|
|
50
|
+
export type IPostMetricsConfig = (body: string) => Promise<IResponse>
|
|
49
51
|
|
|
50
|
-
export type
|
|
52
|
+
export type IPostMetricsUsage = (body: string) => Promise<IResponse>
|
|
51
53
|
|
|
52
54
|
export interface ISplitApi {
|
|
53
55
|
getSdkAPIHealthCheck: IHealthCheckAPI
|
|
@@ -59,8 +61,8 @@ export interface ISplitApi {
|
|
|
59
61
|
postEventsBulk: IPostEventsBulk
|
|
60
62
|
postTestImpressionsBulk: IPostTestImpressionsBulk
|
|
61
63
|
postTestImpressionsCount: IPostTestImpressionsCount
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
postMetricsConfig: IPostMetricsConfig
|
|
65
|
+
postMetricsUsage: IPostMetricsUsage
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
// Minimal version of EventSource API used by the SDK
|
|
@@ -37,10 +37,15 @@ export abstract class AbstractSegmentsCacheSync implements ISegmentsCacheSync {
|
|
|
37
37
|
registerSegments(names: string[]): boolean { return false; }
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* For server-side synchronizer: get the list of segments
|
|
41
|
-
*
|
|
40
|
+
* For server-side synchronizer: get the list of segments to fetch changes.
|
|
41
|
+
* Also used for the `seC` (segment count) telemetry stat.
|
|
42
|
+
*/
|
|
43
|
+
abstract getRegisteredSegments(): string[]
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Only used for the `skC`(segment keys count) telemetry stat: 1 for client-side, and total count of keys in server-side.
|
|
42
47
|
*/
|
|
43
|
-
|
|
48
|
+
abstract getKeysCount(): number
|
|
44
49
|
|
|
45
50
|
/**
|
|
46
51
|
* For server-side synchronizer: set the change number of `name` segment.
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { KeyBuilder } from './KeyBuilder';
|
|
2
2
|
import { IMetadata } from '../dtos/types';
|
|
3
|
+
import { Method } from '../sync/submitters/types';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const methodNames: Record<Method, string> = {
|
|
6
|
+
t: 'treatment',
|
|
7
|
+
ts: 'treatments',
|
|
8
|
+
tc: 'treatmentWithConfig',
|
|
9
|
+
tcs: 'treatmentsWithConfig',
|
|
10
|
+
tr: 'track'
|
|
11
|
+
};
|
|
7
12
|
|
|
8
13
|
export class KeyBuilderSS extends KeyBuilder {
|
|
9
14
|
|
|
@@ -19,7 +24,7 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
private buildVersionablePrefix() {
|
|
22
|
-
return `${this.
|
|
27
|
+
return `${this.metadata.s}/${this.metadata.n}/${this.metadata.i}`;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
buildImpressionsKey() {
|
|
@@ -30,58 +35,16 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
30
35
|
return `${this.prefix}.events`;
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
return `${this.buildVersionablePrefix()}
|
|
38
|
+
buildLatencyKey(method: Method, bucket: number) {
|
|
39
|
+
return `${this.prefix}.telemetry.latencies::${this.buildVersionablePrefix()}/${methodNames[method]}/${bucket}`;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
return `${this.
|
|
42
|
+
buildExceptionKey(method: Method) {
|
|
43
|
+
return `${this.prefix}.telemetry.exceptions::${this.buildVersionablePrefix()}/${methodNames[method]}`;
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
buildCountKey(metricName: string) {
|
|
42
|
-
return `${this.buildVersionablePrefix()}/count.${metricName}`;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// NOT USED
|
|
46
|
-
// buildGaugeKey(metricName: string) {
|
|
47
|
-
// return `${this.buildVersionablePrefix()}/gauge.${metricName}`;
|
|
48
|
-
// }
|
|
49
|
-
|
|
50
|
-
// NOT USED
|
|
51
|
-
// searchPatternForCountKeys() {
|
|
52
|
-
// return `${this.buildVersionablePrefix()}/count.*`;
|
|
53
|
-
// }
|
|
54
|
-
|
|
55
46
|
searchPatternForSplitKeys() {
|
|
56
47
|
return `${this.buildSplitKeyPrefix()}*`;
|
|
57
48
|
}
|
|
58
49
|
|
|
59
|
-
// NOT USED
|
|
60
|
-
// searchPatternForLatency() {
|
|
61
|
-
// return `${this.buildLatencyKeyPrefix()}.*`;
|
|
62
|
-
// }
|
|
63
|
-
|
|
64
|
-
// NOT USED
|
|
65
|
-
// extractCounterName(counterKey: string) {
|
|
66
|
-
// const m = counterKey.match(everythingAfterCount);
|
|
67
|
-
// if (m && m.length) {
|
|
68
|
-
// return m[1]; // everything after count
|
|
69
|
-
// } else {
|
|
70
|
-
// throw new Error('Invalid counter key provided');
|
|
71
|
-
// }
|
|
72
|
-
// }
|
|
73
|
-
|
|
74
|
-
// NOT USED
|
|
75
|
-
// extractLatencyMetricNameAndBucket(latencyKey: string) {
|
|
76
|
-
// const parts = latencyKey.match(latencyMetricNameAndBucket);
|
|
77
|
-
|
|
78
|
-
// if (parts && parts.length > 2) {
|
|
79
|
-
// return {
|
|
80
|
-
// metricName: parts[1],
|
|
81
|
-
// bucketNumber: parts[2]
|
|
82
|
-
// };
|
|
83
|
-
// } else {
|
|
84
|
-
// throw new Error('Invalid counter key provided');
|
|
85
|
-
// }
|
|
86
|
-
// }
|
|
87
50
|
}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { isNaNNumber } from '../utils/lang';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const MIN = 0;
|
|
4
|
+
const MAX = 22;
|
|
5
|
+
const BASE = 1.5;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Calculates buckets from latency in milliseconds
|
|
9
|
+
*
|
|
10
|
+
* @param latencyInMs
|
|
11
|
+
* @returns a bucket index from 0 to 22 inclusive
|
|
12
|
+
*/
|
|
13
|
+
export function findLatencyIndex(latencyInMs: number): number {
|
|
14
|
+
const index = Math.min(MAX, Math.max(MIN, Math.ceil(Math.log(latencyInMs) / Math.log(BASE))));
|
|
6
15
|
return isNaNNumber(index) ? 0 : index; // index is NaN if latency is not a positive number
|
|
7
16
|
}
|
|
@@ -72,7 +72,7 @@ export class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
|
|
|
72
72
|
if (segmentName) {
|
|
73
73
|
accum.push(segmentName);
|
|
74
74
|
} else {
|
|
75
|
-
// @BREAKING: This is only to clean up "old" keys. Remove this whole else code block.
|
|
75
|
+
// @TODO @BREAKING: This is only to clean up "old" keys. Remove this whole else code block and reuse `getRegisteredSegments` method.
|
|
76
76
|
segmentName = this.keys.extractOldSegmentKey(key);
|
|
77
77
|
|
|
78
78
|
if (segmentName) { // this was an old segment key, let's clean up.
|
|
@@ -121,4 +121,16 @@ export class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
|
|
|
121
121
|
return isDiff;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
getRegisteredSegments(): string[] {
|
|
125
|
+
return Object.keys(localStorage).reduce<string[]>((accum, key) => {
|
|
126
|
+
const segmentName = this.keys.extractSegmentName(key);
|
|
127
|
+
if (segmentName) accum.push(segmentName);
|
|
128
|
+
return accum;
|
|
129
|
+
}, []);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getKeysCount() {
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
|
|
124
136
|
}
|
|
@@ -12,7 +12,8 @@ import { SplitsCacheInMemory } from '../inMemory/SplitsCacheInMemory';
|
|
|
12
12
|
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../../utils/constants/browser';
|
|
13
13
|
import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
|
|
14
14
|
import { LOG_PREFIX } from './constants';
|
|
15
|
-
import { STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
15
|
+
import { LOCALHOST_MODE, STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
16
|
+
import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
|
|
16
17
|
|
|
17
18
|
export interface InLocalStorageOptions {
|
|
18
19
|
prefix?: string
|
|
@@ -29,7 +30,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
29
30
|
|
|
30
31
|
// Fallback to InMemoryStorage if LocalStorage API is not available
|
|
31
32
|
if (!isLocalStorageAvailable()) {
|
|
32
|
-
params.log.warn(LOG_PREFIX + 'LocalStorage API is unavailable.
|
|
33
|
+
params.log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
|
|
33
34
|
return InMemoryStorageCSFactory(params);
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -43,6 +44,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
43
44
|
impressions: new ImpressionsCacheInMemory(params.impressionsQueueSize),
|
|
44
45
|
impressionCounts: params.optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
45
46
|
events: new EventsCacheInMemory(params.eventsQueueSize),
|
|
47
|
+
telemetry: params.mode !== LOCALHOST_MODE && shouldRecordTelemetry() ? new TelemetryCacheInMemory() : undefined,
|
|
46
48
|
|
|
47
49
|
destroy() {
|
|
48
50
|
this.splits = new SplitsCacheInMemory();
|
|
@@ -62,6 +64,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
62
64
|
impressions: this.impressions,
|
|
63
65
|
impressionCounts: this.impressionCounts,
|
|
64
66
|
events: this.events,
|
|
67
|
+
telemetry: this.telemetry,
|
|
65
68
|
|
|
66
69
|
destroy() {
|
|
67
70
|
this.splits = new SplitsCacheInMemory();
|
|
@@ -4,7 +4,8 @@ import { ImpressionsCacheInMemory } from './ImpressionsCacheInMemory';
|
|
|
4
4
|
import { EventsCacheInMemory } from './EventsCacheInMemory';
|
|
5
5
|
import { IStorageFactoryParams, IStorageSync } from '../types';
|
|
6
6
|
import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
7
|
-
import { STORAGE_MEMORY } from '../../utils/constants';
|
|
7
|
+
import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
|
+
import { TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* InMemory storage factory for standalone server-side SplitFactory
|
|
@@ -19,6 +20,7 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
|
|
|
19
20
|
impressions: new ImpressionsCacheInMemory(params.impressionsQueueSize),
|
|
20
21
|
impressionCounts: params.optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
21
22
|
events: new EventsCacheInMemory(params.eventsQueueSize),
|
|
23
|
+
telemetry: params.mode !== LOCALHOST_MODE ? new TelemetryCacheInMemory() : undefined, // Always track telemetry in standalone mode on server-side
|
|
22
24
|
|
|
23
25
|
// When using MEMORY we should clean all the caches to leave them empty
|
|
24
26
|
destroy() {
|