diff --git a/src/analytics/index.tsx b/src/analytics/index.tsx index 8e0a9aeff2..18dfc0ef80 100644 --- a/src/analytics/index.tsx +++ b/src/analytics/index.tsx @@ -131,6 +131,8 @@ export function AnalyticsContext({ combinedMetadata.base.sessionId = sessionId combinedMetadata.geolocation = geolocation const context: AnalyticsBaseContextType = { + ...parentContext, + // TODO trim down metadata logger: createLogger(Logger.Context.Default, combinedMetadata), metadata: combinedMetadata, metric: (event, payload, extraMetadata) => { @@ -196,6 +198,7 @@ export function useAnalyticsBase() { export function useAnalytics() { const ctx = useContext(Context) if (!('feature' in ctx) || !('Features' in ctx)) { + console.log(ctx) throw new Error( 'useAnalytics must be used within an AnalyticsFeaturesContext', ) diff --git a/src/analytics/metrics/client.ts b/src/analytics/metrics/client.ts index 1dbb080336..42f50c38de 100644 --- a/src/analytics/metrics/client.ts +++ b/src/analytics/metrics/client.ts @@ -1,5 +1,6 @@ import {onAppStateChange} from '#/lib/appState' import {isNetworkError} from '#/lib/strings/errors' +import {Logger} from '#/logger' import {Sentry} from '#/logger/sentry/lib' import * as env from '#/env' @@ -13,6 +14,7 @@ type Event> = { } const TRACKING_ENDPOINT = env.METRICS_API_HOST + '/t' +const logger = Logger.create(Logger.Context.Metric, {}) export class MetricsClient> { private started: boolean = false @@ -49,6 +51,11 @@ export class MetricsClient> { metadata, }) + logger.debug(`event: ${event as string}`, { + payload, + metadata, + }) + if (this.queue.length > 100) { this.flush() } @@ -62,6 +69,10 @@ export class MetricsClient> { } private async sendBatch(events: Event[], isRetry: boolean = false) { + logger.debug(`sendBatch: ${events.length}`, { + isRetry, + }) + try { const body = JSON.stringify(events) if (env.IS_WEB && 'navigator' in globalThis && navigator.sendBeacon) { diff --git a/src/state/feed-feedback.tsx b/src/state/feed-feedback.tsx index 28f13fb5f2..8886264766 100644 --- a/src/state/feed-feedback.tsx +++ b/src/state/feed-feedback.tsx @@ -11,7 +11,6 @@ import {type AppBskyFeedDefs} from '@atproto/api' import throttle from 'lodash.throttle' import {PROD_FEEDS, STAGING_FEEDS} from '#/lib/constants' -import {Logger} from '#/logger' import { type FeedSourceFeedInfo, type FeedSourceInfo, @@ -22,6 +21,7 @@ import { type FeedPostSliceItem, } from '#/state/queries/post-feed' import {getItemsForFeedback} from '#/view/com/posts/PostFeed' +import {useAnalytics} from '#/analytics' import {useAgent} from './session' export const FEEDBACK_FEEDS = [...PROD_FEEDS, ...STAGING_FEEDS] @@ -42,8 +42,6 @@ export const THIRD_PARTY_ALLOWED_INTERACTIONS = new Set< 'app.bsky.feed.defs#interactionSeen', ]) -const logger = Logger.create(Logger.Context.FeedFeedback) - export type StateContext = { enabled: boolean onItemSeen: (item: any) => void @@ -65,6 +63,8 @@ export function useFeedFeedback( feedSourceInfo: FeedSourceInfo | undefined, hasSession: boolean, ) { + const ax = useAnalytics() + const logger = ax.logger.useContext(ax.logger.Context.FeedFeedback) const agent = useAgent() const feed = @@ -85,22 +85,55 @@ export function useFeedFeedback( WeakSet >(new WeakSet()) + const flushEvents = useCallback( + (stats: AggregatedStats | null, feedDescriptor: string) => { + if (stats === null) { + return + } + + if (stats.clickthroughCount > 0) { + ax.metric('feed:clickthrough', { + count: stats.clickthroughCount, + feed: feedDescriptor, + }) + stats.clickthroughCount = 0 + } + + if (stats.engagedCount > 0) { + ax.metric('feed:engaged', { + count: stats.engagedCount, + feed: feedDescriptor, + }) + stats.engagedCount = 0 + } + + if (stats.seenCount > 0) { + ax.metric('feed:seen', { + count: stats.seenCount, + feed: feedDescriptor, + }) + stats.seenCount = 0 + } + }, + [ax], + ) + const aggregatedStats = useRef(null) const throttledFlushAggregatedStats = useMemo( () => throttle( () => - flushToStatsig( + flushEvents( aggregatedStats.current, feed?.feedDescriptor ?? 'unknown', ), - 45e3, + 5e3, { leading: true, // The outer call is already throttled somewhat. trailing: true, }, ), - [feed?.feedDescriptor], + [feed?.feedDescriptor, flushEvents], ) const sendToFeedNoDelay = useCallback(() => { @@ -299,37 +332,3 @@ function sendOrAggregateInteractionsForStats( } } } - -function flushToStatsig(stats: AggregatedStats | null, feedDescriptor: string) { - if (stats === null) { - return - } - - if (stats.clickthroughCount > 0) { - logger.metric('feed:clickthrough', { - count: stats.clickthroughCount, - feed: feedDescriptor, - }) - stats.clickthroughCount = 0 - } - - if (stats.engagedCount > 0) { - logger.metric('feed:engaged', { - count: stats.engagedCount, - feed: feedDescriptor, - }) - stats.engagedCount = 0 - } - - if (stats.seenCount > 0) { - logger.metric( - 'feed:seen', - { - count: stats.seenCount, - feed: feedDescriptor, - }, - {statsig: false}, - ) - stats.seenCount = 0 - } -}