diff --git a/src/Navigation.tsx b/src/Navigation.tsx index 0bf0e9f9..2beba4f9 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -661,16 +661,15 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) { linking={LINKING} theme={theme} onStateChange={() => { - logEvent('router:navigate:sampled', { - from: prevLoggedRouteName.current, - }) - prevLoggedRouteName.current = getCurrentRouteName() + const routeName = getCurrentRouteName() + if (routeName === 'Notifications') { + logEvent('router:navigate:notifications:sampled', {}) + } }} onReady={() => { attachRouteToLogEvents(getCurrentRouteName) logModuleInitTime() onReady() - logEvent('router:navigate:sampled', {}) }}> {children} diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx index a263d194..6f6d6804 100644 --- a/src/components/ProfileCard.tsx +++ b/src/components/ProfileCard.tsx @@ -276,8 +276,8 @@ export function DescriptionPlaceholder() { export type FollowButtonProps = { profile: AppBskyActorDefs.ProfileViewBasic moderationOpts: ModerationOpts - logContext: LogEvents['profile:follow']['logContext'] & - LogEvents['profile:unfollow']['logContext'] + logContext: LogEvents['profile:follow:sampled']['logContext'] & + LogEvents['profile:unfollow:sampled']['logContext'] } & Partial export function FollowButton(props: FollowButtonProps) { diff --git a/src/components/hooks/useFollowMethods.ts b/src/components/hooks/useFollowMethods.ts index d67c3690..31a1e43d 100644 --- a/src/components/hooks/useFollowMethods.ts +++ b/src/components/hooks/useFollowMethods.ts @@ -15,8 +15,8 @@ export function useFollowMethods({ logContext, }: { profile: Shadow - logContext: LogEvents['profile:follow']['logContext'] & - LogEvents['profile:unfollow']['logContext'] + logContext: LogEvents['profile:follow:sampled']['logContext'] & + LogEvents['profile:unfollow:sampled']['logContext'] }) { const {_} = useLingui() const requireAuth = useRequireAuth() diff --git a/src/lib/statsig/events.ts b/src/lib/statsig/events.ts index 4768bdc2..18718949 100644 --- a/src/lib/statsig/events.ts +++ b/src/lib/statsig/events.ts @@ -25,7 +25,7 @@ export type LogEvents = { secondsActive: number } 'state:foreground:sampled': {} - 'router:navigate:sampled': {} + 'router:navigate:notifications:sampled': {} 'deepLink:referrerReceived': { to: string referrer: string @@ -127,25 +127,25 @@ export type LogEvents = { langs: string logContext: 'Composer' } - 'post:like': { + 'post:like:sampled': { doesLikerFollowPoster: boolean | undefined doesPosterFollowLiker: boolean | undefined likerClout: number | undefined postClout: number | undefined logContext: 'FeedItem' | 'PostThreadItem' | 'Post' } - 'post:repost': { + 'post:repost:sampled': { logContext: 'FeedItem' | 'PostThreadItem' | 'Post' } - 'post:unlike': { + 'post:unlike:sampled': { logContext: 'FeedItem' | 'PostThreadItem' | 'Post' } - 'post:unrepost': { + 'post:unrepost:sampled': { logContext: 'FeedItem' | 'PostThreadItem' | 'Post' } 'post:mute': {} 'post:unmute': {} - 'profile:follow': { + 'profile:follow:sampled': { didBecomeMutual: boolean | undefined followeeClout: number | undefined followerClout: number | undefined @@ -162,7 +162,7 @@ export type LogEvents = { | 'FeedInterstitial' | 'ProfileHeaderSuggestedFollows' } - 'profile:unfollow': { + 'profile:unfollow:sampled': { logContext: | 'RecommendedFollowsItem' | 'PostThreadItem' diff --git a/src/lib/statsig/statsig.tsx b/src/lib/statsig/statsig.tsx index 7d86f407..c50bfeb8 100644 --- a/src/lib/statsig/statsig.tsx +++ b/src/lib/statsig/statsig.tsx @@ -89,8 +89,9 @@ export function toClout(n: number | null | undefined): number | undefined { } } +const DOWNSAMPLE_RATE = 0.95 // 95% likely const DOWNSAMPLED_EVENTS: Set = new Set([ - 'router:navigate:sampled', + 'router:navigate:notifications:sampled', 'state:background:sampled', 'state:foreground:sampled', 'home:feedDisplayed:sampled', @@ -99,8 +100,14 @@ const DOWNSAMPLED_EVENTS: Set = new Set([ 'discover:clickthrough:sampled', 'discover:engaged: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( eventName: E & string, @@ -117,12 +124,16 @@ export function logEvent( ) } - if (isDownsampledSession && DOWNSAMPLED_EVENTS.has(eventName)) { + const isDownsampledEvent = DOWNSAMPLED_EVENTS.has(eventName) + if (isDownsampledSession && isDownsampledEvent) { return } const fullMetadata = { ...rawMetadata, } as Record // Statsig typings are unnecessarily strict here. + if (isDownsampledEvent) { + fullMetadata.downsampleRate = DOWNSAMPLE_RATE.toString() + } fullMetadata.routeName = getCurrentRouteName() ?? '(Uninitialized)' if (Statsig.initializeCalled()) { Statsig.logEvent(eventName, null, fullMetadata) diff --git a/src/state/queries/post.ts b/src/state/queries/post.ts index 197903be..982d224a 100644 --- a/src/state/queries/post.ts +++ b/src/state/queries/post.ts @@ -99,8 +99,8 @@ export function useGetPosts() { export function usePostLikeMutationQueue( post: Shadow, - logContext: LogEvents['post:like']['logContext'] & - LogEvents['post:unlike']['logContext'], + logContext: LogEvents['post:like:sampled']['logContext'] & + LogEvents['post:unlike:sampled']['logContext'], ) { const queryClient = useQueryClient() const postUri = post.uri @@ -158,7 +158,7 @@ export function usePostLikeMutationQueue( } function usePostLikeMutation( - logContext: LogEvents['post:like']['logContext'], + logContext: LogEvents['post:like:sampled']['logContext'], post: Shadow, ) { const {currentAccount} = useSession() @@ -175,7 +175,7 @@ function usePostLikeMutation( if (currentAccount) { ownProfile = findProfileQueryData(queryClient, currentAccount.did) } - logEvent('post:like', { + logEvent('post:like:sampled', { logContext, doesPosterFollowLiker: postAuthor.viewer ? Boolean(postAuthor.viewer.followedBy) @@ -200,12 +200,12 @@ function usePostLikeMutation( } function usePostUnlikeMutation( - logContext: LogEvents['post:unlike']['logContext'], + logContext: LogEvents['post:unlike:sampled']['logContext'], ) { const agent = useAgent() return useMutation({ mutationFn: ({likeUri}) => { - logEvent('post:unlike', {logContext}) + logEvent('post:unlike:sampled', {logContext}) return agent.deleteLike(likeUri) }, onSuccess() { @@ -216,8 +216,8 @@ function usePostUnlikeMutation( export function usePostRepostMutationQueue( post: Shadow, - logContext: LogEvents['post:repost']['logContext'] & - LogEvents['post:unrepost']['logContext'], + logContext: LogEvents['post:repost:sampled']['logContext'] & + LogEvents['post:unrepost:sampled']['logContext'], ) { const queryClient = useQueryClient() const postUri = post.uri @@ -273,7 +273,7 @@ export function usePostRepostMutationQueue( } function usePostRepostMutation( - logContext: LogEvents['post:repost']['logContext'], + logContext: LogEvents['post:repost:sampled']['logContext'], ) { const agent = useAgent() return useMutation< @@ -282,7 +282,7 @@ function usePostRepostMutation( {uri: string; cid: string} // the post's uri and cid >({ mutationFn: post => { - logEvent('post:repost', {logContext}) + logEvent('post:repost:sampled', {logContext}) return agent.repost(post.uri, post.cid) }, onSuccess() { @@ -292,12 +292,12 @@ function usePostRepostMutation( } function usePostUnrepostMutation( - logContext: LogEvents['post:unrepost']['logContext'], + logContext: LogEvents['post:unrepost:sampled']['logContext'], ) { const agent = useAgent() return useMutation({ mutationFn: ({repostUri}) => { - logEvent('post:unrepost', {logContext}) + logEvent('post:unrepost:sampled', {logContext}) return agent.deleteRepost(repostUri) }, onSuccess() { diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index 6682cf3c..532b005c 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -219,8 +219,8 @@ export function useProfileUpdateMutation() { export function useProfileFollowMutationQueue( profile: Shadow, - logContext: LogEvents['profile:follow']['logContext'] & - LogEvents['profile:unfollow']['logContext'], + logContext: LogEvents['profile:follow:sampled']['logContext'] & + LogEvents['profile:follow:sampled']['logContext'], ) { const agent = useAgent() const queryClient = useQueryClient() @@ -291,7 +291,7 @@ export function useProfileFollowMutationQueue( } function useProfileFollowMutation( - logContext: LogEvents['profile:follow']['logContext'], + logContext: LogEvents['profile:follow:sampled']['logContext'], profile: Shadow, ) { const {currentAccount} = useSession() @@ -306,7 +306,7 @@ function useProfileFollowMutation( ownProfile = findProfileQueryData(queryClient, currentAccount.did) } captureAction(ProgressGuideAction.Follow) - logEvent('profile:follow', { + logEvent('profile:follow:sampled', { logContext, didBecomeMutual: profile.viewer ? Boolean(profile.viewer.followedBy) @@ -323,12 +323,12 @@ function useProfileFollowMutation( } function useProfileUnfollowMutation( - logContext: LogEvents['profile:unfollow']['logContext'], + logContext: LogEvents['profile:unfollow:sampled']['logContext'], ) { const agent = useAgent() return useMutation({ mutationFn: async ({followUri}) => { - logEvent('profile:unfollow', {logContext}) + logEvent('profile:unfollow:sampled', {logContext}) track('Profile:Unfollow', {username: followUri}) return await agent.deleteFollow(followUri) },