From 093c49f282498c6c6a1d14c6ecd7df1e9794261d Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 25 Jan 2022 18:41:14 -0300 Subject: [PATCH 1/2] implementation and UTs --- .../inMemory/TelemetryCacheInMemory.ts | 196 +++++++++++++++ .../__tests__/TelemetryCacheInMemory.spec.ts | 225 ++++++++++++++++++ src/storages/types.ts | 90 +++++-- src/sync/submitters/types.ts | 123 ++++++++++ src/utils/constants/index.ts | 27 +++ 5 files changed, 636 insertions(+), 25 deletions(-) create mode 100644 src/storages/inMemory/TelemetryCacheInMemory.ts create mode 100644 src/storages/inMemory/__tests__/TelemetryCacheInMemory.spec.ts diff --git a/src/storages/inMemory/TelemetryCacheInMemory.ts b/src/storages/inMemory/TelemetryCacheInMemory.ts new file mode 100644 index 00000000..845348b7 --- /dev/null +++ b/src/storages/inMemory/TelemetryCacheInMemory.ts @@ -0,0 +1,196 @@ +import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies } from '../../sync/submitters/types'; +import { TelemetryCacheSync } from '../types'; + +const MAX_LATENCY_BUCKET_COUNT = 23; +const MAX_STREAMING_EVENTS = 20; +const MAX_TAGS = 10; + +export class TelemetryCacheInMemory implements TelemetryCacheSync { + + private timeUntilReady?: number; + + getTimeUntilReady() { + return this.timeUntilReady; + } + + recordTimeUntilReady(ms: number) { + this.timeUntilReady = ms; + } + + private timeUntilReadyFromCache?: number; + + getTimeUntilReadyFromCache() { + return this.timeUntilReadyFromCache; + } + + recordTimeUntilReadyFromCache(ms: number) { + this.timeUntilReadyFromCache = ms; + } + + private notReadyUsage = 0; + + getNonReadyUsage() { + return this.notReadyUsage; + } + + recordNonReadyUsage() { + this.notReadyUsage++; + } + + private impressionStats = [0, 0, 0]; + + getImpressionStats(type: ImpressionDataType) { + return this.impressionStats[type]; + } + + recordImpressionStats(type: ImpressionDataType, count: number) { + this.impressionStats[type] += count; + } + + private eventStats = [0, 0]; + + getEventStats(type: EventDataType) { + return this.eventStats[type]; + } + + recordEventStats(type: EventDataType, count: number) { + this.eventStats[type] += count; + } + + // @ts-expect-error + private lastSync: LastSync = {}; + + getLastSynchronization() { + return this.lastSync; + } + + recordSuccessfulSync(resource: OperationType, timeMs: number) { + this.lastSync[resource] = timeMs; + } + + // @ts-expect-error + private httpErrors: HttpErrors = {}; + + popHttpErrors() { + const result = this.httpErrors; // @ts-expect-error + this.httpErrors = {}; + return result; + } + + recordSyncError(resource: OperationType, status: number) { + if (!this.httpErrors[resource]) this.httpErrors[resource] = {}; + if (!this.httpErrors[resource][status]) { + this.httpErrors[resource][status] = 1; + } else { + this.httpErrors[resource][status]++; + } + } + + // @ts-expect-error + private httpLatencies: HttpLatencies = {}; + + popHttpLatencies() { + const result = this.httpLatencies; // @ts-expect-error + this.httpLatencies = {}; + return result; + } + + recordSyncLatency(resource: OperationType, latencyMs: number) { + if (!this.httpLatencies[resource]) this.httpLatencies[resource] = []; + if (this.httpLatencies[resource].length < MAX_LATENCY_BUCKET_COUNT) { + this.httpLatencies[resource].push(latencyMs); + } + } + + private authRejections = 0; + + popAuthRejections() { + const result = this.authRejections; + this.authRejections = 0; + return result; + } + + recordAuthRejections() { + this.authRejections++; + } + + private tokenRefreshes = 0; + + popTokenRefreshes() { + const result = this.tokenRefreshes; + this.tokenRefreshes = 0; + return result; + } + + recordTokenRefreshes() { + this.tokenRefreshes++; + } + + private streamingEvents: StreamingEvent[] = [] + + popStreamingEvents() { + return this.streamingEvents.splice(0); + } + + recordStreamingEvents(streamingEvent: StreamingEvent) { + if (this.streamingEvents.length < MAX_STREAMING_EVENTS) { + this.streamingEvents.push(streamingEvent); + } + } + + private tags: string[] = []; + + popTags() { + return this.tags.splice(0); + } + + addTag(tag: string) { + if (this.tags.length < MAX_TAGS) { + this.tags.push(tag); + } + } + + private sessionLength?: number; + + getSessionLength() { + return this.sessionLength; + } + + recordSessionLength(ms: number) { + this.sessionLength = ms; + } + + // @ts-expect-error + private exceptions: MethodExceptions = {}; + + popExceptions() { + const result = this.exceptions; // @ts-expect-error + this.exceptions = {}; + return result; + } + + recordException(method: Method) { + if (!this.exceptions[method]) { + this.exceptions[method] = 1; + } else { + this.exceptions[method]++; + } + } + + // @ts-expect-error + private latencies: MethodLatencies = {}; + + popLatencies() { + const result = this.latencies; // @ts-expect-error + this.latencies = {}; + return result; + } + + recordLatency(method: Method, latencyMs: number) { + if (!this.latencies[method]) this.latencies[method] = []; + if (this.latencies[method].length < MAX_LATENCY_BUCKET_COUNT) { + this.latencies[method].push(latencyMs); + } + } + +} diff --git a/src/storages/inMemory/__tests__/TelemetryCacheInMemory.spec.ts b/src/storages/inMemory/__tests__/TelemetryCacheInMemory.spec.ts new file mode 100644 index 00000000..ab09141f --- /dev/null +++ b/src/storages/inMemory/__tests__/TelemetryCacheInMemory.spec.ts @@ -0,0 +1,225 @@ +import { QUEUED, DROPPED, DEDUPED, EVENTS, IMPRESSIONS, IMPRESSIONS_COUNT, MY_SEGMENT, SEGMENT, SPLITS, TELEMETRY, TOKEN, TRACK, TREATMENT, TREATMENTS, TREATMENTS_WITH_CONFIG, TREATMENT_WITH_CONFIG } from '../../../utils/constants'; +import { EventDataType, ImpressionDataType, Method, OperationType, StreamingEvent } from '../../../sync/submitters/types'; +import { TelemetryCacheInMemory } from '../TelemetryCacheInMemory'; + +const impressionDataTypes: ImpressionDataType[] = [QUEUED, DROPPED, DEDUPED]; + +const eventDataTypes: EventDataType[] = [QUEUED, DROPPED]; + +const operationTypes: OperationType[] = [ + SPLITS, + IMPRESSIONS, + IMPRESSIONS_COUNT, + EVENTS, + TELEMETRY, + TOKEN, + SEGMENT, + MY_SEGMENT +]; + +const methods: Method[] = [ + TREATMENT, + TREATMENTS, + TREATMENT_WITH_CONFIG, + TREATMENTS_WITH_CONFIG, + TRACK +]; + +describe('TELEMETRY CACHE', () => { + const cache = new TelemetryCacheInMemory(); + + test('time until ready', () => { + expect(cache.getTimeUntilReady()).toBe(undefined); + cache.recordTimeUntilReady(100); + expect(cache.getTimeUntilReady()).toBe(100); + }); + + test('time until ready from cache', () => { + expect(cache.getTimeUntilReadyFromCache()).toBe(undefined); + cache.recordTimeUntilReadyFromCache(10); + expect(cache.getTimeUntilReadyFromCache()).toBe(10); + }); + + test('session length', () => { + expect(cache.getSessionLength()).toBe(undefined); + cache.recordSessionLength(10); + expect(cache.getSessionLength()).toBe(10); + }); + + test('not ready usage', () => { + expect(cache.getNonReadyUsage()).toBe(0); + cache.recordNonReadyUsage(); + expect(cache.getNonReadyUsage()).toBe(1); + cache.recordNonReadyUsage(); + cache.recordNonReadyUsage(); + expect(cache.getNonReadyUsage()).toBe(3); + }); + + test('impression stats', () => { + impressionDataTypes.forEach((stat: ImpressionDataType) => { + expect(cache.getImpressionStats(stat)).toBe(0); + cache.recordImpressionStats(stat, 1); + expect(cache.getImpressionStats(stat)).toBe(1); + cache.recordImpressionStats(stat, 10); + expect(cache.getImpressionStats(stat)).toBe(11); + }); + }); + + test('event stats', () => { + eventDataTypes.forEach((stat: EventDataType) => { + expect(cache.getEventStats(stat)).toBe(0); + cache.recordEventStats(stat, 1); + expect(cache.getEventStats(stat)).toBe(1); + cache.recordEventStats(stat, 2); + expect(cache.getEventStats(stat)).toBe(3); + }); + }); + + test('last synchronization', () => { + expect(cache.getLastSynchronization()).toEqual({}); + operationTypes.forEach((operation, index) => { + cache.recordSuccessfulSync(operation, index); + }); + + const expectedLastSync = { 'sp': 0, 'im': 1, 'ic': 2, 'ev': 3, 'te': 4, 'to': 5, 'se': 6, 'ms': 7 }; + expect(cache.getLastSynchronization()).toEqual(expectedLastSync); + + // Overwrite a single operation + cache.recordSuccessfulSync(MY_SEGMENT, 100); + expect(cache.getLastSynchronization()).toEqual({ ...expectedLastSync, 'ms': 100 }); + }); + + test('http errors', () => { + expect(cache.popHttpErrors()).toEqual({}); + operationTypes.forEach((operation) => { + cache.recordSyncError(operation, 400); + cache.recordSyncError(operation, 400); + cache.recordSyncError(operation, 500); + }); + + const httpErrors = { '400': 2, '500': 1 }; + const expectedHttpErrors = { 'sp': httpErrors, 'im': httpErrors, 'ic': httpErrors, 'ev': httpErrors, 'te': httpErrors, 'to': httpErrors, 'se': httpErrors, 'ms': httpErrors }; + expect(cache.popHttpErrors()).toEqual(expectedHttpErrors); + expect(cache.popHttpErrors()).toEqual({}); + + // Set a single http error + cache.recordSyncError(MY_SEGMENT, 400); + expect(cache.popHttpErrors()).toEqual({ 'ms': { 400: 1 } }); + }); + + test('http latencies', () => { + expect(cache.popHttpLatencies()).toEqual({}); + operationTypes.forEach((operation) => { + cache.recordSyncLatency(operation, 300); + cache.recordSyncLatency(operation, 400); + cache.recordSyncLatency(operation, 500); + }); + + const latencies = [300, 400, 500]; + const expectedLatencies = { 'sp': latencies, 'im': latencies, 'ic': latencies, 'ev': latencies, 'te': latencies, 'to': latencies, 'se': latencies, 'ms': latencies }; + expect(cache.popHttpLatencies()).toEqual(expectedLatencies); + expect(cache.popHttpLatencies()).toEqual({}); + + // MAX_LATENCY_BUCKET_COUNT === 23 + for (let i = 0; i < 100; i++) { + cache.recordSyncLatency(MY_SEGMENT, i); + } + expect(cache.popHttpLatencies()).toEqual({ 'ms': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22] }); + expect(cache.popHttpLatencies()).toEqual({}); + }); + + test('auth rejections', () => { + expect(cache.popAuthRejections()).toBe(0); + cache.recordAuthRejections(); + expect(cache.popAuthRejections()).toBe(1); + expect(cache.popAuthRejections()).toBe(0); + cache.recordAuthRejections(); + cache.recordAuthRejections(); + expect(cache.popAuthRejections()).toBe(2); + expect(cache.popAuthRejections()).toBe(0); + }); + + test('token refreshes', () => { + expect(cache.popTokenRefreshes()).toBe(0); + cache.recordTokenRefreshes(); + expect(cache.popTokenRefreshes()).toBe(1); + expect(cache.popTokenRefreshes()).toBe(0); + cache.recordTokenRefreshes(); + cache.recordTokenRefreshes(); + expect(cache.popTokenRefreshes()).toBe(2); + expect(cache.popTokenRefreshes()).toBe(0); + }); + + test('streaming events', () => { + const streamingEvent: StreamingEvent = { e: 10, d: 2, t: 3 }; + + expect(cache.popStreamingEvents()).toEqual([]); + cache.recordStreamingEvents(streamingEvent); + expect(cache.popStreamingEvents()).toEqual([streamingEvent]); + expect(cache.popStreamingEvents()).toEqual([]); + + // MAX_STREAMING_EVENTS === 20 + for (let i = 0; i < 100; i++) { + cache.recordStreamingEvents({ ...streamingEvent, t: i }); + } + const actualStreamingEvents = cache.popStreamingEvents(); + expect(actualStreamingEvents.length).toBe(20); + actualStreamingEvents.forEach((actualStreamingEvent, index) => { + expect(actualStreamingEvent).toEqual({ ...streamingEvent, t: index }); + }); + expect(cache.popStreamingEvents()).toEqual([]); + }); + + test('tags', () => { + expect(cache.popTags()).toEqual([]); + cache.addTag('MY_TAG'); + expect(cache.popTags()).toEqual(['MY_TAG']); + expect(cache.popTags()).toEqual([]); + + // MAX_TAGS === 10 + for (let i = 0; i < 100; i++) { + cache.addTag('TAG_' + i); + } + expect(cache.popTags()).toEqual(['TAG_0', 'TAG_1', 'TAG_2', 'TAG_3', 'TAG_4', 'TAG_5', 'TAG_6', 'TAG_7', 'TAG_8', 'TAG_9']); + expect(cache.popTags()).toEqual([]); + }); + + + test('method exceptions', () => { + expect(cache.popExceptions()).toEqual({}); + methods.forEach((method) => { + cache.recordException(method); + cache.recordException(method); + }); + + const expectedExceptions = { 't': 2, 'ts': 2, 'tc': 2, 'tcs': 2, 'tr': 2 }; + expect(cache.popExceptions()).toEqual(expectedExceptions); + expect(cache.popExceptions()).toEqual({}); + + // Set a single method exception error + cache.recordException(TRACK); + expect(cache.popExceptions()).toEqual({ 'tr': 1 }); + }); + + test('method latencies', () => { + expect(cache.popLatencies()).toEqual({}); + methods.forEach((method) => { + cache.recordLatency(method, 300); + cache.recordLatency(method, 400); + cache.recordLatency(method, 500); + }); + + const latencies = [300, 400, 500]; + const expectedLatencies = { 't': latencies, 'ts': latencies, 'tc': latencies, 'tcs': latencies, 'tr': latencies }; + expect(cache.popLatencies()).toEqual(expectedLatencies); + expect(cache.popLatencies()).toEqual({}); + + // MAX_LATENCY_BUCKET_COUNT === 23 + for (let i = 0; i < 100; i++) { + cache.recordLatency(TRACK, i); + } + expect(cache.popLatencies()).toEqual({ 'tr': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22] }); + expect(cache.popLatencies()).toEqual({}); + }); + +}); diff --git a/src/storages/types.ts b/src/storages/types.ts index 0e3a6001..7285616f 100644 --- a/src/storages/types.ts +++ b/src/storages/types.ts @@ -1,6 +1,6 @@ import { MaybeThenable, IMetadata, ISplitFiltersValidation } from '../dtos/types'; import { ILogger } from '../logger/types'; -import { StoredEventWithMetadata, StoredImpressionWithMetadata } from '../sync/submitters/types'; +import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent } from '../sync/submitters/types'; import { SplitIO, ImpressionDTO, SDKMode } from '../types'; /** @@ -351,29 +351,73 @@ export interface IImpressionCountsCacheSync extends IRecorderCacheProducerSync> { - track(metricName: string, latency: number): boolean - isEmpty(): boolean - clear(): void - state(): Record +export interface TelemetryInitConsumerSync { + getTimeUntilReady(): number | undefined; + getTimeUntilReadyFromCache(): number | undefined; + getNonReadyUsage(): number; + // 'active factories' and 'redundant factories' are not tracked in the storage. They are derived from `usedKeysMap` } -export interface ILatenciesCacheAsync { - track(metricName: string, latency: number): Promise +export interface TelemetryRuntimeConsumerSync { + getImpressionStats(type: ImpressionDataType): number; + getEventStats(type: EventDataType): number; + getLastSynchronization(): LastSync; + popHttpErrors(): HttpErrors; + popHttpLatencies(): HttpLatencies; + popAuthRejections(): number; + popTokenRefreshes(): number; + popStreamingEvents(): Array; + popTags(): Array | undefined; + getSessionLength(): number | undefined; } -export interface ICountsCacheSync extends IRecorderCacheProducerSync> { - track(metricName: string): boolean - isEmpty(): boolean - clear(): void - state(): Record +export interface TelemetryEvaluationConsumerSync { + popExceptions(): MethodExceptions; + popLatencies(): MethodLatencies; +} + +export interface TelemetryStorageConsumerSync extends TelemetryInitConsumerSync, TelemetryRuntimeConsumerSync, TelemetryEvaluationConsumerSync { } + +export interface TelemetryInitProducerSync { + recordTimeUntilReady(ms: number): void; + recordTimeUntilReadyFromCache(ms: number): void; + recordNonReadyUsage(): void; + // 'active factories' and 'redundant factories' are not tracked in the storage. They are derived from `usedKeysMap` } -export interface ICountsCacheAsync { - track(metricName: string): Promise +export interface TelemetryRuntimeProducerSync { + addTag(tag: string): void; + recordImpressionStats(type: ImpressionDataType, count: number): void; + recordEventStats(type: EventDataType, count: number): void; + recordSuccessfulSync(resource: OperationType, timeMs: number): void; + recordSyncError(resource: OperationType, status: number): void; + recordSyncLatency(resource: OperationType, latencyMs: number): void; + recordAuthRejections(): void; + recordTokenRefreshes(): void; + recordStreamingEvents(streamingEvent: StreamingEvent): void; + recordSessionLength(ms: number): void; +} + +export interface TelemetryEvaluationProducerSync { + recordLatency(method: Method, latencyMs: number): void; + recordException(method: Method): void; +} + +export interface TelemetryStorageProducerSync extends TelemetryInitProducerSync, TelemetryRuntimeProducerSync, TelemetryEvaluationProducerSync { } + +export interface TelemetryCacheSync extends TelemetryStorageConsumerSync, TelemetryStorageProducerSync { } + +/** + * Telemetry storage interface for consumer mode. + * Methods are async because data is stored in Redis or a pluggable storage. + */ +export interface TelemetryCacheAsync { + // @TODO } /** @@ -385,16 +429,14 @@ export interface IStorageBase< TSegmentsCache extends ISegmentsCacheBase, TImpressionsCache extends IImpressionsCacheBase, TEventsCache extends IEventsCacheBase, - TLatenciesCache extends ILatenciesCacheSync | ILatenciesCacheAsync, - TCountsCache extends ICountsCacheSync | ICountsCacheAsync, + TTelemetryCache extends TelemetryCacheSync | TelemetryCacheAsync > { splits: TSplitsCache, segments: TSegmentsCache, impressions: TImpressionsCache, impressionCounts?: IImpressionCountsCacheSync, events: TEventsCache, - latencies?: TLatenciesCache, - counts?: TCountsCache, + telemetry?: TTelemetryCache, destroy(): void | Promise, shared?: (matchingKey: string, onReadyCb: (error?: any) => void) => this } @@ -404,8 +446,7 @@ export type IStorageSync = IStorageBase< ISegmentsCacheSync, IImpressionsCacheSync, IEventsCacheSync, - ILatenciesCacheSync, - ICountsCacheSync + TelemetryCacheSync > export type IStorageAsync = IStorageBase< @@ -413,8 +454,7 @@ export type IStorageAsync = IStorageBase< ISegmentsCacheAsync, IImpressionsCacheAsync | IImpressionsCacheSync, IEventsCacheAsync | IEventsCacheSync, - ILatenciesCacheAsync, - ICountsCacheAsync + TelemetryCacheAsync | TelemetryCacheSync > /** StorageFactory */ diff --git a/src/sync/submitters/types.ts b/src/sync/submitters/types.ts index 6ab697c1..695c145d 100644 --- a/src/sync/submitters/types.ts +++ b/src/sync/submitters/types.ts @@ -62,3 +62,126 @@ export type StoredEventWithMetadata = { /** Stored event */ e: SplitIO.EventData } + +/** + * Telemetry usage stats + */ + +export type QUEUED = 0; +export type DROPPED = 1; +export type DEDUPED = 2; +export type ImpressionDataType = QUEUED | DROPPED | DEDUPED +export type EventDataType = QUEUED | DROPPED; + +export type SPLITS = 'sp'; +export type IMPRESSIONS = 'im'; +export type IMPRESSIONS_COUNT = 'ic'; +export type EVENTS = 'ev'; +export type TELEMETRY = 'te'; +export type TOKEN = 'to'; +export type SEGMENT = 'se'; +export type MY_SEGMENT = 'ms'; +export type OperationType = SPLITS | IMPRESSIONS | IMPRESSIONS_COUNT | EVENTS | TELEMETRY | TOKEN | SEGMENT | MY_SEGMENT; + +export type LastSync = Record +export type HttpErrors = Record +export type HttpLatencies = Record> + +export type TREATMENT = 't'; +export type TREATMENTS = 'ts'; +export type TREATMENT_WITH_CONFIG = 'tc'; +export type TREATMENTS_WITH_CONFIG = 'tcs'; +export type TRACK = 'tr'; +export type Method = TREATMENT | TREATMENTS | TREATMENT_WITH_CONFIG | TREATMENTS_WITH_CONFIG | TRACK; + +export type MethodLatencies = Record>; + +export type MethodExceptions = Record; + +export type CONNECTION_ESTABLISHED = 0; +export type OCCUPANCY_PRI = 10; +export type OCCUPANCY_SEC = 20; +export type STREAMING_STATUS = 30; +export type SSE_CONNECTION_ERROR = 40; +export type TOKEN_REFRESH = 50; +export type ABLY_ERROR = 60; +export type SYNC_MODE_UPDATE = 70; +export type EventType = CONNECTION_ESTABLISHED | OCCUPANCY_PRI | OCCUPANCY_SEC | STREAMING_STATUS | SSE_CONNECTION_ERROR | TOKEN_REFRESH | ABLY_ERROR | SYNC_MODE_UPDATE; + +export type StreamingEvent = { + e: EventType, // eventType + d: number, // eventData + t: number, // timestamp +} + +// 'metrics/usage' JSON request body +export type TelemetryUsageStatsPayload = { + lS: LastSync, // lastSynchronization + mL: MethodLatencies, // clientMethodLatencies + mE: MethodExceptions, // methodExceptions + hE: HttpErrors, // httpErrors + hL: HttpLatencies, // httpLatencies + tR: number, // tokenRefreshes + aR: number, // authRejections + iQ: number, // impressionsQueued + iDe: number, // impressionsDeduped + iDr: number, // impressionsDropped + spC: number, // splitCount + seC: number, // segmentCount + skC: number, // segmentKeyCount + sL: number, // sessionLengthMs + eQ: number, // eventsQueued + eD: number, // eventsDropped + sE: Array, // streamingEvents + t?: Array, // tags +} + +/** + * Telemetry config stats + */ + +export type STANDALONE_ENUM = 0; +export type CONSUMER_ENUM = 1; +export type CONSUMER_PARTIAL_ENUM = 2; +export type OperationMode = STANDALONE_ENUM | CONSUMER_ENUM | CONSUMER_PARTIAL_ENUM + +export type OPTIMIZED_ENUM = 0; +export type DEBUG_ENUM = 1; +export type ImpressionsMode = OPTIMIZED_ENUM | DEBUG_ENUM; + +export type RefreshRates = { + sp: number, // splits + se: number, // mySegments + im: number, // impressions + ev: number, // events + te: number, // telemetry +} + +export type UrlOverrides = { + s: boolean, // sdkUrl + e: boolean, // events + a: boolean, // auth + st: boolean, // stream + t: boolean, // telemetry +} + +// 'metrics/config' JSON request body +export type TelemetryConfigStatsPayload = { + oM?: OperationMode, // operationMode + st: 'memory' | 'redis' | 'pluggable' | 'localstorage', // storage + sE: boolean, // streamingEnabled + rR: RefreshRates, // refreshRates + uO: UrlOverrides, // urlOverrides + iQ: number, // impressionsQueueSize + eQ: number, // eventsQueueSize + iM: ImpressionsMode, // impressionsMode + iL: boolean, // impressionsListenerEnabled + hP: boolean, // httpProxyDetected + aF: number, // activeFactories + rF: number, // redundantActiveFactories + tR: number, // timeUntilSDKReady + tC: number, // timeUntilSDKReadyFromCache + nR: number, // SDKNotReadyUsage + t?: Array, // tags + i?: Array, // integrations +} diff --git a/src/utils/constants/index.ts b/src/utils/constants/index.ts index 4a4d8303..56fdddff 100644 --- a/src/utils/constants/index.ts +++ b/src/utils/constants/index.ts @@ -32,3 +32,30 @@ export const STORAGE_MEMORY: StorageType = 'MEMORY'; export const STORAGE_LOCALSTORAGE: StorageType = 'LOCALSTORAGE'; export const STORAGE_REDIS: StorageType = 'REDIS'; export const STORAGE_PLUGGABLE: StorageType = 'PLUGGABLE'; + +// Telemetry +export const QUEUED = 0; +export const DROPPED = 1; +export const DEDUPED = 2; + +export const STANDALONE_ENUM = 0; +export const CONSUMER_ENUM = 1; +export const CONSUMER_PARTIAL_ENUM = 2; + +export const OPTIMIZED_ENUM = 0; +export const DEBUG_ENUM = 1; + +export const SPLITS = 'sp'; +export const IMPRESSIONS = 'im'; +export const IMPRESSIONS_COUNT = 'ic'; +export const EVENTS = 'ev'; +export const TELEMETRY = 'te'; +export const TOKEN = 'to'; +export const SEGMENT = 'se'; +export const MY_SEGMENT = 'ms'; + +export const TREATMENT = 't'; +export const TREATMENTS = 'ts'; +export const TREATMENT_WITH_CONFIG = 'tc'; +export const TREATMENTS_WITH_CONFIG = 'tcs'; +export const TRACK = 'tr'; From 6ff0ad899f52e9cc037481d3c94325c6f610ae64 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 25 Jan 2022 18:47:54 -0300 Subject: [PATCH 2/2] fixed ut utils --- src/storages/__tests__/testUtils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/storages/__tests__/testUtils.ts b/src/storages/__tests__/testUtils.ts index 4905adb2..520dba1d 100644 --- a/src/storages/__tests__/testUtils.ts +++ b/src/storages/__tests__/testUtils.ts @@ -7,8 +7,7 @@ export function assertStorageInterface(storage: IStorageSync | IStorageAsync) { expect(typeof storage.segments).toBe('object'); expect(typeof storage.impressions).toBe('object'); expect(typeof storage.events).toBe('object'); - expect(!storage.latencies || typeof storage.latencies === 'object').toBeTruthy; - expect(!storage.counts || typeof storage.counts === 'object').toBeTruthy; + expect(!storage.telemetry || typeof storage.telemetry === 'object').toBeTruthy; expect(!storage.impressionCounts || typeof storage.impressionCounts === 'object').toBeTruthy; }