[Statsig] Sample noisy events (#4288)
* Sample state:background and state:foreground * Sample feed events * Add DEV protection against forgetting to add events to the list
This commit is contained in:
parent
9431201026
commit
d6275e98c2
7 changed files with 41 additions and 21 deletions
|
@ -20,10 +20,10 @@ export type LogEvents = {
|
||||||
context: 'StartOnboarding' | 'AfterOnboarding' | 'Login'
|
context: 'StartOnboarding' | 'AfterOnboarding' | 'Login'
|
||||||
status: 'granted' | 'denied' | 'undetermined'
|
status: 'granted' | 'denied' | 'undetermined'
|
||||||
}
|
}
|
||||||
'state:background': {
|
'state:background:sampled': {
|
||||||
secondsActive: number
|
secondsActive: number
|
||||||
}
|
}
|
||||||
'state:foreground': {}
|
'state:foreground:sampled': {}
|
||||||
'router:navigate:sampled': {}
|
'router:navigate:sampled': {}
|
||||||
|
|
||||||
// Screen events
|
// Screen events
|
||||||
|
@ -57,18 +57,18 @@ export type LogEvents = {
|
||||||
'onboarding:finished:avatarResult': {
|
'onboarding:finished:avatarResult': {
|
||||||
avatarResult: 'default' | 'created' | 'uploaded'
|
avatarResult: 'default' | 'created' | 'uploaded'
|
||||||
}
|
}
|
||||||
'home:feedDisplayed': {
|
'home:feedDisplayed:sampled': {
|
||||||
feedUrl: string
|
feedUrl: string
|
||||||
feedType: string
|
feedType: string
|
||||||
index: number
|
index: number
|
||||||
reason: 'focus' | 'tabbar-click' | 'pager-swipe' | 'desktop-sidebar-click'
|
reason: 'focus' | 'tabbar-click' | 'pager-swipe' | 'desktop-sidebar-click'
|
||||||
}
|
}
|
||||||
'feed:endReached': {
|
'feed:endReached:sampled': {
|
||||||
feedUrl: string
|
feedUrl: string
|
||||||
feedType: string
|
feedType: string
|
||||||
itemCount: number
|
itemCount: number
|
||||||
}
|
}
|
||||||
'feed:refresh': {
|
'feed:refresh:sampled': {
|
||||||
feedUrl: string
|
feedUrl: string
|
||||||
feedType: string
|
feedType: string
|
||||||
reason: 'pull-to-refresh' | 'soft-reset' | 'load-latest'
|
reason: 'pull-to-refresh' | 'soft-reset' | 'load-latest'
|
||||||
|
|
|
@ -87,7 +87,14 @@ export function toClout(n: number | null | undefined): number | undefined {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DOWNSAMPLED_EVENTS = new Set(['router:navigate:sampled'])
|
const DOWNSAMPLED_EVENTS: Set<keyof LogEvents> = new Set([
|
||||||
|
'router:navigate:sampled',
|
||||||
|
'state:background:sampled',
|
||||||
|
'state:foreground:sampled',
|
||||||
|
'home:feedDisplayed:sampled',
|
||||||
|
'feed:endReached:sampled',
|
||||||
|
'feed:refresh:sampled',
|
||||||
|
])
|
||||||
const isDownsampledSession = Math.random() < 0.9 // 90% likely
|
const isDownsampledSession = Math.random() < 0.9 // 90% likely
|
||||||
|
|
||||||
export function logEvent<E extends keyof LogEvents>(
|
export function logEvent<E extends keyof LogEvents>(
|
||||||
|
@ -98,6 +105,13 @@ export function logEvent<E extends keyof LogEvents>(
|
||||||
if (isDownsampledSession && DOWNSAMPLED_EVENTS.has(eventName)) {
|
if (isDownsampledSession && DOWNSAMPLED_EVENTS.has(eventName)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
if (eventName.endsWith(':sampled')) {
|
||||||
|
logger.error(
|
||||||
|
'Did you forget to add ' + eventName + ' to DOWNSAMPLED_EVENTS?',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
const fullMetadata = {
|
const fullMetadata = {
|
||||||
...rawMetadata,
|
...rawMetadata,
|
||||||
} as Record<string, string> // Statsig typings are unnecessarily strict here.
|
} as Record<string, string> // Statsig typings are unnecessarily strict here.
|
||||||
|
@ -199,14 +213,14 @@ AppState.addEventListener('change', (state: AppStateStatus) => {
|
||||||
lastState = state
|
lastState = state
|
||||||
if (state === 'active') {
|
if (state === 'active') {
|
||||||
lastActive = performance.now()
|
lastActive = performance.now()
|
||||||
logEvent('state:foreground', {})
|
logEvent('state:foreground:sampled', {})
|
||||||
} else {
|
} else {
|
||||||
let secondsActive = 0
|
let secondsActive = 0
|
||||||
if (lastActive != null) {
|
if (lastActive != null) {
|
||||||
secondsActive = Math.round((performance.now() - lastActive) / 1e3)
|
secondsActive = Math.round((performance.now() - lastActive) / 1e3)
|
||||||
}
|
}
|
||||||
lastActive = null
|
lastActive = null
|
||||||
logEvent('state:background', {
|
logEvent('state:background:sampled', {
|
||||||
secondsActive,
|
secondsActive,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ export function FeedPage({
|
||||||
scrollToTop()
|
scrollToTop()
|
||||||
truncateAndInvalidate(queryClient, FEED_RQKEY(feed))
|
truncateAndInvalidate(queryClient, FEED_RQKEY(feed))
|
||||||
setHasNew(false)
|
setHasNew(false)
|
||||||
logEvent('feed:refresh', {
|
logEvent('feed:refresh:sampled', {
|
||||||
feedType: feed.split('|')[0],
|
feedType: feed.split('|')[0],
|
||||||
feedUrl: feed,
|
feedUrl: feed,
|
||||||
reason: 'soft-reset',
|
reason: 'soft-reset',
|
||||||
|
@ -102,7 +102,7 @@ export function FeedPage({
|
||||||
scrollToTop()
|
scrollToTop()
|
||||||
truncateAndInvalidate(queryClient, FEED_RQKEY(feed))
|
truncateAndInvalidate(queryClient, FEED_RQKEY(feed))
|
||||||
setHasNew(false)
|
setHasNew(false)
|
||||||
logEvent('feed:refresh', {
|
logEvent('feed:refresh:sampled', {
|
||||||
feedType: feed.split('|')[0],
|
feedType: feed.split('|')[0],
|
||||||
feedUrl: feed,
|
feedUrl: feed,
|
||||||
reason: 'load-latest',
|
reason: 'load-latest',
|
||||||
|
|
|
@ -15,7 +15,7 @@ const AnimatedPagerView = Animated.createAnimatedComponent(PagerView)
|
||||||
export interface PagerRef {
|
export interface PagerRef {
|
||||||
setPage: (
|
setPage: (
|
||||||
index: number,
|
index: number,
|
||||||
reason: LogEvents['home:feedDisplayed']['reason'],
|
reason: LogEvents['home:feedDisplayed:sampled']['reason'],
|
||||||
) => void
|
) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ interface Props {
|
||||||
onPageSelected?: (index: number) => void
|
onPageSelected?: (index: number) => void
|
||||||
onPageSelecting?: (
|
onPageSelecting?: (
|
||||||
index: number,
|
index: number,
|
||||||
reason: LogEvents['home:feedDisplayed']['reason'],
|
reason: LogEvents['home:feedDisplayed:sampled']['reason'],
|
||||||
) => void
|
) => void
|
||||||
onPageScrollStateChanged?: (
|
onPageScrollStateChanged?: (
|
||||||
scrollState: 'idle' | 'dragging' | 'settling',
|
scrollState: 'idle' | 'dragging' | 'settling',
|
||||||
|
@ -61,7 +61,7 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
|
||||||
React.useImperativeHandle(ref, () => ({
|
React.useImperativeHandle(ref, () => ({
|
||||||
setPage: (
|
setPage: (
|
||||||
index: number,
|
index: number,
|
||||||
reason: LogEvents['home:feedDisplayed']['reason'],
|
reason: LogEvents['home:feedDisplayed:sampled']['reason'],
|
||||||
) => {
|
) => {
|
||||||
pagerView.current?.setPage(index)
|
pagerView.current?.setPage(index)
|
||||||
onPageSelecting?.(index, reason)
|
onPageSelecting?.(index, reason)
|
||||||
|
|
|
@ -18,7 +18,7 @@ interface Props {
|
||||||
onPageSelected?: (index: number) => void
|
onPageSelected?: (index: number) => void
|
||||||
onPageSelecting?: (
|
onPageSelecting?: (
|
||||||
index: number,
|
index: number,
|
||||||
reason: LogEvents['home:feedDisplayed']['reason'],
|
reason: LogEvents['home:feedDisplayed:sampled']['reason'],
|
||||||
) => void
|
) => void
|
||||||
}
|
}
|
||||||
export const Pager = React.forwardRef(function PagerImpl(
|
export const Pager = React.forwardRef(function PagerImpl(
|
||||||
|
@ -38,14 +38,17 @@ export const Pager = React.forwardRef(function PagerImpl(
|
||||||
React.useImperativeHandle(ref, () => ({
|
React.useImperativeHandle(ref, () => ({
|
||||||
setPage: (
|
setPage: (
|
||||||
index: number,
|
index: number,
|
||||||
reason: LogEvents['home:feedDisplayed']['reason'],
|
reason: LogEvents['home:feedDisplayed:sampled']['reason'],
|
||||||
) => {
|
) => {
|
||||||
onTabBarSelect(index, reason)
|
onTabBarSelect(index, reason)
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const onTabBarSelect = React.useCallback(
|
const onTabBarSelect = React.useCallback(
|
||||||
(index: number, reason: LogEvents['home:feedDisplayed']['reason']) => {
|
(
|
||||||
|
index: number,
|
||||||
|
reason: LogEvents['home:feedDisplayed:sampled']['reason'],
|
||||||
|
) => {
|
||||||
const scrollY = window.scrollY
|
const scrollY = window.scrollY
|
||||||
// We want to determine if the tabbar is already "sticking" at the top (in which
|
// We want to determine if the tabbar is already "sticking" at the top (in which
|
||||||
// case we should preserve and restore scroll), or if it is somewhere below in the
|
// case we should preserve and restore scroll), or if it is somewhere below in the
|
||||||
|
|
|
@ -226,7 +226,7 @@ let Feed = ({
|
||||||
|
|
||||||
const onRefresh = React.useCallback(async () => {
|
const onRefresh = React.useCallback(async () => {
|
||||||
track('Feed:onRefresh')
|
track('Feed:onRefresh')
|
||||||
logEvent('feed:refresh', {
|
logEvent('feed:refresh:sampled', {
|
||||||
feedType: feedType,
|
feedType: feedType,
|
||||||
feedUrl: feed,
|
feedUrl: feed,
|
||||||
reason: 'pull-to-refresh',
|
reason: 'pull-to-refresh',
|
||||||
|
@ -244,7 +244,7 @@ let Feed = ({
|
||||||
const onEndReached = React.useCallback(async () => {
|
const onEndReached = React.useCallback(async () => {
|
||||||
if (isFetching || !hasNextPage || isError) return
|
if (isFetching || !hasNextPage || isError) return
|
||||||
|
|
||||||
logEvent('feed:endReached', {
|
logEvent('feed:endReached:sampled', {
|
||||||
feedType: feedType,
|
feedType: feedType,
|
||||||
feedUrl: feed,
|
feedUrl: feed,
|
||||||
itemCount: feedItems.length,
|
itemCount: feedItems.length,
|
||||||
|
|
|
@ -99,7 +99,7 @@ function HomeScreenReady({
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useNonReactiveCallback(() => {
|
useNonReactiveCallback(() => {
|
||||||
if (selectedFeed) {
|
if (selectedFeed) {
|
||||||
logEvent('home:feedDisplayed', {
|
logEvent('home:feedDisplayed:sampled', {
|
||||||
index: selectedIndex,
|
index: selectedIndex,
|
||||||
feedType: selectedFeed.split('|')[0],
|
feedType: selectedFeed.split('|')[0],
|
||||||
feedUrl: selectedFeed,
|
feedUrl: selectedFeed,
|
||||||
|
@ -140,9 +140,12 @@ function HomeScreenReady({
|
||||||
)
|
)
|
||||||
|
|
||||||
const onPageSelecting = React.useCallback(
|
const onPageSelecting = React.useCallback(
|
||||||
(index: number, reason: LogEvents['home:feedDisplayed']['reason']) => {
|
(
|
||||||
|
index: number,
|
||||||
|
reason: LogEvents['home:feedDisplayed:sampled']['reason'],
|
||||||
|
) => {
|
||||||
const feed = allFeeds[index]
|
const feed = allFeeds[index]
|
||||||
logEvent('home:feedDisplayed', {
|
logEvent('home:feedDisplayed:sampled', {
|
||||||
index,
|
index,
|
||||||
feedType: feed.split('|')[0],
|
feedType: feed.split('|')[0],
|
||||||
feedUrl: feed,
|
feedUrl: feed,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue