import { Marker } from './Diagnostics'; import { SamplingDecision } from './LogEventProcessor'; import { StatsigUser } from './StatsigUser'; import { clone } from './utils/core'; import LogEventValidator, { MAX_OBJ_SIZE } from './utils/LogEventValidator'; export type LogEventData = { time: number; eventName: string; user: StatsigUser | null; value: string | number | null; metadata: Record | null; secondaryExposures: SecondaryExposure[]; statsigMetadata: Record | null; }; export type SecondaryExposure = { gate: string; gateValue: string; ruleID: string; }; export default class LogEvent { private time: number; private eventName: string; private user: StatsigUser | null = null; private value: string | number | null = null; private metadata: Record | null = null; private secondaryExposures: SecondaryExposure[] = []; private statsigMetadata: Record = {}; public constructor(eventName: string) { this.time = Date.now(); this.eventName = LogEventValidator.validateEventName(eventName) ?? 'invalid_event'; } public setUser(user: StatsigUser) { const validatedUser = LogEventValidator.validateUserObject(user); if (validatedUser == null) { return; } this.user = clone(validatedUser); if (this.user != null) { this.user.privateAttributes = null; } } public setValue(value: string | number | null) { const validatedValue = LogEventValidator.validateEventValue(value); if (validatedValue == null) { return; } this.value = validatedValue; } public setMetadata(metadata: Record | null) { const validatedMetadata = LogEventValidator.validateEventMetadata(metadata); if (validatedMetadata == null) { return; } this.metadata = clone(validatedMetadata); } public setSamplingDecision(samplingDecision: SamplingDecision) { if (samplingDecision.samplingRate) { this.statsigMetadata['samplingRate'] = samplingDecision.samplingRate; } if (samplingDecision.shadowLogged) { this.statsigMetadata['shadowLogged'] = samplingDecision.shadowLogged; } if (samplingDecision.samplingMode) { this.statsigMetadata['samplingMode'] = samplingDecision.samplingMode; } } public setDiagnosticsMetadata(metadata: { context: string; markers: Marker[]; statsigOptions: object | undefined; }) { const metadataSize = LogEventValidator.approximateObjectSize(metadata); let optionSize = 0; const metadataCopy = clone(metadata) as { context: string; markers: unknown; statsigOptions: unknown; }; if (metadataSize > MAX_OBJ_SIZE) { if (metadata.statsigOptions) { optionSize = LogEventValidator.approximateObjectSize( metadata.statsigOptions, ); metadataCopy.statsigOptions = 'dropped'; } if (metadataSize - optionSize > MAX_OBJ_SIZE) { if (metadata.context === 'initialize') { metadataCopy.markers = metadata.markers.filter( (marker) => marker.key === 'overall', ); } else { metadataCopy.markers = 'dropped'; } } } this.metadata = metadataCopy; } public setTime(time: number) { const validatedTime = LogEventValidator.validateEventTime(time); if (validatedTime == null) { return; } this.time = validatedTime; } public setSecondaryExposures(exposures: SecondaryExposure[]) { this.secondaryExposures = Array.isArray(exposures) ? exposures : []; } public validate(): boolean { return typeof this.eventName === 'string' && this.eventName.length > 0; } public toObject(): LogEventData { return { eventName: this.eventName, metadata: this.metadata, time: this.time, user: this.user, value: this.value, secondaryExposures: this.secondaryExposures, statsigMetadata: this.statsigMetadata, }; } }