From ac7c075787de2911e745c01c44113c6e1861eb35 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Thu, 4 Jan 2024 12:58:04 -0600 Subject: [PATCH] feat(shared): Introduce event-specific sampling rates --- .changeset/dirty-sheep-warn.md | 5 +++++ .../shared/src/__tests__/telemetry.test.ts | 18 ++++++++++++++++++ packages/shared/src/telemetry/collector.ts | 15 ++++++++++----- .../src/telemetry/events/component-mounted.ts | 2 ++ packages/shared/src/telemetry/types.ts | 1 + 5 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 .changeset/dirty-sheep-warn.md diff --git a/.changeset/dirty-sheep-warn.md b/.changeset/dirty-sheep-warn.md new file mode 100644 index 00000000000..af12d42caa0 --- /dev/null +++ b/.changeset/dirty-sheep-warn.md @@ -0,0 +1,5 @@ +--- +'@clerk/shared': patch +--- + +Update TelemetryCollector to consider event-specific sampling rates. diff --git a/packages/shared/src/__tests__/telemetry.test.ts b/packages/shared/src/__tests__/telemetry.test.ts index 4fab9b73ee3..7f2c0a41e7f 100644 --- a/packages/shared/src/__tests__/telemetry.test.ts +++ b/packages/shared/src/__tests__/telemetry.test.ts @@ -152,4 +152,22 @@ describe('TelemetryCollector', () => { fetchSpy.mockRestore(); }); + + test('does not send events if the random seed does not exceed the event-specific sampling rate', async () => { + const fetchSpy = jest.spyOn(global, 'fetch'); + const randomSpy = jest.spyOn(Math, 'random').mockReturnValue(0.1); + + const collector = new TelemetryCollector({ + publishableKey: TEST_PK, + }); + + collector.record({ event: 'TEST_EVENT', eventSamplingRate: 0.01, payload: {} }); + + jest.runAllTimers(); + + expect(fetchSpy).not.toHaveBeenCalled(); + + fetchSpy.mockRestore(); + randomSpy.mockRestore; + }); }); diff --git a/packages/shared/src/telemetry/collector.ts b/packages/shared/src/telemetry/collector.ts index 04751ae937b..2122c7e2da0 100644 --- a/packages/shared/src/telemetry/collector.ts +++ b/packages/shared/src/telemetry/collector.ts @@ -14,7 +14,7 @@ import type { InstanceType } from '@clerk/types'; import { parsePublishableKey } from '../keys'; import { isTruthy } from '../underscore'; -import type { TelemetryCollectorOptions, TelemetryEvent } from './types'; +import type { TelemetryCollectorOptions, TelemetryEvent, TelemetryEventRaw } from './types'; type TelemetryCollectorConfig = Pick< TelemetryCollectorOptions, @@ -105,12 +105,12 @@ export class TelemetryCollector { return this.#config.debug || (typeof process !== 'undefined' && isTruthy(process.env.CLERK_TELEMETRY_DEBUG)); } - record(event: Pick): void { + record(event: TelemetryEventRaw): void { const preparedPayload = this.#preparePayload(event.event, event.payload); this.#logEvent(preparedPayload.event, preparedPayload); - if (!this.#shouldRecord()) { + if (!this.#shouldRecord(event.eventSamplingRate)) { return; } @@ -119,8 +119,13 @@ export class TelemetryCollector { this.#scheduleFlush(); } - #shouldRecord(): boolean { - return this.isEnabled && !this.isDebug && Math.random() <= this.#config.samplingRate; + #shouldRecord(eventSamplingRate?: number): boolean { + const randomSeed = Math.random(); + const shouldBeSampled = + randomSeed <= this.#config.samplingRate && + (typeof eventSamplingRate === 'undefined' || randomSeed <= eventSamplingRate); + + return this.isEnabled && !this.isDebug && shouldBeSampled; } #scheduleFlush(): void { diff --git a/packages/shared/src/telemetry/events/component-mounted.ts b/packages/shared/src/telemetry/events/component-mounted.ts index e298bc8a1b9..8649bf1a113 100644 --- a/packages/shared/src/telemetry/events/component-mounted.ts +++ b/packages/shared/src/telemetry/events/component-mounted.ts @@ -1,6 +1,7 @@ import type { TelemetryEventRaw } from '../types'; const EVENT_COMPONENT_MOUNTED = 'COMPONENT_MOUNTED' as const; +const EVENT_SAMPLING_RATE = 0.1; type EventComponentMounted = { component: string; @@ -19,6 +20,7 @@ export function eventComponentMounted( ): TelemetryEventRaw { return { event: EVENT_COMPONENT_MOUNTED, + eventSamplingRate: EVENT_SAMPLING_RATE, payload: { component, appearanceProp: Boolean(props?.appearance), diff --git a/packages/shared/src/telemetry/types.ts b/packages/shared/src/telemetry/types.ts index af902a33854..e594590db58 100644 --- a/packages/shared/src/telemetry/types.ts +++ b/packages/shared/src/telemetry/types.ts @@ -70,5 +70,6 @@ export type TelemetryEvent = { export type TelemetryEventRaw = { event: TelemetryEvent['event']; + eventSamplingRate?: number; payload: Payload; };