-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
feat: configure session recording sample rate #18068
Changes from 37 commits
3acdaf1
b70ec1a
24084c1
db33638
bc0142b
a3f171a
1a080c7
76d07f6
93a0e6c
1440392
9116ff0
3d02cd3
8c0bda7
5d2ea58
379ecda
10e0c02
89725ca
6174109
0f30d39
3845825
87ce2e2
ca76d1c
c0833ee
a083c3b
a8013d2
a561d6b
0b77b0c
42f2d8f
faa375a
9ddc393
1e9ee03
82cde4d
d19aa8e
605d058
337c11a
3a884ae
3b20ab9
933b537
e5a2714
545ebae
5221b16
71ba595
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 |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { useState } from 'react' | ||
import { useValues } from 'kea' | ||
import { featureFlagLogic } from 'scenes/feature-flags/featureFlagLogic' | ||
import { TaxonomicFilterGroupType, TaxonomicFilterLogicProps } from 'lib/components/TaxonomicFilter/types' | ||
import { Popover } from 'lib/lemon-ui/Popover' | ||
import { TaxonomicFilter } from 'lib/components/TaxonomicFilter/TaxonomicFilter' | ||
import { LemonButton } from 'lib/lemon-ui/LemonButton' | ||
|
||
interface FlagSelectorProps { | ||
value: number | undefined | ||
onChange: (id: number, key: string) => void | ||
readOnly?: boolean | ||
} | ||
|
||
export function FlagSelector({ value, onChange, readOnly }: FlagSelectorProps): JSX.Element { | ||
const [visible, setVisible] = useState(false) | ||
|
||
const { featureFlag } = useValues(featureFlagLogic({ id: value || 'link' })) | ||
|
||
const taxonomicFilterLogicProps: TaxonomicFilterLogicProps = { | ||
groupType: TaxonomicFilterGroupType.FeatureFlags, | ||
value: value, | ||
onChange: (_, __, item) => { | ||
'id' in item && item.id && onChange(item.id, item.key) | ||
setVisible(false) | ||
}, | ||
taxonomicGroupTypes: [TaxonomicFilterGroupType.FeatureFlags], | ||
optionsFromProp: undefined, | ||
popoverEnabled: true, | ||
selectFirstItem: true, | ||
taxonomicFilterLogicKey: 'flag-selectorz', | ||
} | ||
|
||
return ( | ||
<Popover | ||
overlay={<TaxonomicFilter {...taxonomicFilterLogicProps} />} | ||
visible={visible} | ||
placement="right-start" | ||
fallbackPlacements={['left-end', 'bottom']} | ||
onClickOutside={() => setVisible(false)} | ||
> | ||
{readOnly ? ( | ||
<div>{featureFlag.key}</div> | ||
) : ( | ||
<LemonButton type="secondary" onClick={() => setVisible(!visible)}> | ||
{featureFlag.key ? featureFlag.key : 'Select flag'} | ||
</LemonButton> | ||
)} | ||
</Popover> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,15 @@ | ||
import { useActions, useValues } from 'kea' | ||
import { teamLogic } from 'scenes/teamLogic' | ||
import { LemonSwitch, Link } from '@posthog/lemon-ui' | ||
import { LemonButton, LemonSelect, LemonSwitch, Link } from '@posthog/lemon-ui' | ||
import { urls } from 'scenes/urls' | ||
import { AuthorizedUrlList } from 'lib/components/AuthorizedUrlList/AuthorizedUrlList' | ||
import { AuthorizedUrlListType } from 'lib/components/AuthorizedUrlList/authorizedUrlListLogic' | ||
import { LemonDialog } from 'lib/lemon-ui/LemonDialog' | ||
import { LemonLabel } from 'lib/lemon-ui/LemonLabel/LemonLabel' | ||
import { FlaggedFeature } from 'lib/components/FlaggedFeature' | ||
import { FEATURE_FLAGS } from 'lib/constants' | ||
import { IconCancel } from 'lib/lemon-ui/icons' | ||
import { FlagSelector } from 'lib/components/FlagSelector' | ||
|
||
export type SessionRecordingSettingsProps = { | ||
inModal?: boolean | ||
|
@@ -102,6 +106,113 @@ export function SessionRecordingSettings({ inModal = false }: SessionRecordingSe | |
</p> | ||
<AuthorizedUrlList type={AuthorizedUrlListType.RECORDING_DOMAINS} /> | ||
</div> | ||
<FlaggedFeature flag={FEATURE_FLAGS.SESSION_RECORDING_SAMPLING}> | ||
pauldambra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<> | ||
<div className={'flex flex-row justify-between'}> | ||
<LemonLabel className="text-base">Sampling</LemonLabel> | ||
<LemonSelect | ||
onChange={(v) => { | ||
updateCurrentTeam({ session_recording_sample_rate: v }) | ||
}} | ||
options={[ | ||
{ | ||
label: '100%', | ||
value: '1.00', | ||
}, | ||
{ | ||
label: '95%', | ||
value: '0.95', | ||
}, | ||
{ | ||
label: '90%', | ||
value: '0.90', | ||
}, | ||
{ | ||
label: '80%', | ||
value: '0.80', | ||
}, | ||
{ | ||
label: '50%', | ||
value: '0.50', | ||
}, | ||
]} | ||
pauldambra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
value={ | ||
typeof currentTeam?.session_recording_sample_rate === 'string' | ||
? currentTeam?.session_recording_sample_rate | ||
: '1.00' | ||
} | ||
/> | ||
</div> | ||
<p> | ||
Use this setting to restrict the percentage of sessions that will be recorded. This is useful if | ||
you want to reduce the amount of data you collect. 100% means all sessions will be collected. | ||
50% means roughly half of sessions will be collected. | ||
</p> | ||
<div className={'flex flex-row justify-between'}> | ||
<LemonLabel className="text-base">Minimum session duration (seconds)</LemonLabel> | ||
<LemonSelect | ||
dropdownMatchSelectWidth={false} | ||
onChange={(v) => { | ||
updateCurrentTeam({ session_recording_minimum_duration_milliseconds: v }) | ||
}} | ||
options={[ | ||
{ | ||
label: 'no minimum', | ||
value: null, | ||
}, | ||
{ | ||
label: '1', | ||
value: 1000, | ||
}, | ||
{ | ||
label: '2', | ||
value: 2000, | ||
}, | ||
{ | ||
label: '5', | ||
value: 5000, | ||
}, | ||
{ | ||
label: '10', | ||
value: 10000, | ||
}, | ||
{ | ||
label: '15', | ||
value: 15000, | ||
}, | ||
]} | ||
value={currentTeam?.session_recording_minimum_duration_milliseconds} | ||
/> | ||
</div> | ||
<p> | ||
Setting a minimum session duration will ensure that only sessions that last longer than that | ||
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. I think we should warn that this does mean some useful data may not be collected. Debugging a user issue that starts with a loading screen before redirecting to another domain. With this setting set to say, 10 seconds, the initial redirect screen would not have been recorded as it is only buffered in memory. 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. This could also be expanded in documentation instead of the modal |
||
value are collected. This helps you avoid collecting sessions that are too short to be useful. | ||
</p> | ||
<div className={'flex flex-row justify-between'}> | ||
<LemonLabel className="text-base">Enable recordings using feature flag</LemonLabel> | ||
{currentTeam?.session_recording_linked_flag && ( | ||
<LemonButton | ||
className="ml-2" | ||
icon={<IconCancel />} | ||
size="small" | ||
status="stealth" | ||
onClick={() => updateCurrentTeam({ session_recording_linked_flag: null })} | ||
aria-label="close" | ||
/> | ||
)} | ||
<FlagSelector | ||
value={currentTeam?.session_recording_linked_flag?.id ?? undefined} | ||
onChange={(id, key) => { | ||
updateCurrentTeam({ session_recording_linked_flag: { id, key } }) | ||
}} | ||
/> | ||
pauldambra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</div> | ||
<p> | ||
Linking a flag means that recordings will only be collected for users who have the flag enabled. | ||
Only supports release toggles (boolean flags). | ||
</p> | ||
</> | ||
</FlaggedFeature> | ||
</div> | ||
) | ||
} | ||
|
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.
@liyiy @neilkakkar I've moved the flag selector into components since I wanted to use it in replay config. And exposed the flag key as well as the id on change... That ok?