[Statsig] Add more events to downsample, increase downsample rate (#5198)

* add some events for sampling

* include downsample rate in metadata

* fix metadata logic

* uncomment debug
This commit is contained in:
Hailey 2024-09-07 04:13:51 -07:00 committed by GitHub
parent adef9cff10
commit c8be9b78c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 47 additions and 37 deletions

View file

@ -661,16 +661,15 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
linking={LINKING} linking={LINKING}
theme={theme} theme={theme}
onStateChange={() => { onStateChange={() => {
logEvent('router:navigate:sampled', { const routeName = getCurrentRouteName()
from: prevLoggedRouteName.current, if (routeName === 'Notifications') {
}) logEvent('router:navigate:notifications:sampled', {})
prevLoggedRouteName.current = getCurrentRouteName() }
}} }}
onReady={() => { onReady={() => {
attachRouteToLogEvents(getCurrentRouteName) attachRouteToLogEvents(getCurrentRouteName)
logModuleInitTime() logModuleInitTime()
onReady() onReady()
logEvent('router:navigate:sampled', {})
}}> }}>
{children} {children}
</NavigationContainer> </NavigationContainer>

View file

@ -276,8 +276,8 @@ export function DescriptionPlaceholder() {
export type FollowButtonProps = { export type FollowButtonProps = {
profile: AppBskyActorDefs.ProfileViewBasic profile: AppBskyActorDefs.ProfileViewBasic
moderationOpts: ModerationOpts moderationOpts: ModerationOpts
logContext: LogEvents['profile:follow']['logContext'] & logContext: LogEvents['profile:follow:sampled']['logContext'] &
LogEvents['profile:unfollow']['logContext'] LogEvents['profile:unfollow:sampled']['logContext']
} & Partial<ButtonProps> } & Partial<ButtonProps>
export function FollowButton(props: FollowButtonProps) { export function FollowButton(props: FollowButtonProps) {

View file

@ -15,8 +15,8 @@ export function useFollowMethods({
logContext, logContext,
}: { }: {
profile: Shadow<AppBskyActorDefs.ProfileViewBasic> profile: Shadow<AppBskyActorDefs.ProfileViewBasic>
logContext: LogEvents['profile:follow']['logContext'] & logContext: LogEvents['profile:follow:sampled']['logContext'] &
LogEvents['profile:unfollow']['logContext'] LogEvents['profile:unfollow:sampled']['logContext']
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const requireAuth = useRequireAuth() const requireAuth = useRequireAuth()

View file

@ -25,7 +25,7 @@ export type LogEvents = {
secondsActive: number secondsActive: number
} }
'state:foreground:sampled': {} 'state:foreground:sampled': {}
'router:navigate:sampled': {} 'router:navigate:notifications:sampled': {}
'deepLink:referrerReceived': { 'deepLink:referrerReceived': {
to: string to: string
referrer: string referrer: string
@ -127,25 +127,25 @@ export type LogEvents = {
langs: string langs: string
logContext: 'Composer' logContext: 'Composer'
} }
'post:like': { 'post:like:sampled': {
doesLikerFollowPoster: boolean | undefined doesLikerFollowPoster: boolean | undefined
doesPosterFollowLiker: boolean | undefined doesPosterFollowLiker: boolean | undefined
likerClout: number | undefined likerClout: number | undefined
postClout: number | undefined postClout: number | undefined
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' logContext: 'FeedItem' | 'PostThreadItem' | 'Post'
} }
'post:repost': { 'post:repost:sampled': {
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' logContext: 'FeedItem' | 'PostThreadItem' | 'Post'
} }
'post:unlike': { 'post:unlike:sampled': {
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' logContext: 'FeedItem' | 'PostThreadItem' | 'Post'
} }
'post:unrepost': { 'post:unrepost:sampled': {
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' logContext: 'FeedItem' | 'PostThreadItem' | 'Post'
} }
'post:mute': {} 'post:mute': {}
'post:unmute': {} 'post:unmute': {}
'profile:follow': { 'profile:follow:sampled': {
didBecomeMutual: boolean | undefined didBecomeMutual: boolean | undefined
followeeClout: number | undefined followeeClout: number | undefined
followerClout: number | undefined followerClout: number | undefined
@ -162,7 +162,7 @@ export type LogEvents = {
| 'FeedInterstitial' | 'FeedInterstitial'
| 'ProfileHeaderSuggestedFollows' | 'ProfileHeaderSuggestedFollows'
} }
'profile:unfollow': { 'profile:unfollow:sampled': {
logContext: logContext:
| 'RecommendedFollowsItem' | 'RecommendedFollowsItem'
| 'PostThreadItem' | 'PostThreadItem'

View file

@ -89,8 +89,9 @@ export function toClout(n: number | null | undefined): number | undefined {
} }
} }
const DOWNSAMPLE_RATE = 0.95 // 95% likely
const DOWNSAMPLED_EVENTS: Set<keyof LogEvents> = new Set([ const DOWNSAMPLED_EVENTS: Set<keyof LogEvents> = new Set([
'router:navigate:sampled', 'router:navigate:notifications:sampled',
'state:background:sampled', 'state:background:sampled',
'state:foreground:sampled', 'state:foreground:sampled',
'home:feedDisplayed:sampled', 'home:feedDisplayed:sampled',
@ -99,8 +100,14 @@ const DOWNSAMPLED_EVENTS: Set<keyof LogEvents> = new Set([
'discover:clickthrough:sampled', 'discover:clickthrough:sampled',
'discover:engaged:sampled', 'discover:engaged:sampled',
'discover:seen:sampled', 'discover:seen:sampled',
'post:like:sampled',
'post:unlike:sampled',
'post:repost:sampled',
'post:unrepost:sampled',
'profile:follow:sampled',
'profile:unfollow:sampled',
]) ])
const isDownsampledSession = Math.random() < 0.9 // 90% likely const isDownsampledSession = Math.random() < DOWNSAMPLE_RATE
export function logEvent<E extends keyof LogEvents>( export function logEvent<E extends keyof LogEvents>(
eventName: E & string, eventName: E & string,
@ -117,12 +124,16 @@ export function logEvent<E extends keyof LogEvents>(
) )
} }
if (isDownsampledSession && DOWNSAMPLED_EVENTS.has(eventName)) { const isDownsampledEvent = DOWNSAMPLED_EVENTS.has(eventName)
if (isDownsampledSession && isDownsampledEvent) {
return return
} }
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.
if (isDownsampledEvent) {
fullMetadata.downsampleRate = DOWNSAMPLE_RATE.toString()
}
fullMetadata.routeName = getCurrentRouteName() ?? '(Uninitialized)' fullMetadata.routeName = getCurrentRouteName() ?? '(Uninitialized)'
if (Statsig.initializeCalled()) { if (Statsig.initializeCalled()) {
Statsig.logEvent(eventName, null, fullMetadata) Statsig.logEvent(eventName, null, fullMetadata)

View file

@ -99,8 +99,8 @@ export function useGetPosts() {
export function usePostLikeMutationQueue( export function usePostLikeMutationQueue(
post: Shadow<AppBskyFeedDefs.PostView>, post: Shadow<AppBskyFeedDefs.PostView>,
logContext: LogEvents['post:like']['logContext'] & logContext: LogEvents['post:like:sampled']['logContext'] &
LogEvents['post:unlike']['logContext'], LogEvents['post:unlike:sampled']['logContext'],
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const postUri = post.uri const postUri = post.uri
@ -158,7 +158,7 @@ export function usePostLikeMutationQueue(
} }
function usePostLikeMutation( function usePostLikeMutation(
logContext: LogEvents['post:like']['logContext'], logContext: LogEvents['post:like:sampled']['logContext'],
post: Shadow<AppBskyFeedDefs.PostView>, post: Shadow<AppBskyFeedDefs.PostView>,
) { ) {
const {currentAccount} = useSession() const {currentAccount} = useSession()
@ -175,7 +175,7 @@ function usePostLikeMutation(
if (currentAccount) { if (currentAccount) {
ownProfile = findProfileQueryData(queryClient, currentAccount.did) ownProfile = findProfileQueryData(queryClient, currentAccount.did)
} }
logEvent('post:like', { logEvent('post:like:sampled', {
logContext, logContext,
doesPosterFollowLiker: postAuthor.viewer doesPosterFollowLiker: postAuthor.viewer
? Boolean(postAuthor.viewer.followedBy) ? Boolean(postAuthor.viewer.followedBy)
@ -200,12 +200,12 @@ function usePostLikeMutation(
} }
function usePostUnlikeMutation( function usePostUnlikeMutation(
logContext: LogEvents['post:unlike']['logContext'], logContext: LogEvents['post:unlike:sampled']['logContext'],
) { ) {
const agent = useAgent() const agent = useAgent()
return useMutation<void, Error, {postUri: string; likeUri: string}>({ return useMutation<void, Error, {postUri: string; likeUri: string}>({
mutationFn: ({likeUri}) => { mutationFn: ({likeUri}) => {
logEvent('post:unlike', {logContext}) logEvent('post:unlike:sampled', {logContext})
return agent.deleteLike(likeUri) return agent.deleteLike(likeUri)
}, },
onSuccess() { onSuccess() {
@ -216,8 +216,8 @@ function usePostUnlikeMutation(
export function usePostRepostMutationQueue( export function usePostRepostMutationQueue(
post: Shadow<AppBskyFeedDefs.PostView>, post: Shadow<AppBskyFeedDefs.PostView>,
logContext: LogEvents['post:repost']['logContext'] & logContext: LogEvents['post:repost:sampled']['logContext'] &
LogEvents['post:unrepost']['logContext'], LogEvents['post:unrepost:sampled']['logContext'],
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const postUri = post.uri const postUri = post.uri
@ -273,7 +273,7 @@ export function usePostRepostMutationQueue(
} }
function usePostRepostMutation( function usePostRepostMutation(
logContext: LogEvents['post:repost']['logContext'], logContext: LogEvents['post:repost:sampled']['logContext'],
) { ) {
const agent = useAgent() const agent = useAgent()
return useMutation< return useMutation<
@ -282,7 +282,7 @@ function usePostRepostMutation(
{uri: string; cid: string} // the post's uri and cid {uri: string; cid: string} // the post's uri and cid
>({ >({
mutationFn: post => { mutationFn: post => {
logEvent('post:repost', {logContext}) logEvent('post:repost:sampled', {logContext})
return agent.repost(post.uri, post.cid) return agent.repost(post.uri, post.cid)
}, },
onSuccess() { onSuccess() {
@ -292,12 +292,12 @@ function usePostRepostMutation(
} }
function usePostUnrepostMutation( function usePostUnrepostMutation(
logContext: LogEvents['post:unrepost']['logContext'], logContext: LogEvents['post:unrepost:sampled']['logContext'],
) { ) {
const agent = useAgent() const agent = useAgent()
return useMutation<void, Error, {postUri: string; repostUri: string}>({ return useMutation<void, Error, {postUri: string; repostUri: string}>({
mutationFn: ({repostUri}) => { mutationFn: ({repostUri}) => {
logEvent('post:unrepost', {logContext}) logEvent('post:unrepost:sampled', {logContext})
return agent.deleteRepost(repostUri) return agent.deleteRepost(repostUri)
}, },
onSuccess() { onSuccess() {

View file

@ -219,8 +219,8 @@ export function useProfileUpdateMutation() {
export function useProfileFollowMutationQueue( export function useProfileFollowMutationQueue(
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>, profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
logContext: LogEvents['profile:follow']['logContext'] & logContext: LogEvents['profile:follow:sampled']['logContext'] &
LogEvents['profile:unfollow']['logContext'], LogEvents['profile:follow:sampled']['logContext'],
) { ) {
const agent = useAgent() const agent = useAgent()
const queryClient = useQueryClient() const queryClient = useQueryClient()
@ -291,7 +291,7 @@ export function useProfileFollowMutationQueue(
} }
function useProfileFollowMutation( function useProfileFollowMutation(
logContext: LogEvents['profile:follow']['logContext'], logContext: LogEvents['profile:follow:sampled']['logContext'],
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>, profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
) { ) {
const {currentAccount} = useSession() const {currentAccount} = useSession()
@ -306,7 +306,7 @@ function useProfileFollowMutation(
ownProfile = findProfileQueryData(queryClient, currentAccount.did) ownProfile = findProfileQueryData(queryClient, currentAccount.did)
} }
captureAction(ProgressGuideAction.Follow) captureAction(ProgressGuideAction.Follow)
logEvent('profile:follow', { logEvent('profile:follow:sampled', {
logContext, logContext,
didBecomeMutual: profile.viewer didBecomeMutual: profile.viewer
? Boolean(profile.viewer.followedBy) ? Boolean(profile.viewer.followedBy)
@ -323,12 +323,12 @@ function useProfileFollowMutation(
} }
function useProfileUnfollowMutation( function useProfileUnfollowMutation(
logContext: LogEvents['profile:unfollow']['logContext'], logContext: LogEvents['profile:unfollow:sampled']['logContext'],
) { ) {
const agent = useAgent() const agent = useAgent()
return useMutation<void, Error, {did: string; followUri: string}>({ return useMutation<void, Error, {did: string; followUri: string}>({
mutationFn: async ({followUri}) => { mutationFn: async ({followUri}) => {
logEvent('profile:unfollow', {logContext}) logEvent('profile:unfollow:sampled', {logContext})
track('Profile:Unfollow', {username: followUri}) track('Profile:Unfollow', {username: followUri})
return await agent.deleteFollow(followUri) return await agent.deleteFollow(followUri)
}, },