Skip to content

Commit

Permalink
feat: paradata batch configuration with .env (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
chloe-renaud authored Dec 18, 2024
1 parent 7f4d800 commit 70f1bd9
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@ VITE_VISUALIZE_DISABLED=
# Waiting vite-env support dynamic base path
VITE_BASE_PATH=
VITE_REVIEW_IDENTITY_PROVIDER=

# When VITE_TELEMETRY_DISABLED equals true we disable telemetry (default: enabled)
VITE_TELEMETRY_DISABLED=
# Override max delay in ms to wait for before sending a batch (default: 1min)
VITE_TELEMETRY_MAX_DELAY=
# Override max number of data to send in a single batch (default: 10)
VITE_TELEMETRY_MAX_LENGTH=
21 changes: 16 additions & 5 deletions src/contexts/TelemetryContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
TelemetryEvent,
TelemetryParadata,
} from '@/models/telemetry'
import { computeDataMaxLength, computeInactivityDelay } from '@/utils/telemetry'

type TelemetryContextType = {
isTelemetryDisabled: boolean
Expand All @@ -22,23 +23,23 @@ type TelemetryContextType = {
triggerBatchTelemetryCallback?: () => Promise<void>
}

/** Mandatory values used as a context's last-resort fallback */
/** Mandatory values used as a context's last-resort fallback. */
const defaultValues = {
isTelemetryDisabled: true,
pushEvent: (_: TelemetryParadata) => {},
setDefaultValues: (_: DefaultParadataValues) => {},
}

/**
* Exposes shared functions to handle telemetry events.
* Expose shared functions to handle telemetry events.
*
* Should be used with the useBatch hook to reduce external API load.
*/
export const TelemetryContext: React.Context<TelemetryContextType> =
createContext(defaultValues)

/**
* Returns the current telemetry context value.
* Return the current telemetry context value.
*
* @version 1.3.0
* @see https://react.dev/reference/react/useContext
Expand All @@ -47,7 +48,13 @@ export function useTelemetry() {
return useContext(TelemetryContext)
}

/** Initializes the telemetry context with a batch system */
/**
* Initialize the telemetry context with a batch system.
*
* A batch mechanism will be used to avoid sending too many event to the API.
* It can be configured through the environment variables
* `VITE_TELEMETRY_MAX_DELAY` and `VITE_TELEMETRY_MAX_LENGTH`.
*/
export function TelemetryProvider({
children,
}: Readonly<{
Expand All @@ -66,7 +73,11 @@ export function TelemetryProvider({
}
}, [])

const { addDatum, triggerTimeoutEvent } = useBatch(pushEvents)
const { addDatum, triggerTimeoutEvent } = useBatch(
pushEvents,
computeDataMaxLength(),
computeInactivityDelay(),
)

/** Add the event to a batch mechanism. */
const pushEvent = useCallback(
Expand Down
36 changes: 36 additions & 0 deletions src/utils/telemetry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import {
computeContactSupportEvent,
computeControlEvent,
computeControlSkipEvent,
computeDataMaxLength,
computeExitEvent,
computeInactivityDelay,
computeInitEvent,
computeInputEvent,
computeNewPageEvent,
Expand Down Expand Up @@ -138,3 +140,37 @@ test('correctly compares input paradata', async () => {
),
).toBeFalsy()
})

describe('computeDataMaxLength', () => {
afterEach(() => {
vi.unstubAllEnvs()
})

test.each([
[undefined, undefined],
['', undefined],
['100', 100],
['-1', undefined],
['azear', undefined],
])('with env var %i -> %i', (env, res) => {
vi.stubEnv('VITE_TELEMETRY_MAX_LENGTH', env)
expect(computeDataMaxLength()).toBe(res)
})
})

describe('computeInactivityDelay', () => {
afterEach(() => {
vi.unstubAllEnvs()
})

test.each([
[undefined, undefined],
['', undefined],
['100', 100],
['-1', undefined],
['azear', undefined],
])('with env var %i -> %i', (env, res) => {
vi.stubEnv('VITE_TELEMETRY_MAX_DELAY', env)
expect(computeInactivityDelay()).toBe(res)
})
})
48 changes: 41 additions & 7 deletions src/utils/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@ import type {
TelemetryParadata,
} from '@/models/telemetry'

/**
* Compute paradata values that are common to every paradata but must be
* recalculated for each event (e.g. date).
*/
function getCommonData(): CommonParadata {
return {
date: new Date().toISOString(),
}
}

/** Creates an event to be used by telemetry context when the user starts the app */
/** Create an event to be used by telemetry context when the user starts the app. */
export function computeInitEvent(): TelemetryParadata {
return {
...getCommonData(),
type: TELEMETRY_EVENT_TYPE.INIT,
}
}

/** Creates an event to be used by telemetry context when the user quits the app */
/** Create an event to be used by telemetry context when the user quits the app. */
export function computeExitEvent({
source,
}: {
Expand All @@ -33,7 +37,7 @@ export function computeExitEvent({
}
}

/** Creates an event to be used by telemetry context when the user goes to a new page */
/** Create an event to be used by telemetry context when the user goes to a new page. */
export function computeNewPageEvent({
page,
pageTag,
Expand All @@ -49,7 +53,7 @@ export function computeNewPageEvent({
}
}

/** Creates an event to be used by telemetry context when the user inputs something in lunatic components */
/** Create an event to be used by telemetry context when the user inputs something in lunatic components. */
export function computeInputEvent({
name,
iteration,
Expand All @@ -65,7 +69,7 @@ export function computeInputEvent({
}
}

/** Creates an event to be used by telemetry context when lunatic shows a control to the user */
/** Create an event to be used by telemetry context when lunatic shows a control to the user. */
export function computeControlEvent({
controlIds,
}: {
Expand All @@ -78,7 +82,7 @@ export function computeControlEvent({
}
}

/** Creates an event to be used by telemetry context when the user ignores the control shown by lunatic */
/** Create an event to be used by telemetry context when the user ignores the control shown by lunatic. */
export function computeControlSkipEvent({
controlIds,
}: {
Expand All @@ -91,14 +95,18 @@ export function computeControlSkipEvent({
}
}

/** Creates an event to be used by telemetry context when the user clicks on 'contact support' */
/** Create an event to be used by telemetry context when the user clicks on 'contact support'. */
export function computeContactSupportEvent(): TelemetryParadata {
return {
...getCommonData(),
type: TELEMETRY_EVENT_TYPE.CONTACT_SUPPORT,
}
}

/**
* Check if two input paradata are about the same input (i.e. based on input
* name and iteration).
*/
export function areInputParadataIdentical(
event1: InputParadata,
event2: InputParadata,
Expand All @@ -119,3 +127,29 @@ function areArraysEqual(array1: any[], array2: any[]): boolean {
array1.every((value, index) => value === array2[index])
)
}

/**
* Compute batch parameters based on environment variable
* `VITE_TELEMETRY_MAX_LENGTH` for max data to send in one batch.
*/
export function computeDataMaxLength(): number | undefined {
const envVar = import.meta.env.VITE_TELEMETRY_MAX_LENGTH
if (envVar) {
const parsedEnvVar = parseInt(envVar, 10)
if (!isNaN(parsedEnvVar) && parsedEnvVar > 0) return parsedEnvVar
}
return undefined
}

/**
* Compute batch parameters based on environment variable
* `VITE_TELEMETRY_MAX_DELAY` for max delay to wait before sending a batch.
*/
export function computeInactivityDelay(): number | undefined {
const envVar = import.meta.env.VITE_TELEMETRY_MAX_DELAY
if (envVar) {
const parsedEnvVar = parseInt(envVar, 10)
if (!isNaN(parsedEnvVar) && parsedEnvVar > 0) return parsedEnvVar
}
return undefined
}
2 changes: 2 additions & 0 deletions src/vite-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ type ImportMetaEnv = {
VITE_BASE_PATH: string
VITE_REVIEW_IDENTITY_PROVIDER: string
VITE_TELEMETRY_DISABLED: string
VITE_TELEMETRY_MAX_DELAY: string
VITE_TELEMETRY_MAX_LENGTH: string
BASE_URL: string
MODE: string
DEV: boolean
Expand Down
6 changes: 6 additions & 0 deletions website/src/pages/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
### 1.3.3

#### QoL

- ajout des variables d'environnemment `VITE_TELEMETRY_MAX_DELAY` et `VITE_TELEMETRY_MAX_LENGTH` permettant de paramétrer le méchanisme de batch du tracking des paradonnées

### 1.3.2

#### Montée de version Lunatic
Expand Down

0 comments on commit 70f1bd9

Please sign in to comment.