-
Notifications
You must be signed in to change notification settings - Fork 155
Signals sampling #1166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Signals sampling #1166
Changes from 2 commits
de05dd3
cf6480d
705aa7e
b8e7ef7
0d96d2d
43056e5
86094cd
472334d
b3084e4
3c5e011
6df3f28
70f0ac0
1399435
c56b2e0
3c98fcd
34fbcf7
4c9438a
93bf465
e238b8b
46bfe4e
fe9d373
0f14951
b8c6586
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,13 +8,17 @@ export class SignalsIngestSettings { | |
| flushInterval: number | ||
| apiHost: string | ||
| shouldDisableSignalRedaction: () => boolean | ||
| signalIngestion: () => boolean | ||
| writeKey?: string | ||
| sampleRate: number | ||
| constructor(settings: SignalsIngestSettingsConfig) { | ||
| this.flushAt = settings.flushAt ?? 5 | ||
| this.apiHost = settings.apiHost ?? 'signals.segment.io/v1' | ||
| this.flushInterval = settings.flushInterval ?? 2000 | ||
| this.shouldDisableSignalRedaction = | ||
| settings.shouldDisableSignalRedaction ?? (() => false) | ||
| this.signalIngestion = settings.signalIngestion ?? (() => false) | ||
| this.sampleRate = settings.sampleRate ?? 0 | ||
|
||
| } | ||
| } | ||
|
|
||
|
|
@@ -23,6 +27,8 @@ export interface SignalsIngestSettingsConfig { | |
| flushAt?: number | ||
| flushInterval?: number | ||
| shouldDisableSignalRedaction?: () => boolean | ||
| signalIngestion?: () => boolean | ||
| sampleRate?: number | ||
| } | ||
| /** | ||
| * This currently just uses the Segment analytics-next library to send signals. | ||
|
|
@@ -69,10 +75,25 @@ export class SignalsIngestClient { | |
| return analytics | ||
| } | ||
|
|
||
| private shouldIngestSignals(): boolean { | ||
|
||
| let shouldIngest = false | ||
| if (Math.random() > this.settings.sampleRate) { | ||
| // currently a no-op, but will be used once signals are sent outside of debug mode | ||
| shouldIngest = false | ||
| } | ||
| if (this.settings.signalIngestion()) { | ||
| shouldIngest = true | ||
| } | ||
| return shouldIngest | ||
| } | ||
|
|
||
| private sendTrackCall(signal: Signal) { | ||
| if (!this.analytics) { | ||
| throw new Error('Please initialize before calling this method.') | ||
| } | ||
| if (!this.shouldIngestSignals()) { | ||
| return | ||
| } | ||
| const disableRedaction = this.settings.shouldDisableSignalRedaction() | ||
| const data = disableRedaction | ||
| ? signal.data | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,8 @@ export type SignalsSettingsConfig = Pick< | |
| | 'flushAt' | ||
| | 'flushInterval' | ||
| | 'disableSignalsRedaction' | ||
| | 'signalsIngestion' | ||
| | 'sampleRate' | ||
| | 'networkSignalsAllowList' | ||
| | 'networkSignalsDisallowList' | ||
| | 'networkSignalsAllowSameDomain' | ||
|
|
@@ -34,6 +36,7 @@ export class SignalGlobalSettings { | |
| network: NetworkSettingsConfig | ||
|
|
||
| private redaction = new SignalRedactionSettings() | ||
| private ingestion = new SignalIngestionSettings() | ||
|
|
||
| constructor(settings: SignalsSettingsConfig) { | ||
| if (settings.maxBufferSize && settings.signalStorage) { | ||
|
|
@@ -55,6 +58,8 @@ export class SignalGlobalSettings { | |
| flushAt: settings.flushAt, | ||
| flushInterval: settings.flushInterval, | ||
| shouldDisableSignalRedaction: this.redaction.getDisableSignalRedaction, | ||
| signalIngestion: this.ingestion.getSignalIngestion, | ||
| sampleRate: settings.sampleRate, | ||
| } | ||
| this.sandbox = { | ||
| functionHost: settings.functionHost, | ||
|
|
@@ -70,6 +75,7 @@ export class SignalGlobalSettings { | |
| public update({ | ||
| edgeFnDownloadURL, | ||
| disallowListURLs, | ||
| sampleRate, | ||
| }: { | ||
| /** | ||
| * The URL to download the edge function from | ||
|
|
@@ -79,13 +85,18 @@ export class SignalGlobalSettings { | |
| * Add new URLs to the disallow list | ||
| */ | ||
| disallowListURLs: (string | undefined)[] | ||
| /** | ||
| * The sample rate pulled from CDN settings | ||
| */ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make this | undefined / optional, so update can be used atomically (one day?) |
||
| sampleRate: number | ||
| }): void { | ||
| edgeFnDownloadURL && (this.sandbox.edgeFnDownloadURL = edgeFnDownloadURL) | ||
| this.network.networkSignalsFilterList.disallowed.addURLLike( | ||
| ...disallowListURLs.filter(<T>(val: T): val is NonNullable<T> => | ||
| Boolean(val) | ||
| ) | ||
| ) | ||
| this.ingestClient.sampleRate = sampleRate | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -139,3 +150,54 @@ class SignalRedactionSettings { | |
| return false | ||
| } | ||
| } | ||
|
|
||
| class SignalIngestionSettings { | ||
| private static ingestionKey = 'segment_signals_debug_ingestion_enabled' | ||
| constructor(initialValue?: boolean) { | ||
| if (typeof initialValue === 'boolean') { | ||
| this.setSignalIngestion(initialValue) | ||
| } | ||
|
|
||
| // setting ?segment_signals_debug=true will disable redaction, and set a key in local storage | ||
|
||
| // this setting will persist across page loads (even if there is no query string) | ||
| // in order to clear the setting, user must set ?segment_signals_debug=false | ||
| const debugModeInQs = parseDebugModeQueryString() | ||
| logger.debug('debugMode is set to true via query string') | ||
|
||
| if (typeof debugModeInQs === 'boolean') { | ||
| this.setSignalIngestion(debugModeInQs) | ||
| } | ||
| } | ||
|
|
||
| setSignalIngestion(shouldEnable: boolean) { | ||
| try { | ||
| if (shouldEnable) { | ||
| window.sessionStorage.setItem( | ||
| SignalIngestionSettings.ingestionKey, | ||
| 'true' | ||
| ) | ||
| } else { | ||
| logger.debug('Removing ingestion key from storage') | ||
| window.sessionStorage.removeItem(SignalIngestionSettings.ingestionKey) | ||
| } | ||
| } catch (e) { | ||
| logger.debug('Storage error', e) | ||
| } | ||
| } | ||
|
|
||
| getSignalIngestion() { | ||
| try { | ||
| const isEnabled = Boolean( | ||
| window.sessionStorage.getItem(SignalIngestionSettings.ingestionKey) | ||
| ) | ||
| if (isEnabled) { | ||
| logger.debug( | ||
| `${SignalIngestionSettings.ingestionKey}=true (app. storage)` | ||
| ) | ||
| return true | ||
| } | ||
| } catch (e) { | ||
| logger.debug('Storage error', e) | ||
| } | ||
| return false | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd need a changeset for both signals and analytics =)