diff options
author | Samuel Newman <mozzius@protonmail.com> | 2025-02-14 19:52:53 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-14 19:52:53 +0000 |
commit | d793abf8cd2cf7edf2ffd4a4cd570db33b795bbf (patch) | |
tree | c6f106cedcdd3e04ecde4b6a9d3adcc5b6da7826 | |
parent | 11616846caa69ee1b2eacc87e1e307b47df223a5 (diff) | |
download | voidsky-d793abf8cd2cf7edf2ffd4a4cd570db33b795bbf.tar.zst |
[Instrumentation] Signin (#7742)
* first pass at instrumenting login * round time taken
-rw-r--r-- | src/lib/statsig/events.ts | 16 | ||||
-rw-r--r-- | src/screens/Login/LoginForm.tsx | 52 | ||||
-rw-r--r-- | src/screens/Login/SetNewPasswordForm.tsx | 4 | ||||
-rw-r--r-- | src/screens/Login/index.tsx | 33 | ||||
-rw-r--r-- | src/view/com/auth/server-input/index.tsx | 6 |
5 files changed, 85 insertions, 26 deletions
diff --git a/src/lib/statsig/events.ts b/src/lib/statsig/events.ts index 9a45a620e..519e3997e 100644 --- a/src/lib/statsig/events.ts +++ b/src/lib/statsig/events.ts @@ -51,6 +51,22 @@ export type LogEvents = { } 'signup:captchaSuccess': {} 'signup:captchaFailure': {} + 'signin:hostingProviderPressed': { + hostingProviderDidChange: boolean + } + 'signin:hostingProviderFailedResolution': {} + 'signin:success': { + failedAttemptsCount: number + isUsingCustomProvider: boolean + timeTakenSeconds: number + } + 'signin:backPressed': { + failedAttemptsCount: number + } + 'signin:forgotPasswordPressed': {} + 'signin:passwordReset': {} + 'signin:passwordResetSuccess': {} + 'signin:passwordResetFailure': {} 'onboarding:interests:nextPressed': { selectedInterests: string[] selectedInterestsLength: number diff --git a/src/screens/Login/LoginForm.tsx b/src/screens/Login/LoginForm.tsx index 86e541b3e..134046ff3 100644 --- a/src/screens/Login/LoginForm.tsx +++ b/src/screens/Login/LoginForm.tsx @@ -45,6 +45,8 @@ export const LoginForm = ({ onPressRetryConnect, onPressBack, onPressForgotPassword, + onAttemptSuccess, + onAttemptFailed, }: { error: string serviceUrl: string @@ -55,6 +57,8 @@ export const LoginForm = ({ onPressRetryConnect: () => void onPressBack: () => void onPressForgotPassword: () => void + onAttemptSuccess: () => void + onAttemptFailed: () => void }) => { const t = useTheme() const [isProcessing, setIsProcessing] = useState<boolean>(false) @@ -131,6 +135,7 @@ export const LoginForm = ({ }, 'LoginForm', ) + onAttemptSuccess() setShowLoggedOut(false) setHasCheckedForStarterPack(true) requestNotificationsPermission('Login') @@ -142,29 +147,32 @@ export const LoginForm = ({ e instanceof ComAtprotoServerCreateSession.AuthFactorTokenRequiredError ) { setIsAuthFactorTokenNeeded(true) - } else if (errMsg.includes('Token is invalid')) { - logger.debug('Failed to login due to invalid 2fa token', { - error: errMsg, - }) - setError(_(msg`Invalid 2FA confirmation code.`)) - } else if ( - errMsg.includes('Authentication Required') || - errMsg.includes('Invalid identifier or password') - ) { - logger.debug('Failed to login due to invalid credentials', { - error: errMsg, - }) - setError(_(msg`Incorrect username or password`)) - } else if (isNetworkError(e)) { - logger.warn('Failed to login due to network error', {error: errMsg}) - setError( - _( - msg`Unable to contact your service. Please check your Internet connection.`, - ), - ) } else { - logger.warn('Failed to login', {error: errMsg}) - setError(cleanError(errMsg)) + onAttemptFailed() + if (errMsg.includes('Token is invalid')) { + logger.debug('Failed to login due to invalid 2fa token', { + error: errMsg, + }) + setError(_(msg`Invalid 2FA confirmation code.`)) + } else if ( + errMsg.includes('Authentication Required') || + errMsg.includes('Invalid identifier or password') + ) { + logger.debug('Failed to login due to invalid credentials', { + error: errMsg, + }) + setError(_(msg`Incorrect username or password`)) + } else if (isNetworkError(e)) { + logger.warn('Failed to login due to network error', {error: errMsg}) + setError( + _( + msg`Unable to contact your service. Please check your Internet connection.`, + ), + ) + } else { + logger.warn('Failed to login', {error: errMsg}) + setError(cleanError(errMsg)) + } } } } diff --git a/src/screens/Login/SetNewPasswordForm.tsx b/src/screens/Login/SetNewPasswordForm.tsx index 0eb3ecce8..d78a856cb 100644 --- a/src/screens/Login/SetNewPasswordForm.tsx +++ b/src/screens/Login/SetNewPasswordForm.tsx @@ -4,6 +4,7 @@ import {BskyAgent} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' +import {logEvent} from '#/lib/statsig/statsig' import {isNetworkError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors' import {checkAndFormatResetCode} from '#/lib/strings/password' @@ -48,6 +49,7 @@ export const SetNewPasswordForm = ({ msg`You have entered an invalid code. It should look like XXXXX-XXXXX.`, ), ) + logEvent('signin:passwordResetFailure', {}) return } @@ -67,9 +69,11 @@ export const SetNewPasswordForm = ({ password, }) onPasswordSet() + logEvent('signin:passwordResetSuccess', {}) } catch (e: any) { const errMsg = e.toString() logger.warn('Failed to set new password', {error: e}) + logEvent('signin:passwordResetFailure', {}) setIsProcessing(false) if (isNetworkError(e)) { setError( diff --git a/src/screens/Login/index.tsx b/src/screens/Login/index.tsx index b46f8d26b..8ed8d2da8 100644 --- a/src/screens/Login/index.tsx +++ b/src/screens/Login/index.tsx @@ -1,10 +1,11 @@ -import React from 'react' +import React, {useRef} from 'react' import {KeyboardAvoidingView} from 'react-native' import {LayoutAnimationConfig} from 'react-native-reanimated' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {DEFAULT_SERVICE} from '#/lib/constants' +import {logEvent} from '#/lib/statsig/statsig' import {logger} from '#/logger' import {useServiceQuery} from '#/state/queries/service' import {SessionAccount, useSession} from '#/state/session' @@ -28,6 +29,8 @@ enum Forms { export const Login = ({onPressBack}: {onPressBack: () => void}) => { const {_} = useLingui() + const failedAttemptCountRef = useRef(0) + const startTimeRef = useRef(Date.now()) const {accounts} = useSession() const {requestedAccountSwitchTo} = useLoggedOutView() @@ -79,6 +82,7 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => { logger.warn(`Failed to fetch service description for ${serviceUrl}`, { error: String(serviceError), }) + logEvent('signin:hostingProviderFailedResolution', {}) } else { setError('') } @@ -86,6 +90,27 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => { const onPressForgotPassword = () => { setCurrentForm(Forms.ForgotPassword) + logEvent('signin:forgotPasswordPressed', {}) + } + + const handlePressBack = () => { + onPressBack() + logEvent('signin:backPressed', { + failedAttemptsCount: failedAttemptCountRef.current, + }) + } + + const onAttemptSuccess = () => { + logEvent('signin:success', { + isUsingCustomProvider: serviceUrl !== DEFAULT_SERVICE, + timeTakenSeconds: Math.round((Date.now() - startTimeRef.current) / 1000), + failedAttemptsCount: failedAttemptCountRef.current, + }) + setCurrentForm(Forms.Login) + } + + const onAttemptFailed = () => { + failedAttemptCountRef.current += 1 } let content = null @@ -103,9 +128,11 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => { serviceDescription={serviceDescription} initialHandle={initialHandle} setError={setError} + onAttemptFailed={onAttemptFailed} + onAttemptSuccess={onAttemptSuccess} setServiceUrl={setServiceUrl} onPressBack={() => - accounts.length ? gotoForm(Forms.ChooseAccount) : onPressBack() + accounts.length ? gotoForm(Forms.ChooseAccount) : handlePressBack() } onPressForgotPassword={onPressForgotPassword} onPressRetryConnect={refetchService} @@ -118,7 +145,7 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => { content = ( <ChooseAccountForm onSelectAccount={onSelectAccount} - onPressBack={onPressBack} + onPressBack={handlePressBack} /> ) break diff --git a/src/view/com/auth/server-input/index.tsx b/src/view/com/auth/server-input/index.tsx index 7c0bda45b..9fd426a9b 100644 --- a/src/view/com/auth/server-input/index.tsx +++ b/src/view/com/auth/server-input/index.tsx @@ -5,6 +5,7 @@ import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {BSKY_SERVICE} from '#/lib/constants' +import {logEvent} from '#/lib/statsig/statsig' import * as persisted from '#/state/persisted' import {useSession} from '#/state/session' import {atoms as a, useBreakpoints, useTheme} from '#/alf' @@ -39,7 +40,10 @@ export function ServerInputDialog({ setPreviousCustomAddress(result) } } - }, [onSelect]) + logEvent('signin:hostingProviderPressed', { + hostingProviderDidChange: fixedOption !== BSKY_SERVICE, + }) + }, [onSelect, fixedOption]) return ( <Dialog.Outer |