-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Collect user data measures with telemetry
- Loading branch information
1 parent
316a8bb
commit 6594d96
Showing
10 changed files
with
183 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,71 @@ | ||
import { deepClone } from './utils' | ||
|
||
import { computeBytesCount, deepClone, isEmptyObject, jsonStringify } from './utils' | ||
import type { Context, ContextValue } from './context' | ||
|
||
export type ContextManager = ReturnType<typeof createContextManager> | ||
|
||
export function createContextManager() { | ||
let context: Context = {} | ||
const bytesCounter = contextBytesCounter() | ||
|
||
return { | ||
getBytesCount: () => bytesCounter.compute(context), | ||
/** @deprecated use getContext instead */ | ||
get: () => context, | ||
|
||
/** @deprecated use setContextProperty instead */ | ||
add: (key: string, value: any) => { | ||
context[key] = value as ContextValue | ||
bytesCounter.invalidate() | ||
}, | ||
|
||
/** @deprecated renamed to removeContextProperty */ | ||
remove: (key: string) => { | ||
delete context[key] | ||
bytesCounter.invalidate() | ||
}, | ||
|
||
/** @deprecated use setContext instead */ | ||
set: (newContext: object) => { | ||
context = newContext as Context | ||
bytesCounter.invalidate() | ||
}, | ||
|
||
getContext: () => deepClone(context), | ||
|
||
setContext: (newContext: Context) => { | ||
context = deepClone(newContext) | ||
bytesCounter.invalidate() | ||
}, | ||
|
||
setContextProperty: (key: string, property: any) => { | ||
context[key] = deepClone(property) | ||
bytesCounter.invalidate() | ||
}, | ||
|
||
removeContextProperty: (key: string) => { | ||
delete context[key] | ||
bytesCounter.invalidate() | ||
}, | ||
|
||
clearContext: () => { | ||
context = {} | ||
bytesCounter.invalidate() | ||
}, | ||
} | ||
} | ||
|
||
export function contextBytesCounter() { | ||
let bytesCount: number | undefined | ||
|
||
return { | ||
compute: (context: Context) => { | ||
if (bytesCount === undefined) { | ||
bytesCount = !isEmptyObject(context) ? computeBytesCount(jsonStringify(context)!) : 0 | ||
} | ||
return bytesCount | ||
}, | ||
invalidate: () => { | ||
bytesCount = undefined | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
export { HttpRequest, createHttpRequest, Payload, RetryInfo } from './httpRequest' | ||
export { Batch } from './batch' | ||
export { Batch, BatchFlushEvent } from './batch' | ||
export { canUseEventBridge, getEventBridge, BrowserWindowWithEventBridge } from './eventBridge' | ||
export { startBatchWithReplica } from './startBatchWithReplica' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import type { BatchFlushEvent, Context, ContextManager, Observable } from '@datadog/browser-core' | ||
import { ONE_SECOND, addTelemetryDebug, monitor } from '@datadog/browser-core' | ||
import { RumEventType } from '../rawRumEvent.types' | ||
import type { RumEvent } from '../rumEvent.types' | ||
import type { FeatureFlagContexts } from './contexts/featureFlagContext' | ||
import type { LifeCycle } from './lifeCycle' | ||
import { LifeCycleEventType } from './lifeCycle' | ||
|
||
export const MEASURES_FLUSH_INTERVAL = 10 * ONE_SECOND | ||
|
||
type Measure = { | ||
min: number | ||
max: number | ||
sum: number | ||
} | ||
|
||
let batchCount = 0 | ||
let batchBytesCount: Measure | undefined | ||
let batchMessagesCount: Measure | undefined | ||
let globalContextBytes: Measure | undefined | ||
let userContextBytes: Measure | undefined | ||
let featureFlagBytes: Measure | undefined | ||
|
||
export function startUserDataMeasurement( | ||
lifeCycle: LifeCycle, | ||
globalContextManager: ContextManager, | ||
userContextManager: ContextManager, | ||
featureFlagContexts: FeatureFlagContexts, | ||
batchFlushObservable: Observable<BatchFlushEvent> | ||
) { | ||
lifeCycle.subscribe(LifeCycleEventType.RUM_EVENT_COLLECTED, (event: RumEvent & Context) => { | ||
globalContextBytes = computeMeasure(globalContextBytes, globalContextManager.getBytesCount()) | ||
userContextBytes = computeMeasure(userContextBytes, userContextManager.getBytesCount()) | ||
|
||
if ([RumEventType.VIEW, RumEventType.ERROR].includes(event.type as RumEventType)) { | ||
featureFlagBytes = computeMeasure(featureFlagBytes, featureFlagContexts.getFeatureFlagBytesCount()) | ||
} | ||
}) | ||
|
||
batchFlushObservable.subscribe(({ bufferBytesCount, bufferMessagesCount }) => { | ||
batchCount += 1 | ||
batchBytesCount = computeMeasure(batchBytesCount, bufferBytesCount) | ||
batchMessagesCount = computeMeasure(batchMessagesCount, bufferMessagesCount) | ||
}) | ||
|
||
setInterval(monitor(sendMeasures), MEASURES_FLUSH_INTERVAL) | ||
} | ||
|
||
function sendMeasures() { | ||
if (batchCount === 0) { | ||
return | ||
} | ||
|
||
addTelemetryDebug('User contexts measures', { | ||
batchCount, | ||
batchBytesCount, | ||
batchMessagesCount, | ||
globalContextBytes, | ||
userContextBytes, | ||
featureFlagBytes, | ||
}) | ||
clearMeasures() | ||
} | ||
|
||
function computeMeasure({ min, max, sum }: Measure = { min: Infinity, max: 0, sum: 0 }, newValue: number) { | ||
// only measure when there is some data. It avoid collecting the measure of un unused feature (like global context, etc..). | ||
if (sum === 0 && newValue === 0) { | ||
return undefined | ||
} | ||
|
||
return { | ||
sum: sum + newValue, | ||
min: Math.min(min, newValue), | ||
max: Math.max(max, newValue), | ||
} | ||
} | ||
|
||
function clearMeasures() { | ||
batchCount = 0 | ||
batchBytesCount = undefined | ||
batchMessagesCount = undefined | ||
globalContextBytes = undefined | ||
userContextBytes = undefined | ||
featureFlagBytes = undefined | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters