@splitsoftware/splitio-commons 1.3.2-rc.4 → 1.3.2-rc.7
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/sync/submitters/telemetrySubmitter.js +11 -9
- package/cjs/trackers/telemetryTracker.js +2 -2
- package/cjs/utils/settingsValidation/index.js +3 -10
- package/cjs/utils/timeTracker/now/browser.js +1 -1
- package/cjs/utils/timeTracker/now/node.js +1 -2
- package/esm/sync/submitters/telemetrySubmitter.js +11 -9
- package/esm/trackers/telemetryTracker.js +2 -2
- package/esm/utils/settingsValidation/index.js +4 -11
- package/esm/utils/timeTracker/now/browser.js +1 -1
- package/esm/utils/timeTracker/now/node.js +1 -2
- package/package.json +1 -1
- package/src/sdkFactory/types.ts +16 -2
- package/src/sync/submitters/telemetrySubmitter.ts +12 -10
- package/src/sync/submitters/types.ts +2 -1
- package/src/trackers/telemetryTracker.ts +2 -2
- package/src/utils/lang/index.ts +1 -1
- package/src/utils/settingsValidation/index.ts +3 -10
- package/src/utils/timeTracker/now/browser.ts +1 -1
- package/src/utils/timeTracker/now/node.ts +1 -2
- package/types/sdkFactory/types.d.ts +16 -2
- package/types/sync/submitters/types.d.ts +2 -1
- package/types/utils/lang/index.d.ts +1 -1
- package/types/utils/timeTracker/index.d.ts +1 -70
- package/cjs/utils/timeTracker/index.js +0 -197
- package/esm/utils/timeTracker/index.js +0 -194
- package/src/utils/timeTracker/index.ts +0 -226
package/CHANGES.txt
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
1.4.0 (May 24, 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).
|
|
@@ -82,14 +82,16 @@ function telemetryCacheConfigAdapter(telemetry, settings) {
|
|
|
82
82
|
clear: function () { },
|
|
83
83
|
state: function () {
|
|
84
84
|
var urls = settings.urls, scheduler = settings.scheduler;
|
|
85
|
+
var isClientSide = settings.core.key !== undefined;
|
|
85
86
|
return (0, objectAssign_1.objectAssign)(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
86
87
|
sE: settings.streamingEnabled,
|
|
87
88
|
rR: {
|
|
88
|
-
sp: scheduler.featuresRefreshRate,
|
|
89
|
-
se: scheduler.segmentsRefreshRate,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
sp: scheduler.featuresRefreshRate / 1000,
|
|
90
|
+
se: isClientSide ? undefined : scheduler.segmentsRefreshRate / 1000,
|
|
91
|
+
ms: isClientSide ? scheduler.segmentsRefreshRate / 1000 : undefined,
|
|
92
|
+
im: scheduler.impressionsRefreshRate / 1000,
|
|
93
|
+
ev: scheduler.eventsPushRate / 1000,
|
|
94
|
+
te: scheduler.telemetryRefreshRate / 1000,
|
|
93
95
|
},
|
|
94
96
|
uO: {
|
|
95
97
|
s: urls.sdk !== settingsValidation_1.base.urls.sdk,
|
|
@@ -118,11 +120,11 @@ exports.telemetryCacheConfigAdapter = telemetryCacheConfigAdapter;
|
|
|
118
120
|
* Submitter that periodically posts telemetry data
|
|
119
121
|
*/
|
|
120
122
|
function telemetrySubmitterFactory(params) {
|
|
121
|
-
var _a = params.storage, splits = _a.splits, segments = _a.segments, telemetry = _a.telemetry;
|
|
122
|
-
if (!telemetry)
|
|
123
|
+
var _a = params.storage, splits = _a.splits, segments = _a.segments, telemetry = _a.telemetry, now = params.platform.now;
|
|
124
|
+
if (!telemetry || !now)
|
|
123
125
|
return; // No submitter created if telemetry cache is not defined
|
|
124
|
-
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi,
|
|
125
|
-
var startTime = (0, timer_1.timer)(now
|
|
126
|
+
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
|
|
127
|
+
var startTime = (0, timer_1.timer)(now);
|
|
126
128
|
var submitter = (0, submitter_1.firstPushWindowDecorator)((0, submitter_1.submitterFactory)(log, splitApi.postMetricsUsage, telemetryCacheStatsAdapter(telemetry, splits, segments), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
|
|
127
129
|
readiness.gate.once(constants_2.SDK_READY_FROM_CACHE, function () {
|
|
128
130
|
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
@@ -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();
|
|
@@ -112,16 +112,9 @@ function settingsValidation(config, validationParams) {
|
|
|
112
112
|
scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate);
|
|
113
113
|
scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
|
|
114
114
|
scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
scheduler.impressionsRefreshRate =
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
122
|
-
if (withDefaults.sync.impressionsMode === constants_1.DEBUG)
|
|
123
|
-
scheduler.impressionsRefreshRate = 60;
|
|
124
|
-
}
|
|
115
|
+
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
116
|
+
if ((0, lang_1.get)(config, 'scheduler.impressionsRefreshRate') === undefined && withDefaults.sync.impressionsMode === constants_1.DEBUG)
|
|
117
|
+
scheduler.impressionsRefreshRate = 60;
|
|
125
118
|
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
126
119
|
// Log deprecation for old telemetry param
|
|
127
120
|
if (scheduler.metricsRefreshRate)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.now = void 0;
|
|
4
|
-
//
|
|
4
|
+
// Can be used on any runtime, since it fallbacks to `Date.now` if `performance.now` is not available
|
|
5
5
|
function nowFactory() {
|
|
6
6
|
// eslint-disable-next-line
|
|
7
7
|
if (typeof performance === 'object' && typeof performance.now === 'function') {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.now = void 0;
|
|
4
|
-
// @TODO migrate to Node SDK package eventually
|
|
5
4
|
function now() {
|
|
6
5
|
// eslint-disable-next-line no-undef
|
|
7
6
|
var time = process.hrtime();
|
|
8
|
-
return time[0] * 1e3 + time[1] * 1e-6; // convert it to
|
|
7
|
+
return time[0] * 1e3 + time[1] * 1e-6; // convert it to millis
|
|
9
8
|
}
|
|
10
9
|
exports.now = now;
|
|
@@ -77,14 +77,16 @@ export function telemetryCacheConfigAdapter(telemetry, settings) {
|
|
|
77
77
|
clear: function () { },
|
|
78
78
|
state: function () {
|
|
79
79
|
var urls = settings.urls, scheduler = settings.scheduler;
|
|
80
|
+
var isClientSide = settings.core.key !== undefined;
|
|
80
81
|
return objectAssign(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
81
82
|
sE: settings.streamingEnabled,
|
|
82
83
|
rR: {
|
|
83
|
-
sp: scheduler.featuresRefreshRate,
|
|
84
|
-
se: scheduler.segmentsRefreshRate,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
sp: scheduler.featuresRefreshRate / 1000,
|
|
85
|
+
se: isClientSide ? undefined : scheduler.segmentsRefreshRate / 1000,
|
|
86
|
+
ms: isClientSide ? scheduler.segmentsRefreshRate / 1000 : undefined,
|
|
87
|
+
im: scheduler.impressionsRefreshRate / 1000,
|
|
88
|
+
ev: scheduler.eventsPushRate / 1000,
|
|
89
|
+
te: scheduler.telemetryRefreshRate / 1000,
|
|
88
90
|
},
|
|
89
91
|
uO: {
|
|
90
92
|
s: urls.sdk !== base.urls.sdk,
|
|
@@ -112,11 +114,11 @@ export function telemetryCacheConfigAdapter(telemetry, settings) {
|
|
|
112
114
|
* Submitter that periodically posts telemetry data
|
|
113
115
|
*/
|
|
114
116
|
export function telemetrySubmitterFactory(params) {
|
|
115
|
-
var _a = params.storage, splits = _a.splits, segments = _a.segments, telemetry = _a.telemetry;
|
|
116
|
-
if (!telemetry)
|
|
117
|
+
var _a = params.storage, splits = _a.splits, segments = _a.segments, telemetry = _a.telemetry, now = params.platform.now;
|
|
118
|
+
if (!telemetry || !now)
|
|
117
119
|
return; // No submitter created if telemetry cache is not defined
|
|
118
|
-
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi,
|
|
119
|
-
var startTime = timer(now
|
|
120
|
+
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
|
|
121
|
+
var startTime = timer(now);
|
|
120
122
|
var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage, telemetryCacheStatsAdapter(telemetry, splits, segments), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
|
|
121
123
|
readiness.gate.once(SDK_READY_FROM_CACHE, function () {
|
|
122
124
|
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
@@ -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();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { merge } from '../lang';
|
|
1
|
+
import { merge, get } from '../lang';
|
|
2
2
|
import { mode } from './mode';
|
|
3
3
|
import { validateSplitFilters } from './splitFilters';
|
|
4
4
|
import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE, DEBUG } from '../constants';
|
|
@@ -109,16 +109,9 @@ export function settingsValidation(config, validationParams) {
|
|
|
109
109
|
scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate);
|
|
110
110
|
scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
|
|
111
111
|
scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
scheduler.impressionsRefreshRate =
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
119
|
-
if (withDefaults.sync.impressionsMode === DEBUG)
|
|
120
|
-
scheduler.impressionsRefreshRate = 60;
|
|
121
|
-
}
|
|
112
|
+
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
113
|
+
if (get(config, 'scheduler.impressionsRefreshRate') === undefined && withDefaults.sync.impressionsMode === DEBUG)
|
|
114
|
+
scheduler.impressionsRefreshRate = 60;
|
|
122
115
|
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
123
116
|
// Log deprecation for old telemetry param
|
|
124
117
|
if (scheduler.metricsRefreshRate)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Can be used on any runtime, since it fallbacks to `Date.now` if `performance.now` is not available
|
|
2
2
|
function nowFactory() {
|
|
3
3
|
// eslint-disable-next-line
|
|
4
4
|
if (typeof performance === 'object' && typeof performance.now === 'function') {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
// @TODO migrate to Node SDK package eventually
|
|
2
1
|
export function now() {
|
|
3
2
|
// eslint-disable-next-line no-undef
|
|
4
3
|
var time = process.hrtime();
|
|
5
|
-
return time[0] * 1e3 + time[1] * 1e-6; // convert it to
|
|
4
|
+
return time[0] * 1e3 + time[1] * 1e-6; // convert it to millis
|
|
6
5
|
}
|
package/package.json
CHANGED
package/src/sdkFactory/types.ts
CHANGED
|
@@ -11,13 +11,27 @@ import { SplitIO, ISettings, IEventEmitter } from '../types';
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Environment related dependencies.
|
|
14
|
-
* These getters are called a fixed number of times per factory instantiation.
|
|
15
14
|
*/
|
|
16
15
|
export interface IPlatform {
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* If provided, it is used to retrieve the Fetch API for HTTP requests. Otherwise, the global fetch is used.
|
|
18
|
+
*/
|
|
18
19
|
getFetch?: () => (IFetch | undefined)
|
|
20
|
+
/**
|
|
21
|
+
* If provided, it is used to pass additional options to fetch calls.
|
|
22
|
+
*/
|
|
23
|
+
getOptions?: () => object
|
|
24
|
+
/**
|
|
25
|
+
* If provided, it is used to retrieve the EventSource constructor for streaming support.
|
|
26
|
+
*/
|
|
19
27
|
getEventSource?: () => (IEventSourceConstructor | undefined)
|
|
28
|
+
/**
|
|
29
|
+
* EventEmitter constructor, like NodeJS.EventEmitter or a polyfill.
|
|
30
|
+
*/
|
|
20
31
|
EventEmitter: new () => IEventEmitter,
|
|
32
|
+
/**
|
|
33
|
+
* Function used to track latencies for telemetry.
|
|
34
|
+
*/
|
|
21
35
|
now?: () => number
|
|
22
36
|
}
|
|
23
37
|
|
|
@@ -59,7 +59,7 @@ const USER_CONSENT_MAP = {
|
|
|
59
59
|
[CONSENT_UNKNOWN]: 1,
|
|
60
60
|
[CONSENT_GRANTED]: 2,
|
|
61
61
|
[CONSENT_DECLINED]: 3
|
|
62
|
-
} as Record<ConsentStatus,
|
|
62
|
+
} as Record<ConsentStatus, number>;
|
|
63
63
|
|
|
64
64
|
function getActiveFactories() {
|
|
65
65
|
return Object.keys(usedKeysMap).length;
|
|
@@ -90,15 +90,17 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett
|
|
|
90
90
|
|
|
91
91
|
state(): TelemetryConfigStatsPayload {
|
|
92
92
|
const { urls, scheduler } = settings;
|
|
93
|
+
const isClientSide = settings.core.key !== undefined;
|
|
93
94
|
|
|
94
95
|
return objectAssign(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
95
96
|
sE: settings.streamingEnabled,
|
|
96
97
|
rR: {
|
|
97
|
-
sp: scheduler.featuresRefreshRate,
|
|
98
|
-
se: scheduler.segmentsRefreshRate,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
sp: scheduler.featuresRefreshRate / 1000,
|
|
99
|
+
se: isClientSide ? undefined : scheduler.segmentsRefreshRate / 1000,
|
|
100
|
+
ms: isClientSide ? scheduler.segmentsRefreshRate / 1000 : undefined,
|
|
101
|
+
im: scheduler.impressionsRefreshRate / 1000,
|
|
102
|
+
ev: scheduler.eventsPushRate / 1000,
|
|
103
|
+
te: scheduler.telemetryRefreshRate / 1000,
|
|
102
104
|
}, // refreshRates
|
|
103
105
|
uO: {
|
|
104
106
|
s: urls.sdk !== base.urls.sdk,
|
|
@@ -127,11 +129,11 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett
|
|
|
127
129
|
* Submitter that periodically posts telemetry data
|
|
128
130
|
*/
|
|
129
131
|
export function telemetrySubmitterFactory(params: ISdkFactoryContextSync) {
|
|
130
|
-
const { storage: { splits, segments, telemetry } } = params;
|
|
131
|
-
if (!telemetry) return; // No submitter created if telemetry cache is not defined
|
|
132
|
+
const { storage: { splits, segments, telemetry }, platform: { now } } = params;
|
|
133
|
+
if (!telemetry || !now) return; // No submitter created if telemetry cache is not defined
|
|
132
134
|
|
|
133
|
-
const { settings, settings: { log, scheduler: { telemetryRefreshRate } }, splitApi,
|
|
134
|
-
const startTime = timer(now
|
|
135
|
+
const { settings, settings: { log, scheduler: { telemetryRefreshRate } }, splitApi, readiness, sdkReadinessManager } = params;
|
|
136
|
+
const startTime = timer(now);
|
|
135
137
|
|
|
136
138
|
const submitter = firstPushWindowDecorator(
|
|
137
139
|
submitterFactory(log, splitApi.postMetricsUsage, telemetryCacheStatsAdapter(telemetry, splits, segments), telemetryRefreshRate, 'telemetry stats', undefined, 0, true),
|
|
@@ -151,7 +151,8 @@ export type ImpressionsMode = OPTIMIZED_ENUM | DEBUG_ENUM;
|
|
|
151
151
|
|
|
152
152
|
export type RefreshRates = {
|
|
153
153
|
sp: number, // splits
|
|
154
|
-
se
|
|
154
|
+
se?: number, // segments
|
|
155
|
+
ms?: number, // mySegments
|
|
155
156
|
im: number, // impressions
|
|
156
157
|
ev: number, // events
|
|
157
158
|
te: number, // telemetry
|
|
@@ -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
|
}
|
package/src/utils/lang/index.ts
CHANGED
|
@@ -71,7 +71,7 @@ export function forOwn<T>(obj: { [key: string]: T }, iteratee: (value: T, key: s
|
|
|
71
71
|
* Safely retrieve the specified prop from obj. If we can't retrieve
|
|
72
72
|
* that property value, we return the default value.
|
|
73
73
|
*/
|
|
74
|
-
export function get(obj: any, prop: any, val
|
|
74
|
+
export function get(obj: any, prop: any, val?: any): any {
|
|
75
75
|
let res = val;
|
|
76
76
|
|
|
77
77
|
try { // No risks nor lots of checks.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { merge } from '../lang';
|
|
1
|
+
import { merge, get } from '../lang';
|
|
2
2
|
import { mode } from './mode';
|
|
3
3
|
import { validateSplitFilters } from './splitFilters';
|
|
4
4
|
import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE, DEBUG } from '../constants';
|
|
@@ -131,15 +131,8 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
131
131
|
scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
|
|
132
132
|
scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
scheduler.impressionsRefreshRate = validateMinValue('impressionsRefreshRate', scheduler.impressionsRefreshRate,
|
|
137
|
-
withDefaults.sync.impressionsMode === DEBUG ? 1 : 60 // Min is 1 sec for DEBUG and 60 secs for OPTIMIZED
|
|
138
|
-
);
|
|
139
|
-
} else {
|
|
140
|
-
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
141
|
-
if (withDefaults.sync.impressionsMode === DEBUG) scheduler.impressionsRefreshRate = 60;
|
|
142
|
-
}
|
|
134
|
+
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
135
|
+
if (get(config, 'scheduler.impressionsRefreshRate') === undefined && withDefaults.sync.impressionsMode === DEBUG) scheduler.impressionsRefreshRate = 60;
|
|
143
136
|
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
144
137
|
|
|
145
138
|
// Log deprecation for old telemetry param
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Can be used on any runtime, since it fallbacks to `Date.now` if `performance.now` is not available
|
|
2
2
|
function nowFactory() {
|
|
3
3
|
// eslint-disable-next-line
|
|
4
4
|
if (typeof performance === 'object' && typeof performance.now === 'function') {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// @TODO migrate to Node SDK package eventually
|
|
2
1
|
export function now() {
|
|
3
2
|
// eslint-disable-next-line no-undef
|
|
4
3
|
let time = process.hrtime();
|
|
5
4
|
|
|
6
|
-
return time[0] * 1e3 + time[1] * 1e-6; // convert it to
|
|
5
|
+
return time[0] * 1e3 + time[1] * 1e-6; // convert it to millis
|
|
7
6
|
}
|
|
@@ -10,13 +10,27 @@ import { IImpressionsTracker, IEventTracker, ITelemetryTracker } from '../tracke
|
|
|
10
10
|
import { SplitIO, ISettings, IEventEmitter } from '../types';
|
|
11
11
|
/**
|
|
12
12
|
* Environment related dependencies.
|
|
13
|
-
* These getters are called a fixed number of times per factory instantiation.
|
|
14
13
|
*/
|
|
15
14
|
export interface IPlatform {
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* If provided, it is used to retrieve the Fetch API for HTTP requests. Otherwise, the global fetch is used.
|
|
17
|
+
*/
|
|
17
18
|
getFetch?: () => (IFetch | undefined);
|
|
19
|
+
/**
|
|
20
|
+
* If provided, it is used to pass additional options to fetch calls.
|
|
21
|
+
*/
|
|
22
|
+
getOptions?: () => object;
|
|
23
|
+
/**
|
|
24
|
+
* If provided, it is used to retrieve the EventSource constructor for streaming support.
|
|
25
|
+
*/
|
|
18
26
|
getEventSource?: () => (IEventSourceConstructor | undefined);
|
|
27
|
+
/**
|
|
28
|
+
* EventEmitter constructor, like NodeJS.EventEmitter or a polyfill.
|
|
29
|
+
*/
|
|
19
30
|
EventEmitter: new () => IEventEmitter;
|
|
31
|
+
/**
|
|
32
|
+
* Function used to track latencies for telemetry.
|
|
33
|
+
*/
|
|
20
34
|
now?: () => number;
|
|
21
35
|
}
|
|
22
36
|
export interface ISdkFactoryContext {
|
|
@@ -134,7 +134,8 @@ export declare type DEBUG_ENUM = 1;
|
|
|
134
134
|
export declare type ImpressionsMode = OPTIMIZED_ENUM | DEBUG_ENUM;
|
|
135
135
|
export declare type RefreshRates = {
|
|
136
136
|
sp: number;
|
|
137
|
-
se
|
|
137
|
+
se?: number;
|
|
138
|
+
ms?: number;
|
|
138
139
|
im: number;
|
|
139
140
|
ev: number;
|
|
140
141
|
te: number;
|
|
@@ -28,7 +28,7 @@ export declare function forOwn<T>(obj: {
|
|
|
28
28
|
* Safely retrieve the specified prop from obj. If we can't retrieve
|
|
29
29
|
* that property value, we return the default value.
|
|
30
30
|
*/
|
|
31
|
-
export declare function get(obj: any, prop: any, val
|
|
31
|
+
export declare function get(obj: any, prop: any, val?: any): any;
|
|
32
32
|
/**
|
|
33
33
|
* Parses an array into a map of different arrays, grouping by the specified prop value.
|
|
34
34
|
*/
|
|
@@ -1,70 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { IResponse } from '../../services/types';
|
|
3
|
-
interface MetricsCollector {
|
|
4
|
-
countException(): void;
|
|
5
|
-
count(status: number): void;
|
|
6
|
-
latency(ms: number): void;
|
|
7
|
-
ready(ms: number): void;
|
|
8
|
-
getTreatment(ms: number): void;
|
|
9
|
-
getTreatments(ms: number): void;
|
|
10
|
-
getTreatmentWithConfig(ms: number): void;
|
|
11
|
-
getTreatmentsWithConfig(ms: number): void;
|
|
12
|
-
[method: string]: (ms: number) => void;
|
|
13
|
-
}
|
|
14
|
-
export declare const TrackerAPI: {
|
|
15
|
-
/**
|
|
16
|
-
* "Private" method, used to attach count/countException and stop callbacks to a promise.
|
|
17
|
-
*
|
|
18
|
-
* @param {ILogger} log - Logger.
|
|
19
|
-
* @param {Promise} promise - The promise we want to attach the callbacks.
|
|
20
|
-
* @param {string} task - The name of the task.
|
|
21
|
-
* @param {number | string} modifier - (optional) The modifier for the task, if any.
|
|
22
|
-
*/
|
|
23
|
-
__attachToPromise(log: ILogger, promise: Promise<IResponse>, task: string, collector: false | MetricsCollector, modifier?: string | number | undefined): Promise<IResponse>;
|
|
24
|
-
/**
|
|
25
|
-
* Starts tracking the time for a given task. All tasks tracked are considered "unique" because
|
|
26
|
-
* there may be multiple SDK instances tracking a "generic" task, making any task non-generic.
|
|
27
|
-
*
|
|
28
|
-
* @param {ILogger} log - Logger.
|
|
29
|
-
* @param {string} task - The task we are starting.
|
|
30
|
-
* @param {Object} collectors - The collectors map.
|
|
31
|
-
* @param {Promise} promise - (optional) The promise we are tracking.
|
|
32
|
-
* @return {Function | Promise} The stop function for this specific task or the promise received with the callbacks registered.
|
|
33
|
-
*/
|
|
34
|
-
start(log: ILogger, task: string, collectors?: Record<string, MetricsCollector> | undefined, promise?: Promise<IResponse> | undefined, now?: () => number): Promise<IResponse> | (() => number);
|
|
35
|
-
/**
|
|
36
|
-
* Setup the collector for a task that reports metrics.
|
|
37
|
-
*
|
|
38
|
-
* @param {string} task - The task name
|
|
39
|
-
* @param {number | string} taskUniqueId - The unique identifier for this task
|
|
40
|
-
* @param {Object} collectors - The collectors map.
|
|
41
|
-
*/
|
|
42
|
-
setCollectorForTask(task: string, taskUniqueId: number | string, collectors: Record<string, MetricsCollector>): void;
|
|
43
|
-
/**
|
|
44
|
-
* Stops the tracking of a given task.
|
|
45
|
-
*
|
|
46
|
-
* @param {ILogger} log - Logger.
|
|
47
|
-
* @param {string} task - The task we are starting.
|
|
48
|
-
* @param {number | string} modifier - (optional) The modifier for that specific task.
|
|
49
|
-
*/
|
|
50
|
-
stop(log: ILogger, task: string, modifier?: string | number | undefined): number | undefined;
|
|
51
|
-
/**
|
|
52
|
-
* The constants shortcut for the task names.
|
|
53
|
-
*/
|
|
54
|
-
TaskNames: {
|
|
55
|
-
SDK_READY: string;
|
|
56
|
-
SDK_GET_TREATMENT: string;
|
|
57
|
-
SDK_GET_TREATMENTS: string;
|
|
58
|
-
SDK_GET_TREATMENT_WITH_CONFIG: string;
|
|
59
|
-
SDK_GET_TREATMENTS_WITH_CONFIG: string;
|
|
60
|
-
SPLITS_READY: string;
|
|
61
|
-
SEGMENTS_READY: string;
|
|
62
|
-
METRICS_PUSH: string;
|
|
63
|
-
IMPRESSIONS_PUSH: string;
|
|
64
|
-
EVENTS_PUSH: string;
|
|
65
|
-
MY_SEGMENTS_FETCH: string;
|
|
66
|
-
SEGMENTS_FETCH: string;
|
|
67
|
-
SPLITS_FETCH: string;
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
export {};
|
|
1
|
+
export declare function timeTracker(now: () => number): () => () => number;
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var _a;
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.TrackerAPI = void 0;
|
|
5
|
-
var lang_1 = require("../lang");
|
|
6
|
-
var timer_1 = require("./timer");
|
|
7
|
-
var thenable_1 = require("../promise/thenable");
|
|
8
|
-
// Map we will use for storing timers data
|
|
9
|
-
var timers = {};
|
|
10
|
-
// Tasks constants
|
|
11
|
-
var CONSTANTS = {
|
|
12
|
-
SDK_READY: 'Getting ready - Split SDK',
|
|
13
|
-
SDK_GET_TREATMENT: 'SDK - Get Treatment',
|
|
14
|
-
SDK_GET_TREATMENTS: 'SDK - Get Treatments',
|
|
15
|
-
SDK_GET_TREATMENT_WITH_CONFIG: 'SDK - Get Treatment with config',
|
|
16
|
-
SDK_GET_TREATMENTS_WITH_CONFIG: 'SDK - Get Treatments with config',
|
|
17
|
-
SPLITS_READY: 'Getting ready - Splits',
|
|
18
|
-
SEGMENTS_READY: 'Getting ready - Segments',
|
|
19
|
-
METRICS_PUSH: 'Pushing - Metrics',
|
|
20
|
-
IMPRESSIONS_PUSH: 'Pushing - Impressions',
|
|
21
|
-
EVENTS_PUSH: 'Pushing - Events',
|
|
22
|
-
MY_SEGMENTS_FETCH: 'Fetching - My Segments',
|
|
23
|
-
SEGMENTS_FETCH: 'Fetching - Segments',
|
|
24
|
-
SPLITS_FETCH: 'Fetching - Splits'
|
|
25
|
-
};
|
|
26
|
-
// Tasks callbacks, if any
|
|
27
|
-
var CALLBACKS = (_a = {},
|
|
28
|
-
_a[CONSTANTS.SDK_READY] = {
|
|
29
|
-
collector: 'client',
|
|
30
|
-
method: 'ready'
|
|
31
|
-
},
|
|
32
|
-
_a[CONSTANTS.SDK_GET_TREATMENT] = {
|
|
33
|
-
collector: 'client',
|
|
34
|
-
method: 'getTreatment'
|
|
35
|
-
},
|
|
36
|
-
_a[CONSTANTS.SDK_GET_TREATMENTS] = {
|
|
37
|
-
collector: 'client',
|
|
38
|
-
method: 'getTreatments'
|
|
39
|
-
},
|
|
40
|
-
_a[CONSTANTS.SDK_GET_TREATMENT_WITH_CONFIG] = {
|
|
41
|
-
collector: 'client',
|
|
42
|
-
method: 'getTreatmentWithConfig'
|
|
43
|
-
},
|
|
44
|
-
_a[CONSTANTS.SDK_GET_TREATMENTS_WITH_CONFIG] = {
|
|
45
|
-
collector: 'client',
|
|
46
|
-
method: 'getTreatmentsWithConfig'
|
|
47
|
-
},
|
|
48
|
-
_a[CONSTANTS.MY_SEGMENTS_FETCH] = {
|
|
49
|
-
collector: 'mySegments',
|
|
50
|
-
method: 'latency'
|
|
51
|
-
},
|
|
52
|
-
_a[CONSTANTS.SEGMENTS_FETCH] = {
|
|
53
|
-
collector: 'segmentChanges',
|
|
54
|
-
method: 'latency'
|
|
55
|
-
},
|
|
56
|
-
_a[CONSTANTS.SPLITS_FETCH] = {
|
|
57
|
-
collector: 'splitChanges',
|
|
58
|
-
method: 'latency'
|
|
59
|
-
},
|
|
60
|
-
_a);
|
|
61
|
-
/**
|
|
62
|
-
* Generates the timer keys using the task name and a modifier, if any.
|
|
63
|
-
* @param {string} task - The task name
|
|
64
|
-
* @param {number | string} modifier - (optional) The modifier, if any.
|
|
65
|
-
* @return {string} The generated timer key
|
|
66
|
-
*/
|
|
67
|
-
function generateTimerKey(task, modifier) { return modifier ? task + modifier : task; }
|
|
68
|
-
/**
|
|
69
|
-
* Given the collectors map, it returns the specific collector for a given task.
|
|
70
|
-
*
|
|
71
|
-
* @param {string} task - The task name
|
|
72
|
-
* @param {Object} collectors - The collectors map
|
|
73
|
-
*/
|
|
74
|
-
function getCollectorForTask(task, collectors) {
|
|
75
|
-
var callbackData = CALLBACKS[task];
|
|
76
|
-
if (callbackData && collectors)
|
|
77
|
-
return collectors[callbackData.collector];
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Given a collector and a task, returns the callback function that should be called when we stop the timer.
|
|
82
|
-
*
|
|
83
|
-
* @param {string} task - The task name
|
|
84
|
-
* @param {Object} collector - The collector object for the task
|
|
85
|
-
*/
|
|
86
|
-
function getCallbackForTask(task, collector) {
|
|
87
|
-
var callbackData = CALLBACKS[task];
|
|
88
|
-
if (callbackData && collector)
|
|
89
|
-
return collector[callbackData.method];
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
// Our "time tracker" API
|
|
93
|
-
exports.TrackerAPI = {
|
|
94
|
-
/**
|
|
95
|
-
* "Private" method, used to attach count/countException and stop callbacks to a promise.
|
|
96
|
-
*
|
|
97
|
-
* @param {ILogger} log - Logger.
|
|
98
|
-
* @param {Promise} promise - The promise we want to attach the callbacks.
|
|
99
|
-
* @param {string} task - The name of the task.
|
|
100
|
-
* @param {number | string} modifier - (optional) The modifier for the task, if any.
|
|
101
|
-
*/
|
|
102
|
-
__attachToPromise: function (log, promise, task, collector, modifier) {
|
|
103
|
-
var _this = this;
|
|
104
|
-
return promise.then(function (resp) {
|
|
105
|
-
_this.stop(log, task, modifier);
|
|
106
|
-
if (collector && collector.count)
|
|
107
|
-
collector.count(resp.status);
|
|
108
|
-
return resp;
|
|
109
|
-
})
|
|
110
|
-
.catch(function (err) {
|
|
111
|
-
_this.stop(log, task, modifier);
|
|
112
|
-
if (collector && collector.countException)
|
|
113
|
-
collector.countException();
|
|
114
|
-
throw err;
|
|
115
|
-
});
|
|
116
|
-
},
|
|
117
|
-
/**
|
|
118
|
-
* Starts tracking the time for a given task. All tasks tracked are considered "unique" because
|
|
119
|
-
* there may be multiple SDK instances tracking a "generic" task, making any task non-generic.
|
|
120
|
-
*
|
|
121
|
-
* @param {ILogger} log - Logger.
|
|
122
|
-
* @param {string} task - The task we are starting.
|
|
123
|
-
* @param {Object} collectors - The collectors map.
|
|
124
|
-
* @param {Promise} promise - (optional) The promise we are tracking.
|
|
125
|
-
* @return {Function | Promise} The stop function for this specific task or the promise received with the callbacks registered.
|
|
126
|
-
*/
|
|
127
|
-
start: function (log, task, collectors, promise, now) {
|
|
128
|
-
if (now === void 0) { now = Date.now; }
|
|
129
|
-
var taskUniqueId = (0, lang_1.uniqueId)();
|
|
130
|
-
var taskCollector = getCollectorForTask(task, collectors);
|
|
131
|
-
var result;
|
|
132
|
-
// If we are registering a promise with this task, we should count the status and the exceptions as well
|
|
133
|
-
// as stopping the task when the promise resolves. Then return the promise
|
|
134
|
-
if ((0, thenable_1.thenable)(promise)) {
|
|
135
|
-
result = this.__attachToPromise(log, promise, task, taskCollector, taskUniqueId);
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
// If not, we return the stop function, as it will be stopped manually.
|
|
139
|
-
result = this.stop.bind(this, log, task, taskUniqueId);
|
|
140
|
-
if (CALLBACKS[task] && !taskCollector) {
|
|
141
|
-
// and provide a way for a defered setup of the collector, if needed.
|
|
142
|
-
// @ts-expect-error
|
|
143
|
-
result.setCollectorForTask = this.setCollectorForTask.bind(this, task, taskUniqueId);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
// We start the timer, with an uniqueId attached to it's name, and save tracking info for this task.
|
|
147
|
-
var trackingKey = generateTimerKey(task, taskUniqueId);
|
|
148
|
-
var cb = getCallbackForTask(task, taskCollector);
|
|
149
|
-
timers[trackingKey] = {
|
|
150
|
-
cb: cb,
|
|
151
|
-
timer: (0, timer_1.timer)(now)
|
|
152
|
-
};
|
|
153
|
-
return result;
|
|
154
|
-
},
|
|
155
|
-
/**
|
|
156
|
-
* Setup the collector for a task that reports metrics.
|
|
157
|
-
*
|
|
158
|
-
* @param {string} task - The task name
|
|
159
|
-
* @param {number | string} taskUniqueId - The unique identifier for this task
|
|
160
|
-
* @param {Object} collectors - The collectors map.
|
|
161
|
-
*/
|
|
162
|
-
setCollectorForTask: function (task, taskUniqueId, collectors) {
|
|
163
|
-
var taskCollector = getCollectorForTask(task, collectors);
|
|
164
|
-
if (taskCollector) {
|
|
165
|
-
var trackingKey = generateTimerKey(task, taskUniqueId);
|
|
166
|
-
timers[trackingKey].cb = getCallbackForTask(task, taskCollector);
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
/**
|
|
170
|
-
* Stops the tracking of a given task.
|
|
171
|
-
*
|
|
172
|
-
* @param {ILogger} log - Logger.
|
|
173
|
-
* @param {string} task - The task we are starting.
|
|
174
|
-
* @param {number | string} modifier - (optional) The modifier for that specific task.
|
|
175
|
-
*/
|
|
176
|
-
stop: function (log, task, modifier) {
|
|
177
|
-
var timerName = generateTimerKey(task, modifier);
|
|
178
|
-
var timerData = timers[timerName];
|
|
179
|
-
if (timerData) {
|
|
180
|
-
// Stop the timer and round result for readability.
|
|
181
|
-
var et = timerData.timer();
|
|
182
|
-
log.debug("[TIME TRACKER]: [" + task + "] took " + et + "ms to finish.");
|
|
183
|
-
// Check if we have a tracker callback.
|
|
184
|
-
if (timerData.cb) {
|
|
185
|
-
// If we have a callback, we call it with the elapsed time of the task and then delete the reference.
|
|
186
|
-
timerData.cb(et);
|
|
187
|
-
}
|
|
188
|
-
// Remove the task tracking reference.
|
|
189
|
-
delete timers[timerName];
|
|
190
|
-
return et;
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
/**
|
|
194
|
-
* The constants shortcut for the task names.
|
|
195
|
-
*/
|
|
196
|
-
TaskNames: CONSTANTS
|
|
197
|
-
};
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
var _a;
|
|
2
|
-
import { uniqueId } from '../lang';
|
|
3
|
-
import { timer } from './timer';
|
|
4
|
-
import { thenable } from '../promise/thenable';
|
|
5
|
-
// Map we will use for storing timers data
|
|
6
|
-
var timers = {};
|
|
7
|
-
// Tasks constants
|
|
8
|
-
var CONSTANTS = {
|
|
9
|
-
SDK_READY: 'Getting ready - Split SDK',
|
|
10
|
-
SDK_GET_TREATMENT: 'SDK - Get Treatment',
|
|
11
|
-
SDK_GET_TREATMENTS: 'SDK - Get Treatments',
|
|
12
|
-
SDK_GET_TREATMENT_WITH_CONFIG: 'SDK - Get Treatment with config',
|
|
13
|
-
SDK_GET_TREATMENTS_WITH_CONFIG: 'SDK - Get Treatments with config',
|
|
14
|
-
SPLITS_READY: 'Getting ready - Splits',
|
|
15
|
-
SEGMENTS_READY: 'Getting ready - Segments',
|
|
16
|
-
METRICS_PUSH: 'Pushing - Metrics',
|
|
17
|
-
IMPRESSIONS_PUSH: 'Pushing - Impressions',
|
|
18
|
-
EVENTS_PUSH: 'Pushing - Events',
|
|
19
|
-
MY_SEGMENTS_FETCH: 'Fetching - My Segments',
|
|
20
|
-
SEGMENTS_FETCH: 'Fetching - Segments',
|
|
21
|
-
SPLITS_FETCH: 'Fetching - Splits'
|
|
22
|
-
};
|
|
23
|
-
// Tasks callbacks, if any
|
|
24
|
-
var CALLBACKS = (_a = {},
|
|
25
|
-
_a[CONSTANTS.SDK_READY] = {
|
|
26
|
-
collector: 'client',
|
|
27
|
-
method: 'ready'
|
|
28
|
-
},
|
|
29
|
-
_a[CONSTANTS.SDK_GET_TREATMENT] = {
|
|
30
|
-
collector: 'client',
|
|
31
|
-
method: 'getTreatment'
|
|
32
|
-
},
|
|
33
|
-
_a[CONSTANTS.SDK_GET_TREATMENTS] = {
|
|
34
|
-
collector: 'client',
|
|
35
|
-
method: 'getTreatments'
|
|
36
|
-
},
|
|
37
|
-
_a[CONSTANTS.SDK_GET_TREATMENT_WITH_CONFIG] = {
|
|
38
|
-
collector: 'client',
|
|
39
|
-
method: 'getTreatmentWithConfig'
|
|
40
|
-
},
|
|
41
|
-
_a[CONSTANTS.SDK_GET_TREATMENTS_WITH_CONFIG] = {
|
|
42
|
-
collector: 'client',
|
|
43
|
-
method: 'getTreatmentsWithConfig'
|
|
44
|
-
},
|
|
45
|
-
_a[CONSTANTS.MY_SEGMENTS_FETCH] = {
|
|
46
|
-
collector: 'mySegments',
|
|
47
|
-
method: 'latency'
|
|
48
|
-
},
|
|
49
|
-
_a[CONSTANTS.SEGMENTS_FETCH] = {
|
|
50
|
-
collector: 'segmentChanges',
|
|
51
|
-
method: 'latency'
|
|
52
|
-
},
|
|
53
|
-
_a[CONSTANTS.SPLITS_FETCH] = {
|
|
54
|
-
collector: 'splitChanges',
|
|
55
|
-
method: 'latency'
|
|
56
|
-
},
|
|
57
|
-
_a);
|
|
58
|
-
/**
|
|
59
|
-
* Generates the timer keys using the task name and a modifier, if any.
|
|
60
|
-
* @param {string} task - The task name
|
|
61
|
-
* @param {number | string} modifier - (optional) The modifier, if any.
|
|
62
|
-
* @return {string} The generated timer key
|
|
63
|
-
*/
|
|
64
|
-
function generateTimerKey(task, modifier) { return modifier ? task + modifier : task; }
|
|
65
|
-
/**
|
|
66
|
-
* Given the collectors map, it returns the specific collector for a given task.
|
|
67
|
-
*
|
|
68
|
-
* @param {string} task - The task name
|
|
69
|
-
* @param {Object} collectors - The collectors map
|
|
70
|
-
*/
|
|
71
|
-
function getCollectorForTask(task, collectors) {
|
|
72
|
-
var callbackData = CALLBACKS[task];
|
|
73
|
-
if (callbackData && collectors)
|
|
74
|
-
return collectors[callbackData.collector];
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Given a collector and a task, returns the callback function that should be called when we stop the timer.
|
|
79
|
-
*
|
|
80
|
-
* @param {string} task - The task name
|
|
81
|
-
* @param {Object} collector - The collector object for the task
|
|
82
|
-
*/
|
|
83
|
-
function getCallbackForTask(task, collector) {
|
|
84
|
-
var callbackData = CALLBACKS[task];
|
|
85
|
-
if (callbackData && collector)
|
|
86
|
-
return collector[callbackData.method];
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
// Our "time tracker" API
|
|
90
|
-
export var TrackerAPI = {
|
|
91
|
-
/**
|
|
92
|
-
* "Private" method, used to attach count/countException and stop callbacks to a promise.
|
|
93
|
-
*
|
|
94
|
-
* @param {ILogger} log - Logger.
|
|
95
|
-
* @param {Promise} promise - The promise we want to attach the callbacks.
|
|
96
|
-
* @param {string} task - The name of the task.
|
|
97
|
-
* @param {number | string} modifier - (optional) The modifier for the task, if any.
|
|
98
|
-
*/
|
|
99
|
-
__attachToPromise: function (log, promise, task, collector, modifier) {
|
|
100
|
-
var _this = this;
|
|
101
|
-
return promise.then(function (resp) {
|
|
102
|
-
_this.stop(log, task, modifier);
|
|
103
|
-
if (collector && collector.count)
|
|
104
|
-
collector.count(resp.status);
|
|
105
|
-
return resp;
|
|
106
|
-
})
|
|
107
|
-
.catch(function (err) {
|
|
108
|
-
_this.stop(log, task, modifier);
|
|
109
|
-
if (collector && collector.countException)
|
|
110
|
-
collector.countException();
|
|
111
|
-
throw err;
|
|
112
|
-
});
|
|
113
|
-
},
|
|
114
|
-
/**
|
|
115
|
-
* Starts tracking the time for a given task. All tasks tracked are considered "unique" because
|
|
116
|
-
* there may be multiple SDK instances tracking a "generic" task, making any task non-generic.
|
|
117
|
-
*
|
|
118
|
-
* @param {ILogger} log - Logger.
|
|
119
|
-
* @param {string} task - The task we are starting.
|
|
120
|
-
* @param {Object} collectors - The collectors map.
|
|
121
|
-
* @param {Promise} promise - (optional) The promise we are tracking.
|
|
122
|
-
* @return {Function | Promise} The stop function for this specific task or the promise received with the callbacks registered.
|
|
123
|
-
*/
|
|
124
|
-
start: function (log, task, collectors, promise, now) {
|
|
125
|
-
if (now === void 0) { now = Date.now; }
|
|
126
|
-
var taskUniqueId = uniqueId();
|
|
127
|
-
var taskCollector = getCollectorForTask(task, collectors);
|
|
128
|
-
var result;
|
|
129
|
-
// If we are registering a promise with this task, we should count the status and the exceptions as well
|
|
130
|
-
// as stopping the task when the promise resolves. Then return the promise
|
|
131
|
-
if (thenable(promise)) {
|
|
132
|
-
result = this.__attachToPromise(log, promise, task, taskCollector, taskUniqueId);
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
// If not, we return the stop function, as it will be stopped manually.
|
|
136
|
-
result = this.stop.bind(this, log, task, taskUniqueId);
|
|
137
|
-
if (CALLBACKS[task] && !taskCollector) {
|
|
138
|
-
// and provide a way for a defered setup of the collector, if needed.
|
|
139
|
-
// @ts-expect-error
|
|
140
|
-
result.setCollectorForTask = this.setCollectorForTask.bind(this, task, taskUniqueId);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
// We start the timer, with an uniqueId attached to it's name, and save tracking info for this task.
|
|
144
|
-
var trackingKey = generateTimerKey(task, taskUniqueId);
|
|
145
|
-
var cb = getCallbackForTask(task, taskCollector);
|
|
146
|
-
timers[trackingKey] = {
|
|
147
|
-
cb: cb,
|
|
148
|
-
timer: timer(now)
|
|
149
|
-
};
|
|
150
|
-
return result;
|
|
151
|
-
},
|
|
152
|
-
/**
|
|
153
|
-
* Setup the collector for a task that reports metrics.
|
|
154
|
-
*
|
|
155
|
-
* @param {string} task - The task name
|
|
156
|
-
* @param {number | string} taskUniqueId - The unique identifier for this task
|
|
157
|
-
* @param {Object} collectors - The collectors map.
|
|
158
|
-
*/
|
|
159
|
-
setCollectorForTask: function (task, taskUniqueId, collectors) {
|
|
160
|
-
var taskCollector = getCollectorForTask(task, collectors);
|
|
161
|
-
if (taskCollector) {
|
|
162
|
-
var trackingKey = generateTimerKey(task, taskUniqueId);
|
|
163
|
-
timers[trackingKey].cb = getCallbackForTask(task, taskCollector);
|
|
164
|
-
}
|
|
165
|
-
},
|
|
166
|
-
/**
|
|
167
|
-
* Stops the tracking of a given task.
|
|
168
|
-
*
|
|
169
|
-
* @param {ILogger} log - Logger.
|
|
170
|
-
* @param {string} task - The task we are starting.
|
|
171
|
-
* @param {number | string} modifier - (optional) The modifier for that specific task.
|
|
172
|
-
*/
|
|
173
|
-
stop: function (log, task, modifier) {
|
|
174
|
-
var timerName = generateTimerKey(task, modifier);
|
|
175
|
-
var timerData = timers[timerName];
|
|
176
|
-
if (timerData) {
|
|
177
|
-
// Stop the timer and round result for readability.
|
|
178
|
-
var et = timerData.timer();
|
|
179
|
-
log.debug("[TIME TRACKER]: [" + task + "] took " + et + "ms to finish.");
|
|
180
|
-
// Check if we have a tracker callback.
|
|
181
|
-
if (timerData.cb) {
|
|
182
|
-
// If we have a callback, we call it with the elapsed time of the task and then delete the reference.
|
|
183
|
-
timerData.cb(et);
|
|
184
|
-
}
|
|
185
|
-
// Remove the task tracking reference.
|
|
186
|
-
delete timers[timerName];
|
|
187
|
-
return et;
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
/**
|
|
191
|
-
* The constants shortcut for the task names.
|
|
192
|
-
*/
|
|
193
|
-
TaskNames: CONSTANTS
|
|
194
|
-
};
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import { uniqueId } from '../lang';
|
|
2
|
-
import { timer } from './timer';
|
|
3
|
-
import { thenable } from '../promise/thenable';
|
|
4
|
-
import { ILogger } from '../../logger/types';
|
|
5
|
-
import { IResponse } from '../../services/types';
|
|
6
|
-
|
|
7
|
-
// Based on ProducerMetricsCollector and ClientCollector classes
|
|
8
|
-
interface MetricsCollector {
|
|
9
|
-
// ProducerMetricsCollector API
|
|
10
|
-
countException(): void,
|
|
11
|
-
count(status: number): void,
|
|
12
|
-
latency(ms: number): void,
|
|
13
|
-
|
|
14
|
-
// ClientCollector API
|
|
15
|
-
ready(ms: number): void,
|
|
16
|
-
getTreatment(ms: number): void,
|
|
17
|
-
getTreatments(ms: number): void,
|
|
18
|
-
getTreatmentWithConfig(ms: number): void,
|
|
19
|
-
getTreatmentsWithConfig(ms: number): void,
|
|
20
|
-
|
|
21
|
-
[method: string]: (ms: number) => void,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Map we will use for storing timers data
|
|
25
|
-
const timers: Record<string, {
|
|
26
|
-
cb: false | ((et: number) => void),
|
|
27
|
-
timer: () => number
|
|
28
|
-
}> = {};
|
|
29
|
-
|
|
30
|
-
// Tasks constants
|
|
31
|
-
const CONSTANTS = {
|
|
32
|
-
SDK_READY: 'Getting ready - Split SDK',
|
|
33
|
-
SDK_GET_TREATMENT: 'SDK - Get Treatment',
|
|
34
|
-
SDK_GET_TREATMENTS: 'SDK - Get Treatments',
|
|
35
|
-
SDK_GET_TREATMENT_WITH_CONFIG: 'SDK - Get Treatment with config',
|
|
36
|
-
SDK_GET_TREATMENTS_WITH_CONFIG: 'SDK - Get Treatments with config',
|
|
37
|
-
SPLITS_READY: 'Getting ready - Splits',
|
|
38
|
-
SEGMENTS_READY: 'Getting ready - Segments',
|
|
39
|
-
METRICS_PUSH: 'Pushing - Metrics',
|
|
40
|
-
IMPRESSIONS_PUSH: 'Pushing - Impressions',
|
|
41
|
-
EVENTS_PUSH: 'Pushing - Events',
|
|
42
|
-
MY_SEGMENTS_FETCH: 'Fetching - My Segments',
|
|
43
|
-
SEGMENTS_FETCH: 'Fetching - Segments',
|
|
44
|
-
SPLITS_FETCH: 'Fetching - Splits'
|
|
45
|
-
};
|
|
46
|
-
// Tasks callbacks, if any
|
|
47
|
-
const CALLBACKS = {
|
|
48
|
-
[CONSTANTS.SDK_READY]: {
|
|
49
|
-
collector: 'client',
|
|
50
|
-
method: 'ready'
|
|
51
|
-
},
|
|
52
|
-
[CONSTANTS.SDK_GET_TREATMENT]: {
|
|
53
|
-
collector: 'client',
|
|
54
|
-
method: 'getTreatment'
|
|
55
|
-
},
|
|
56
|
-
[CONSTANTS.SDK_GET_TREATMENTS]: {
|
|
57
|
-
collector: 'client',
|
|
58
|
-
method: 'getTreatments'
|
|
59
|
-
},
|
|
60
|
-
[CONSTANTS.SDK_GET_TREATMENT_WITH_CONFIG]: {
|
|
61
|
-
collector: 'client',
|
|
62
|
-
method: 'getTreatmentWithConfig'
|
|
63
|
-
},
|
|
64
|
-
[CONSTANTS.SDK_GET_TREATMENTS_WITH_CONFIG]: {
|
|
65
|
-
collector: 'client',
|
|
66
|
-
method: 'getTreatmentsWithConfig'
|
|
67
|
-
},
|
|
68
|
-
[CONSTANTS.MY_SEGMENTS_FETCH]: {
|
|
69
|
-
collector: 'mySegments',
|
|
70
|
-
method: 'latency'
|
|
71
|
-
},
|
|
72
|
-
[CONSTANTS.SEGMENTS_FETCH]: {
|
|
73
|
-
collector: 'segmentChanges',
|
|
74
|
-
method: 'latency'
|
|
75
|
-
},
|
|
76
|
-
[CONSTANTS.SPLITS_FETCH]: {
|
|
77
|
-
collector: 'splitChanges',
|
|
78
|
-
method: 'latency'
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* Generates the timer keys using the task name and a modifier, if any.
|
|
83
|
-
* @param {string} task - The task name
|
|
84
|
-
* @param {number | string} modifier - (optional) The modifier, if any.
|
|
85
|
-
* @return {string} The generated timer key
|
|
86
|
-
*/
|
|
87
|
-
function generateTimerKey(task: string, modifier?: number | string) { return modifier ? task + modifier : task; }
|
|
88
|
-
/**
|
|
89
|
-
* Given the collectors map, it returns the specific collector for a given task.
|
|
90
|
-
*
|
|
91
|
-
* @param {string} task - The task name
|
|
92
|
-
* @param {Object} collectors - The collectors map
|
|
93
|
-
*/
|
|
94
|
-
function getCollectorForTask(task: string, collectors?: Record<string, MetricsCollector>): false | MetricsCollector {
|
|
95
|
-
const callbackData = CALLBACKS[task];
|
|
96
|
-
|
|
97
|
-
if (callbackData && collectors) return collectors[callbackData.collector];
|
|
98
|
-
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Given a collector and a task, returns the callback function that should be called when we stop the timer.
|
|
103
|
-
*
|
|
104
|
-
* @param {string} task - The task name
|
|
105
|
-
* @param {Object} collector - The collector object for the task
|
|
106
|
-
*/
|
|
107
|
-
function getCallbackForTask(task: string, collector: MetricsCollector | false): ((ms: number) => void) | false {
|
|
108
|
-
const callbackData = CALLBACKS[task];
|
|
109
|
-
|
|
110
|
-
if (callbackData && collector) return collector[callbackData.method];
|
|
111
|
-
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Our "time tracker" API
|
|
116
|
-
export const TrackerAPI = {
|
|
117
|
-
/**
|
|
118
|
-
* "Private" method, used to attach count/countException and stop callbacks to a promise.
|
|
119
|
-
*
|
|
120
|
-
* @param {ILogger} log - Logger.
|
|
121
|
-
* @param {Promise} promise - The promise we want to attach the callbacks.
|
|
122
|
-
* @param {string} task - The name of the task.
|
|
123
|
-
* @param {number | string} modifier - (optional) The modifier for the task, if any.
|
|
124
|
-
*/
|
|
125
|
-
__attachToPromise(log: ILogger, promise: Promise<IResponse>, task: string, collector: false | MetricsCollector, modifier?: number | string) {
|
|
126
|
-
return promise.then(resp => {
|
|
127
|
-
this.stop(log, task, modifier);
|
|
128
|
-
|
|
129
|
-
if (collector && collector.count) collector.count(resp.status);
|
|
130
|
-
|
|
131
|
-
return resp;
|
|
132
|
-
})
|
|
133
|
-
.catch(err => {
|
|
134
|
-
this.stop(log, task, modifier);
|
|
135
|
-
|
|
136
|
-
if (collector && collector.countException) collector.countException();
|
|
137
|
-
|
|
138
|
-
throw err;
|
|
139
|
-
});
|
|
140
|
-
},
|
|
141
|
-
/**
|
|
142
|
-
* Starts tracking the time for a given task. All tasks tracked are considered "unique" because
|
|
143
|
-
* there may be multiple SDK instances tracking a "generic" task, making any task non-generic.
|
|
144
|
-
*
|
|
145
|
-
* @param {ILogger} log - Logger.
|
|
146
|
-
* @param {string} task - The task we are starting.
|
|
147
|
-
* @param {Object} collectors - The collectors map.
|
|
148
|
-
* @param {Promise} promise - (optional) The promise we are tracking.
|
|
149
|
-
* @return {Function | Promise} The stop function for this specific task or the promise received with the callbacks registered.
|
|
150
|
-
*/
|
|
151
|
-
start(log: ILogger, task: string, collectors?: Record<string, MetricsCollector>, promise?: Promise<IResponse>, now: () => number = Date.now): Promise<IResponse> | (() => number) {
|
|
152
|
-
const taskUniqueId = uniqueId();
|
|
153
|
-
const taskCollector = getCollectorForTask(task, collectors);
|
|
154
|
-
let result;
|
|
155
|
-
|
|
156
|
-
// If we are registering a promise with this task, we should count the status and the exceptions as well
|
|
157
|
-
// as stopping the task when the promise resolves. Then return the promise
|
|
158
|
-
if (thenable(promise)) {
|
|
159
|
-
result = this.__attachToPromise(log, promise, task, taskCollector, taskUniqueId);
|
|
160
|
-
} else {
|
|
161
|
-
// If not, we return the stop function, as it will be stopped manually.
|
|
162
|
-
result = this.stop.bind(this, log, task, taskUniqueId);
|
|
163
|
-
if (CALLBACKS[task] && !taskCollector) {
|
|
164
|
-
// and provide a way for a defered setup of the collector, if needed.
|
|
165
|
-
// @ts-expect-error
|
|
166
|
-
result.setCollectorForTask = this.setCollectorForTask.bind(this, task, taskUniqueId);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// We start the timer, with an uniqueId attached to it's name, and save tracking info for this task.
|
|
171
|
-
const trackingKey = generateTimerKey(task, taskUniqueId);
|
|
172
|
-
const cb = getCallbackForTask(task, taskCollector);
|
|
173
|
-
timers[trackingKey] = {
|
|
174
|
-
cb,
|
|
175
|
-
timer: timer(now)
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
return result as () => number;
|
|
179
|
-
},
|
|
180
|
-
/**
|
|
181
|
-
* Setup the collector for a task that reports metrics.
|
|
182
|
-
*
|
|
183
|
-
* @param {string} task - The task name
|
|
184
|
-
* @param {number | string} taskUniqueId - The unique identifier for this task
|
|
185
|
-
* @param {Object} collectors - The collectors map.
|
|
186
|
-
*/
|
|
187
|
-
setCollectorForTask(task: string, taskUniqueId: number | string, collectors: Record<string, MetricsCollector>) {
|
|
188
|
-
const taskCollector = getCollectorForTask(task, collectors);
|
|
189
|
-
|
|
190
|
-
if (taskCollector) {
|
|
191
|
-
const trackingKey = generateTimerKey(task, taskUniqueId);
|
|
192
|
-
timers[trackingKey].cb = getCallbackForTask(task, taskCollector);
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
/**
|
|
196
|
-
* Stops the tracking of a given task.
|
|
197
|
-
*
|
|
198
|
-
* @param {ILogger} log - Logger.
|
|
199
|
-
* @param {string} task - The task we are starting.
|
|
200
|
-
* @param {number | string} modifier - (optional) The modifier for that specific task.
|
|
201
|
-
*/
|
|
202
|
-
stop(log: ILogger, task: string, modifier?: number | string) {
|
|
203
|
-
const timerName = generateTimerKey(task, modifier);
|
|
204
|
-
const timerData = timers[timerName];
|
|
205
|
-
if (timerData) {
|
|
206
|
-
// Stop the timer and round result for readability.
|
|
207
|
-
const et = timerData.timer();
|
|
208
|
-
log.debug(`[TIME TRACKER]: [${task}] took ${et}ms to finish.`);
|
|
209
|
-
|
|
210
|
-
// Check if we have a tracker callback.
|
|
211
|
-
if (timerData.cb) {
|
|
212
|
-
// If we have a callback, we call it with the elapsed time of the task and then delete the reference.
|
|
213
|
-
timerData.cb(et);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Remove the task tracking reference.
|
|
217
|
-
delete timers[timerName];
|
|
218
|
-
|
|
219
|
-
return et;
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
/**
|
|
223
|
-
* The constants shortcut for the task names.
|
|
224
|
-
*/
|
|
225
|
-
TaskNames: CONSTANTS
|
|
226
|
-
};
|