fix(tracker): sample PostHog events at five percent

This commit is contained in:
DIYgod 2026-07-03 16:46:26 +08:00
parent 54447e6faa
commit 72e289bb3e
6 changed files with 63 additions and 3 deletions

View File

@ -1,5 +1,10 @@
import { env } from "@follow/shared/env.desktop"
import { setFirebaseTracker, setPostHogTracker, tracker } from "@follow/tracker"
import {
createPostHogBeforeSend,
setFirebaseTracker,
setPostHogTracker,
tracker,
} from "@follow/tracker"
import { captureAttributionFromURL, getAttributionForAnalytics } from "@follow/utils"
import type { AuthSessionResponse } from "@follow-app/client-sdk"
import posthog from "posthog-js"
@ -30,6 +35,7 @@ export const initAnalytics = async () => {
api_host: env.VITE_POSTHOG_HOST,
person_profiles: "identified_only",
defaults: "2025-05-24",
before_send: createPostHogBeforeSend(),
capture_exceptions: {
capture_unhandled_errors: true,
capture_unhandled_rejections: true,

View File

@ -1,5 +1,10 @@
import { whoami } from "@follow/store/user/getters"
import { setFirebaseTracker, setPostHogTracker, tracker } from "@follow/tracker"
import {
createPostHogBeforeSend,
setFirebaseTracker,
setPostHogTracker,
tracker,
} from "@follow/tracker"
import type { AuthUser } from "@follow-app/client-sdk"
import { getAnalytics } from "@react-native-firebase/analytics"
import { nativeApplicationVersion, nativeBuildVersion } from "expo-application"
@ -14,6 +19,7 @@ export const initAnalytics = async () => {
setPostHogTracker(
new PostHog(proxyEnv.POSTHOG_KEY, {
host: proxyEnv.POSTHOG_HOST,
before_send: createPostHogBeforeSend(),
errorTracking: {
autocapture: {
uncaughtExceptions: true,

View File

@ -1,4 +1,9 @@
export type { CaptureExceptionPayload, IdentifyPayload, TrackerAdapter, TrackPayload } from "./base"
export { FirebaseAdapter, type FirebaseAdapterConfig } from "./firebase"
export { PostHogAdapter, type PostHogAdapterConfig } from "./posthog"
export {
createPostHogBeforeSend,
POSTHOG_SAMPLE_RATE,
PostHogAdapter,
type PostHogAdapterConfig,
} from "./posthog"
export { ProxyAdapter } from "./proxy"

View File

@ -0,0 +1,22 @@
import { describe, expect, it } from "vitest"
import { createPostHogBeforeSend, POSTHOG_SAMPLE_RATE } from "./posthog"
describe("PostHogAdapter", () => {
it("uses a 5% PostHog sample rate", () => {
expect(POSTHOG_SAMPLE_RATE).toBe(0.05)
})
it("drops PostHog events when outside the configured sample rate", () => {
const beforeSend = createPostHogBeforeSend(0.05, () => 0.5)
expect(beforeSend({ event: "app init" })).toBeNull()
})
it("keeps PostHog events when inside the configured sample rate", () => {
const beforeSend = createPostHogBeforeSend(0.05, () => 0.04)
const event = { event: "app init" }
expect(beforeSend(event)).toBe(event)
})
})

View File

@ -3,6 +3,25 @@ import type PostHogReactNative from "posthog-react-native"
import type { CaptureExceptionPayload, IdentifyPayload, TrackerAdapter, TrackPayload } from "./base"
export const POSTHOG_SAMPLE_RATE = 0.05
const normalizeSampleRate = (sampleRate: number): number => {
if (!Number.isFinite(sampleRate)) return 1
return Math.min(Math.max(sampleRate, 0), 1)
}
export const createPostHogBeforeSend = (
sampleRate = POSTHOG_SAMPLE_RATE,
sampleRandom: () => number = Math.random,
) => {
const normalizedSampleRate = normalizeSampleRate(sampleRate)
const isSampled =
normalizedSampleRate >= 1 || (normalizedSampleRate > 0 && sampleRandom() < normalizedSampleRate)
return <T>(event: T): T | null => (isSampled ? event : null)
}
export interface PostHogAdapterConfig {
instance: PostHog | PostHogReactNative
enabled?: boolean

View File

@ -9,9 +9,11 @@ export const tracker = new TrackerPoints()
export {
type CaptureExceptionPayload,
createPostHogBeforeSend,
FirebaseAdapter,
type FirebaseAdapterConfig,
type IdentifyPayload,
POSTHOG_SAMPLE_RATE,
PostHogAdapter,
type PostHogAdapterConfig,
ProxyAdapter,