[APP-1782] Analytics migration (#9734)
* WIP * Clean up growthbook code, integrate into init and sessions * Move everything out of React * Add metrics client * Move to separate file * Shared metadata cache * Ensure we update metadata when session ID changes * Ensure userMetadata is cleared when logging out * WIP revamp * Integrate feature gates into analytics context * Clean up old code * Fix useMeta util * Some comments and cleanup * Add logger to base analytics context * Refactor current route handling * Rip out LogEvent from navigation * Update tracking endpoint * Migrate toClout * Clear out statsig client * Add todo, reset logger readme * Ope fix statsig noop * Refactor logging in feed-feedback, add debug logging to metrics client * Remove LogEvents alias for Metrics * Prefer root package export * Remove Metrics alias from logger * [APP-1782] Migrate to new analytics APIs (#9735) * Migrate logEvent to useAnalytics * Migrate logger.metric to useAnalytics * Migrate tricky spot, fix types * Migrate remaining tricky spot * Missed one * Remove metric() from logger * Migrate useGate to useAnalytics * Remove all other StatSig mentions * Update event payload * Update logger tests * Mock expo method * Fix session ID bug * Add session ID test * Add test for metrics client * Clarify intent * Clean up core analytics file * Clean up the call once utils * Fix TODO * Fix TODO * Fix TODO * Fix TODO * Fix TODO * Remove debug code * Fix navigation context * OK nav context is not working, todo * Checkpoint: works but feels hacky * Fix navigation context issue * Improve feature API * Improve metric logging * Update logger tests
This commit is contained in:
@@ -45,7 +45,29 @@ describe('general functionality', () => {
|
||||
|
||||
logger.addTransport(mockTransport)
|
||||
|
||||
const extra = {foo: true}
|
||||
const extra = {foo: true, __metadata__: {}}
|
||||
logger.warn('message', extra)
|
||||
|
||||
expect(mockTransport).toHaveBeenCalledWith(
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
'message',
|
||||
extra,
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
|
||||
test('supports inherited metadata', () => {
|
||||
const timestamp = Date.now()
|
||||
const logger = new Logger({
|
||||
metadata: {bar: true},
|
||||
})
|
||||
|
||||
const mockTransport = jest.fn()
|
||||
|
||||
logger.addTransport(mockTransport)
|
||||
|
||||
const extra = {foo: true, __metadata__: {bar: true}}
|
||||
logger.warn('message', extra)
|
||||
|
||||
expect(mockTransport).toHaveBeenCalledWith(
|
||||
@@ -71,7 +93,7 @@ describe('general functionality', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
'a',
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -81,7 +103,7 @@ describe('general functionality', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
'b',
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -91,7 +113,7 @@ describe('general functionality', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
'c',
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -256,7 +278,7 @@ describe('general functionality', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
'warn',
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -276,7 +298,7 @@ describe('create', () => {
|
||||
LogLevel.Info,
|
||||
Logger.Context.Default,
|
||||
message,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -300,7 +322,7 @@ describe('debug contexts', () => {
|
||||
LogLevel.Debug,
|
||||
'specific',
|
||||
message,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -323,7 +345,7 @@ describe('debug contexts', () => {
|
||||
LogLevel.Debug,
|
||||
'namespace:foo',
|
||||
message,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -345,7 +367,7 @@ describe('debug contexts', () => {
|
||||
LogLevel.Debug,
|
||||
'namespace:bar:baz',
|
||||
message,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -367,7 +389,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Debug,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -376,7 +398,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Info,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -385,7 +407,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -395,7 +417,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Error,
|
||||
undefined,
|
||||
e,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -418,7 +440,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Info,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -444,7 +466,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -474,7 +496,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Error,
|
||||
undefined,
|
||||
e,
|
||||
{},
|
||||
{__metadata__: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import {nanoid} from 'nanoid/non-secure'
|
||||
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {add} from '#/logger/logDump'
|
||||
import {type MetricEvents} from '#/logger/metrics'
|
||||
import {consoleTransport} from '#/logger/transports/console'
|
||||
import {sentryTransport} from '#/logger/transports/sentry'
|
||||
import {
|
||||
@@ -14,8 +12,6 @@ import {
|
||||
import {enabledLogLevels} from '#/logger/util'
|
||||
import {ENV} from '#/env'
|
||||
|
||||
export {type MetricEvents as Metrics} from '#/logger/metrics'
|
||||
|
||||
const TRANSPORTS: Transport[] = (function configureTransports() {
|
||||
switch (ENV) {
|
||||
case 'production': {
|
||||
@@ -37,15 +33,17 @@ export class Logger {
|
||||
level: LogLevel
|
||||
context: LogContext | undefined = undefined
|
||||
contextFilter: string = ''
|
||||
ambientMetadata: Record<string, unknown> = {}
|
||||
|
||||
protected debugContextRegexes: RegExp[] = []
|
||||
protected transports: Transport[] = []
|
||||
|
||||
static create(context?: LogContext) {
|
||||
static create(context?: LogContext, metadata: Record<string, unknown> = {}) {
|
||||
const logger = new Logger({
|
||||
level: process.env.EXPO_PUBLIC_LOG_LEVEL as LogLevel,
|
||||
context,
|
||||
contextFilter: process.env.EXPO_PUBLIC_LOG_DEBUG || '',
|
||||
metadata,
|
||||
})
|
||||
for (const transport of TRANSPORTS) {
|
||||
logger.addTransport(transport)
|
||||
@@ -57,14 +55,17 @@ export class Logger {
|
||||
level,
|
||||
context,
|
||||
contextFilter,
|
||||
metadata: ambientMetadata = {},
|
||||
}: {
|
||||
level?: LogLevel
|
||||
context?: LogContext
|
||||
contextFilter?: string
|
||||
metadata?: Record<string, unknown>
|
||||
} = {}) {
|
||||
this.context = context
|
||||
this.level = level || LogLevel.Info
|
||||
this.contextFilter = contextFilter || ''
|
||||
this.ambientMetadata = ambientMetadata
|
||||
if (this.contextFilter) {
|
||||
this.level = LogLevel.Debug
|
||||
}
|
||||
@@ -95,25 +96,6 @@ export class Logger {
|
||||
this.transport({level: LogLevel.Error, message: error, metadata})
|
||||
}
|
||||
|
||||
metric<E extends keyof MetricEvents>(
|
||||
event: E & string,
|
||||
metadata: MetricEvents[E],
|
||||
options: {
|
||||
/**
|
||||
* Optionally also send to StatSig
|
||||
*/
|
||||
statsig?: boolean
|
||||
} = {statsig: true},
|
||||
) {
|
||||
logEvent(event, metadata, {
|
||||
lake: !options.statsig,
|
||||
})
|
||||
|
||||
for (const transport of this.transports) {
|
||||
transport(LogLevel.Info, LogContext.Metric, event, metadata, Date.now())
|
||||
}
|
||||
}
|
||||
|
||||
addTransport(transport: Transport) {
|
||||
this.transports.push(transport)
|
||||
return () => {
|
||||
@@ -139,7 +121,10 @@ export class Logger {
|
||||
return
|
||||
|
||||
const timestamp = Date.now()
|
||||
const meta = metadata || {}
|
||||
const meta: Metadata = {
|
||||
__metadata__: this.ambientMetadata,
|
||||
...metadata,
|
||||
}
|
||||
|
||||
// send every log to syslog
|
||||
add({
|
||||
@@ -1,823 +0,0 @@
|
||||
import {type NotificationReason} from '#/lib/hooks/useNotificationHandler'
|
||||
import {type FeedDescriptor} from '#/state/queries/post-feed'
|
||||
import {type LiveEventFeedMetricContext} from '#/features/liveEvents/types'
|
||||
|
||||
export type MetricEvents = {
|
||||
// App events
|
||||
init: {
|
||||
initMs: number
|
||||
}
|
||||
'account:loggedIn': {
|
||||
logContext:
|
||||
| 'LoginForm'
|
||||
| 'SwitchAccount'
|
||||
| 'ChooseAccountForm'
|
||||
| 'Settings'
|
||||
| 'Notification'
|
||||
withPassword: boolean
|
||||
}
|
||||
'account:loggedOut': {
|
||||
logContext:
|
||||
| 'SwitchAccount'
|
||||
| 'Settings'
|
||||
| 'SignupQueued'
|
||||
| 'Deactivated'
|
||||
| 'Takendown'
|
||||
| 'AgeAssuranceNoAccessScreen'
|
||||
scope: 'current' | 'every'
|
||||
}
|
||||
'notifications:openApp': {
|
||||
reason: NotificationReason
|
||||
causedBoot: boolean
|
||||
}
|
||||
'notifications:request': {
|
||||
context: 'StartOnboarding' | 'AfterOnboarding' | 'Login' | 'Home'
|
||||
status: 'granted' | 'denied' | 'undetermined'
|
||||
}
|
||||
'state:background': {
|
||||
secondsActive: number
|
||||
}
|
||||
'state:foreground': {}
|
||||
'router:navigate': {
|
||||
from?: string
|
||||
}
|
||||
'deepLink:referrerReceived': {
|
||||
to: string
|
||||
referrer: string
|
||||
hostname: string
|
||||
}
|
||||
|
||||
// Screen events
|
||||
'splash:signInPressed': {}
|
||||
'splash:createAccountPressed': {}
|
||||
'welcomeModal:signupClicked': {}
|
||||
'welcomeModal:exploreClicked': {}
|
||||
'welcomeModal:signinClicked': {}
|
||||
'welcomeModal:dismissed': {}
|
||||
'welcomeModal:presented': {}
|
||||
'signup:nextPressed': {
|
||||
activeStep: number
|
||||
phoneVerificationRequired?: boolean
|
||||
}
|
||||
'signup:backPressed': {
|
||||
activeStep: number
|
||||
}
|
||||
'signup:captchaSuccess': {}
|
||||
'signup:captchaFailure': {}
|
||||
'signup:fieldError': {
|
||||
field: string
|
||||
errorCount: number
|
||||
errorMessage: string
|
||||
activeStep: number
|
||||
}
|
||||
'signup:backgrounded': {
|
||||
activeStep: number
|
||||
backgroundCount: number
|
||||
}
|
||||
'signup:handleTaken': {typeahead?: boolean}
|
||||
'signup:handleAvailable': {typeahead?: boolean}
|
||||
'signup:handleSuggestionSelected': {method: string}
|
||||
'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
|
||||
}
|
||||
'onboarding:suggestedAccounts:tabPressed': {
|
||||
tab: string
|
||||
}
|
||||
'onboarding:suggestedAccounts:followAllPressed': {
|
||||
tab: string
|
||||
numAccounts: number
|
||||
}
|
||||
'onboarding:suggestedAccounts:nextPressed': {
|
||||
selectedAccountsLength: number
|
||||
skipped: boolean
|
||||
}
|
||||
'onboarding:followingFeed:nextPressed': {}
|
||||
'onboarding:algoFeeds:nextPressed': {
|
||||
selectedPrimaryFeeds: string[]
|
||||
selectedPrimaryFeedsLength: number
|
||||
selectedSecondaryFeeds: string[]
|
||||
selectedSecondaryFeedsLength: number
|
||||
}
|
||||
'onboarding:topicalFeeds:nextPressed': {
|
||||
selectedFeeds: string[]
|
||||
selectedFeedsLength: number
|
||||
}
|
||||
'onboarding:moderation:nextPressed': {}
|
||||
'onboarding:profile:nextPressed': {}
|
||||
'onboarding:finished:nextPressed': {
|
||||
usedStarterPack: boolean
|
||||
starterPackName?: string
|
||||
starterPackCreator?: string
|
||||
starterPackUri?: string
|
||||
profilesFollowed: number
|
||||
feedsPinned: number
|
||||
}
|
||||
'onboarding:finished:avatarResult': {
|
||||
avatarResult: 'default' | 'created' | 'uploaded'
|
||||
}
|
||||
'onboarding:valueProp:stepOne:nextPressed': {}
|
||||
'onboarding:valueProp:stepTwo:nextPressed': {}
|
||||
'onboarding:valueProp:skipPressed': {}
|
||||
'home:feedDisplayed': {
|
||||
feedUrl: string
|
||||
feedType: string
|
||||
index: number
|
||||
}
|
||||
'feed:endReached': {
|
||||
feedUrl: string
|
||||
feedType: string
|
||||
itemCount: number
|
||||
}
|
||||
'feed:refresh': {
|
||||
feedUrl: string
|
||||
feedType: string
|
||||
reason: 'pull-to-refresh' | 'soft-reset' | 'load-latest'
|
||||
}
|
||||
'feed:save': {
|
||||
feedUrl: string
|
||||
}
|
||||
'feed:unsave': {
|
||||
feedUrl: string
|
||||
}
|
||||
'feed:pin': {
|
||||
feedUrl: string
|
||||
}
|
||||
'feed:unpin': {
|
||||
feedUrl: string
|
||||
}
|
||||
'feed:like': {
|
||||
feedUrl: string
|
||||
}
|
||||
'feed:unlike': {
|
||||
feedUrl: string
|
||||
}
|
||||
'feed:share': {
|
||||
feedUrl: string
|
||||
}
|
||||
'feed:suggestion:seen': {
|
||||
feedUrl: string
|
||||
}
|
||||
'feed:suggestion:press': {
|
||||
feedUrl: string
|
||||
}
|
||||
'post:showMore': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:showLess': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'feed:clickthrough': {
|
||||
feed: string
|
||||
count: number
|
||||
}
|
||||
'feed:engaged': {
|
||||
feed: string
|
||||
count: number
|
||||
}
|
||||
'feed:seen': {
|
||||
feed: string
|
||||
count: number
|
||||
}
|
||||
|
||||
'feed:discover:emptyError': {
|
||||
userDid: string
|
||||
}
|
||||
|
||||
'composer:gif:open': {}
|
||||
'composer:gif:select': {}
|
||||
'composerPrompt:press': {}
|
||||
'composerPrompt:camera:press': {}
|
||||
'composerPrompt:gallery:press': {}
|
||||
|
||||
'composer:threadgate:open': {
|
||||
nudged: boolean
|
||||
}
|
||||
'composer:threadgate:save': {
|
||||
replyOptions: string
|
||||
quotesEnabled: boolean
|
||||
persist: boolean
|
||||
hasChanged: boolean
|
||||
}
|
||||
|
||||
// Data events
|
||||
'account:create:begin': {}
|
||||
'account:create:success': {
|
||||
signupDuration: number
|
||||
fieldErrorsTotal: number
|
||||
backgroundCount: number
|
||||
}
|
||||
'post:create': {
|
||||
imageCount: number
|
||||
isReply: boolean
|
||||
isPartOfThread: boolean
|
||||
hasLink: boolean
|
||||
hasQuote: boolean
|
||||
langs: string
|
||||
logContext: 'Composer'
|
||||
}
|
||||
'thread:create': {
|
||||
postCount: number
|
||||
isReply: boolean
|
||||
}
|
||||
'post:like': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
doesLikerFollowPoster: boolean | undefined
|
||||
doesPosterFollowLiker: boolean | undefined
|
||||
likerClout: number | undefined
|
||||
postClout: number | undefined
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
}
|
||||
'post:repost': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
}
|
||||
'post:unlike': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
}
|
||||
'post:unrepost': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
}
|
||||
'post:mute': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:unmute': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:pin': {}
|
||||
'post:unpin': {}
|
||||
'post:bookmark': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:unbookmark': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:clickReply': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:clickQuotePost': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:clickthroughAuthor': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:clickthroughItem': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:clickthroughEmbed': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'post:view': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext:
|
||||
| 'FeedItem'
|
||||
| 'PostThreadItem'
|
||||
| 'Post'
|
||||
| 'ImmersiveVideo'
|
||||
| 'SearchResults'
|
||||
| 'Bookmarks'
|
||||
| 'Notifications'
|
||||
| 'Hashtag'
|
||||
| 'Topic'
|
||||
| 'PostQuotes'
|
||||
feedDescriptor?: string
|
||||
position?: number
|
||||
}
|
||||
'bookmarks:view': {}
|
||||
'bookmarks:post-clicked': {}
|
||||
'profile:follow': {
|
||||
contextProfileDid?: string
|
||||
didBecomeMutual: boolean | undefined
|
||||
followeeClout: number | undefined
|
||||
followeeDid: string
|
||||
followerClout: number | undefined
|
||||
position?: number
|
||||
logContext:
|
||||
| 'RecommendedFollowsItem'
|
||||
| 'PostThreadItem'
|
||||
| 'ProfileCard'
|
||||
| 'ProfileHeader'
|
||||
| 'ProfileHeaderSuggestedFollows'
|
||||
| 'ProfileMenu'
|
||||
| 'ProfileHoverCard'
|
||||
| 'AvatarButton'
|
||||
| 'StarterPackProfilesList'
|
||||
| 'FeedInterstitial'
|
||||
| 'ProfileHeaderSuggestedFollows'
|
||||
| 'PostOnboardingFindFollows'
|
||||
| 'ImmersiveVideo'
|
||||
| 'ExploreSuggestedAccounts'
|
||||
| 'OnboardingSuggestedAccounts'
|
||||
| 'FindContacts'
|
||||
}
|
||||
'profile:followers:view': {
|
||||
contextProfileDid: string
|
||||
isOwnProfile: boolean
|
||||
}
|
||||
'profile:followers:paginate': {
|
||||
contextProfileDid: string
|
||||
itemCount: number
|
||||
page: number
|
||||
}
|
||||
'profile:following:view': {
|
||||
contextProfileDid: string
|
||||
isOwnProfile: boolean
|
||||
}
|
||||
'profile:following:paginate': {
|
||||
contextProfileDid: string
|
||||
itemCount: number
|
||||
page: number
|
||||
}
|
||||
'profileCard:seen': {
|
||||
contextProfileDid?: string
|
||||
profileDid: string
|
||||
position?: number
|
||||
}
|
||||
'suggestedUser:follow': {
|
||||
logContext:
|
||||
| 'Explore'
|
||||
| 'InterstitialDiscover'
|
||||
| 'InterstitialProfile'
|
||||
| 'Profile'
|
||||
| 'Onboarding'
|
||||
location: 'Card' | 'Profile'
|
||||
recId?: number
|
||||
position: number
|
||||
suggestedDid: string
|
||||
category: string | null
|
||||
}
|
||||
'suggestedUser:press': {
|
||||
logContext:
|
||||
| 'Explore'
|
||||
| 'InterstitialDiscover'
|
||||
| 'InterstitialProfile'
|
||||
| 'Onboarding'
|
||||
recId?: number
|
||||
position: number
|
||||
suggestedDid: string
|
||||
category: string | null
|
||||
}
|
||||
'suggestedUser:seen': {
|
||||
logContext:
|
||||
| 'Explore'
|
||||
| 'InterstitialDiscover'
|
||||
| 'InterstitialProfile'
|
||||
| 'Profile'
|
||||
| 'Onboarding'
|
||||
| 'ProgressGuide'
|
||||
recId?: number
|
||||
position: number
|
||||
suggestedDid: string
|
||||
category: string | null
|
||||
}
|
||||
'suggestedUser:seeMore': {
|
||||
logContext:
|
||||
| 'Explore'
|
||||
| 'InterstitialDiscover'
|
||||
| 'InterstitialProfile'
|
||||
| 'Profile'
|
||||
| 'Onboarding'
|
||||
}
|
||||
'suggestedUser:dismiss': {
|
||||
logContext: 'InterstitialDiscover' | 'InterstitialProfile'
|
||||
recId?: number
|
||||
position: number
|
||||
suggestedDid: string
|
||||
}
|
||||
'profile:unfollow': {
|
||||
logContext:
|
||||
| 'RecommendedFollowsItem'
|
||||
| 'PostThreadItem'
|
||||
| 'ProfileCard'
|
||||
| 'ProfileHeader'
|
||||
| 'ProfileHeaderSuggestedFollows'
|
||||
| 'ProfileMenu'
|
||||
| 'ProfileHoverCard'
|
||||
| 'Chat'
|
||||
| 'AvatarButton'
|
||||
| 'StarterPackProfilesList'
|
||||
| 'FeedInterstitial'
|
||||
| 'ProfileHeaderSuggestedFollows'
|
||||
| 'PostOnboardingFindFollows'
|
||||
| 'ImmersiveVideo'
|
||||
| 'ExploreSuggestedAccounts'
|
||||
| 'OnboardingSuggestedAccounts'
|
||||
| 'FindContacts'
|
||||
}
|
||||
'chat:create': {
|
||||
logContext: 'ProfileHeader' | 'NewChatDialog' | 'SendViaChatDialog'
|
||||
}
|
||||
'chat:open': {
|
||||
logContext:
|
||||
| 'ProfileHeader'
|
||||
| 'NewChatDialog'
|
||||
| 'ChatsList'
|
||||
| 'SendViaChatDialog'
|
||||
}
|
||||
'starterPack:addUser': {
|
||||
starterPack?: string
|
||||
}
|
||||
'starterPack:removeUser': {
|
||||
starterPack?: string
|
||||
}
|
||||
'starterPack:share': {
|
||||
starterPack: string
|
||||
shareType: 'link' | 'qrcode'
|
||||
qrShareType?: 'save' | 'copy' | 'share'
|
||||
}
|
||||
'starterPack:followAll': {
|
||||
logContext: 'StarterPackProfilesList' | 'Onboarding'
|
||||
starterPack: string
|
||||
count: number
|
||||
}
|
||||
'starterPack:delete': {}
|
||||
'starterPack:create': {
|
||||
setName: boolean
|
||||
setDescription: boolean
|
||||
profilesCount: number
|
||||
feedsCount: number
|
||||
}
|
||||
'starterPack:ctaPress': {
|
||||
starterPack: string
|
||||
}
|
||||
'starterPack:opened': {
|
||||
starterPack: string
|
||||
}
|
||||
'link:clicked': {
|
||||
url: string
|
||||
domain: string
|
||||
}
|
||||
|
||||
'feed:interstitial:feedCard:press': {}
|
||||
'desktopFeeds:feed:click': {
|
||||
feedUri: string
|
||||
feedDescriptor: string
|
||||
}
|
||||
|
||||
'profile:header:suggestedFollowsCard:press': {}
|
||||
'profile:addToStarterPack': {}
|
||||
|
||||
'test:all:always': {}
|
||||
'test:all:sometimes': {}
|
||||
'test:all:boosted_by_gate1': {reason: 'base' | 'gate1'}
|
||||
'test:all:boosted_by_gate2': {reason: 'base' | 'gate2'}
|
||||
'test:all:boosted_by_both': {reason: 'base' | 'gate1' | 'gate2'}
|
||||
'test:gate1:always': {}
|
||||
'test:gate1:sometimes': {}
|
||||
'test:gate2:always': {}
|
||||
'test:gate2:sometimes': {}
|
||||
|
||||
'tmd:share': {}
|
||||
'tmd:download': {}
|
||||
'tmd:post': {}
|
||||
|
||||
'trendingTopics:show': {
|
||||
context: 'settings'
|
||||
}
|
||||
'trendingTopics:hide': {
|
||||
context: 'settings' | 'sidebar' | 'interstitial' | 'explore:trending'
|
||||
}
|
||||
'trendingTopic:click': {
|
||||
context: 'sidebar' | 'interstitial' | 'explore'
|
||||
}
|
||||
'recommendedTopic:click': {
|
||||
context: 'explore'
|
||||
}
|
||||
'trendingVideos:show': {
|
||||
context: 'settings'
|
||||
}
|
||||
'trendingVideos:hide': {
|
||||
context: 'settings' | 'interstitial:discover' | 'interstitial:explore'
|
||||
}
|
||||
'videoCard:click': {
|
||||
context: 'interstitial:discover' | 'interstitial:explore' | 'feed'
|
||||
}
|
||||
|
||||
'explore:module:seen': {
|
||||
module:
|
||||
| 'trendingTopics'
|
||||
| 'trendingVideos'
|
||||
| 'suggestedAccounts'
|
||||
| 'suggestedFeeds'
|
||||
| 'suggestedStarterPacks'
|
||||
| `feed:${FeedDescriptor}`
|
||||
}
|
||||
'explore:module:searchButtonPress': {
|
||||
module: 'suggestedAccounts' | 'suggestedFeeds'
|
||||
}
|
||||
'explore:suggestedAccounts:tabPressed': {
|
||||
tab: string
|
||||
}
|
||||
|
||||
'progressGuide:hide': {}
|
||||
'progressGuide:followDialog:open': {}
|
||||
|
||||
'moderation:subscribedToLabeler': {}
|
||||
'moderation:unsubscribedFromLabeler': {}
|
||||
'moderation:changeLabelPreference': {
|
||||
preference: string
|
||||
}
|
||||
|
||||
'moderation:subscribedToList': {
|
||||
listType: 'mute' | 'block'
|
||||
}
|
||||
'moderation:unsubscribedFromList': {
|
||||
listType: 'mute' | 'block'
|
||||
}
|
||||
|
||||
'reportDialog:open': {
|
||||
subjectType: string
|
||||
}
|
||||
'reportDialog:close': {}
|
||||
'reportDialog:success': {
|
||||
reason: string
|
||||
labeler: string
|
||||
details: boolean
|
||||
}
|
||||
'reportDialog:failure': {}
|
||||
|
||||
translate: {
|
||||
sourceLanguages: string[]
|
||||
targetLanguage: string
|
||||
textLength: number
|
||||
}
|
||||
|
||||
'verification:create': {}
|
||||
'verification:revoke': {}
|
||||
'verification:badge:click': {}
|
||||
'verification:learn-more': {
|
||||
location:
|
||||
| 'initialAnnouncementeNux'
|
||||
| 'verificationsDialog'
|
||||
| 'verifierDialog'
|
||||
| 'verificationSettings'
|
||||
}
|
||||
'verification:settings:hideBadges': {}
|
||||
'verification:settings:unHideBadges': {}
|
||||
|
||||
'live:create': {duration: number}
|
||||
'live:edit': {}
|
||||
'live:remove': {}
|
||||
'live:card:open': {subject: string; from: 'post' | 'profile'}
|
||||
'live:card:watch': {subject: string}
|
||||
'live:card:openProfile': {subject: string}
|
||||
'live:view:profile': {subject: string}
|
||||
'live:view:post': {subject: string; feed?: string}
|
||||
|
||||
'post:share': {
|
||||
uri: string
|
||||
authorDid: string
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
feedDescriptor?: string
|
||||
postContext: 'feed' | 'thread'
|
||||
position?: number
|
||||
}
|
||||
'share:press:copyLink': {}
|
||||
'share:press:nativeShare': {}
|
||||
'share:press:openDmSearch': {}
|
||||
'share:press:dmSelected': {}
|
||||
'share:press:recentDm': {}
|
||||
'share:press:embed': {}
|
||||
|
||||
'thread:click:showOtherReplies': {}
|
||||
'thread:click:hideReplyForMe': {}
|
||||
'thread:click:hideReplyForEveryone': {}
|
||||
'thread:preferences:load': {
|
||||
[key: string]: any
|
||||
}
|
||||
'thread:preferences:update': {
|
||||
[key: string]: any
|
||||
}
|
||||
'thread:click:headerMenuOpen': {}
|
||||
'thread:click:editOwnThreadgate': {}
|
||||
'thread:click:viewSomeoneElsesThreadgate': {}
|
||||
'activitySubscription:enable': {
|
||||
setting: 'posts' | 'posts_and_replies'
|
||||
}
|
||||
'activitySubscription:disable': {}
|
||||
'activityPreference:changeChannels': {
|
||||
name: string
|
||||
push: boolean
|
||||
list: boolean
|
||||
}
|
||||
'activityPreference:changeFilter': {
|
||||
name: string
|
||||
value: string
|
||||
}
|
||||
|
||||
'ageAssurance:navigateToSettings': {}
|
||||
'ageAssurance:dismissFeedBanner': {}
|
||||
'ageAssurance:dismissSettingsNotice': {}
|
||||
'ageAssurance:initDialogOpen': {
|
||||
hasInitiatedPreviously: boolean
|
||||
}
|
||||
'ageAssurance:initDialogSubmit': {}
|
||||
'ageAssurance:api:begin': {
|
||||
platform: string
|
||||
countryCode: string
|
||||
regionCode?: string
|
||||
}
|
||||
'ageAssurance:initDialogError': {
|
||||
code: string
|
||||
}
|
||||
'ageAssurance:redirectDialogOpen': {}
|
||||
'ageAssurance:redirectDialogSuccess': {}
|
||||
'ageAssurance:redirectDialogFail': {}
|
||||
'ageAssurance:appealDialogOpen': {}
|
||||
'ageAssurance:appealDialogSubmit': {}
|
||||
'ageAssurance:noAccessScreen:shown': {
|
||||
accountCreatedAt: string
|
||||
isAARegion: boolean
|
||||
hasDeclaredAge: boolean
|
||||
canUpdateBirthday: boolean
|
||||
}
|
||||
'ageAssurance:noAccessScreen:openBirthdateDialog': {}
|
||||
|
||||
/*
|
||||
* Specifically for the `BlockedGeoOverlay`
|
||||
*/
|
||||
'blockedGeoOverlay:shown': {}
|
||||
|
||||
'geo:debug': {}
|
||||
|
||||
/*
|
||||
* Find Contacts stuff
|
||||
*/
|
||||
|
||||
// user presses the button on the new feature NUX
|
||||
'contacts:nux:ctaPressed': {}
|
||||
// user presses the banner NUX
|
||||
'contacts:nux:bannerPressed': {}
|
||||
// user dismisses the banner
|
||||
'contacts:nux:bannerDismissed': {}
|
||||
|
||||
// user lands on the contacts step
|
||||
'onboarding:contacts:presented': {}
|
||||
// user pressed "Import Contacts" button to begin flow
|
||||
'onboarding:contacts:begin': {}
|
||||
// skips the step entirely
|
||||
'onboarding:contacts:skipPressed': {}
|
||||
// user shared their contacts
|
||||
'onboarding:contacts:contactsShared': {}
|
||||
// user leaves the matches page
|
||||
'onboarding:contacts:nextPressed': {
|
||||
matchCount: number
|
||||
followCount: number
|
||||
dismissedMatchCount: number
|
||||
}
|
||||
|
||||
// user entered a number
|
||||
'contacts:phone:phoneEntered': {
|
||||
entryPoint: 'Onboarding' | 'Standalone'
|
||||
}
|
||||
// user entered the correct one-time-code
|
||||
'contacts:phone:phoneVerified': {
|
||||
entryPoint: 'Onboarding' | 'Standalone'
|
||||
}
|
||||
// user responded to the contacts permission prompt
|
||||
'contacts:permission:request': {
|
||||
status: 'granted' | 'denied'
|
||||
accessLevelIOS?: 'all' | 'limited' | 'none'
|
||||
}
|
||||
// contacts were successfully imported and matched
|
||||
'contacts:import:success': {
|
||||
contactCount: number
|
||||
matchCount: number
|
||||
entryPoint: 'Onboarding' | 'Standalone'
|
||||
}
|
||||
// contacts import failed
|
||||
'contacts:import:failure': {
|
||||
reason: 'noValidNumbers' | 'networkError' | 'unknown'
|
||||
entryPoint: 'Onboarding' | 'Standalone'
|
||||
}
|
||||
// user followed a single match
|
||||
'contacts:matches:follow': {
|
||||
entryPoint: 'Onboarding' | 'Standalone'
|
||||
}
|
||||
// user pressed "Follow All" on matches
|
||||
'contacts:matches:followAll': {
|
||||
followCount: number
|
||||
entryPoint: 'Onboarding' | 'Standalone'
|
||||
}
|
||||
// user dismissed a match
|
||||
'contacts:matches:dismiss': {
|
||||
entryPoint: 'Onboarding' | 'Standalone'
|
||||
}
|
||||
// user pressed invite to send an SMS to a non-match
|
||||
'contacts:matches:invite': {
|
||||
entryPoint: 'Onboarding' | 'Standalone'
|
||||
}
|
||||
// user opened the Find Contacts settings screen
|
||||
'contacts:settings:presented': {
|
||||
hasPreviouslySynced: boolean
|
||||
matchCount?: number
|
||||
}
|
||||
// user followed a single match from settings
|
||||
'contacts:settings:follow': {}
|
||||
// user pressed "Follow All" from settings
|
||||
'contacts:settings:followAll': {
|
||||
followCount: number
|
||||
}
|
||||
// user dismissed a match from settings
|
||||
'contacts:settings:dismiss': {}
|
||||
// user re-entered the flow via the resync button
|
||||
'contacts:settings:resync': {
|
||||
daysSinceLastSync: number
|
||||
}
|
||||
// user pressed the remove all data button
|
||||
'contacts:settings:removeData': {}
|
||||
|
||||
'liveEvents:feedBanner:seen': {
|
||||
feed: string
|
||||
context: LiveEventFeedMetricContext
|
||||
}
|
||||
'liveEvents:feedBanner:click': {
|
||||
feed: string
|
||||
context: LiveEventFeedMetricContext
|
||||
}
|
||||
'liveEvents:feedBanner:hide': {
|
||||
feed: string
|
||||
context: LiveEventFeedMetricContext
|
||||
}
|
||||
'liveEvents:feedBanner:unhide': {
|
||||
feed: string
|
||||
context: LiveEventFeedMetricContext
|
||||
}
|
||||
'liveEvents:hideAllFeedBanners': {
|
||||
context: LiveEventFeedMetricContext
|
||||
}
|
||||
'liveEvents:unhideAllFeedBanners': {
|
||||
context: LiveEventFeedMetricContext
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ export const consoleTransport: Transport = (
|
||||
if (IS_WEB) {
|
||||
if (hasMetadata) {
|
||||
console.groupCollapsed(msg)
|
||||
console.log(metadata)
|
||||
console.log(prepareMetadata(metadata))
|
||||
console.groupEnd()
|
||||
} else {
|
||||
console.log(msg)
|
||||
|
||||
@@ -49,6 +49,11 @@ export type Metadata = {
|
||||
*/
|
||||
__context__?: undefined
|
||||
|
||||
/**
|
||||
* Reserved for inherited metadata gathered in ambient context
|
||||
*/
|
||||
__metadata__?: Record<string, unknown>
|
||||
|
||||
/**
|
||||
* Applied as Sentry breadcrumb types. Defaults to `default`.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,14 @@ export function prepareMetadata(
|
||||
if (value instanceof Error) {
|
||||
value = value.toString()
|
||||
}
|
||||
if (
|
||||
typeof value === 'object' &&
|
||||
value !== null &&
|
||||
Object.keys(value).length === 0 &&
|
||||
value.constructor === Object
|
||||
) {
|
||||
return acc
|
||||
}
|
||||
return {...acc, [key]: value}
|
||||
}, {})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user