From 90f7aac8ad2ed5e771f3c20f4265d4e2e63bae6f Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 4 Oct 2025 12:23:20 +0530 Subject: [PATCH] Feat: Enable Poshog and Sentry for OSS (#23) feat: enable posthog and sentry for oss --- docker-compose.yaml | 18 ++-- ui/Dockerfile | 8 +- ui/next.config.ts | 4 +- ui/src/app/api/config/posthog/route.ts | 16 ++++ ui/src/app/api/config/sentry/route.ts | 9 ++ ui/src/instrumentation-client.ts | 122 ++++++++++++++++--------- 6 files changed, 118 insertions(+), 59 deletions(-) create mode 100644 ui/src/app/api/config/posthog/route.ts create mode 100644 ui/src/app/api/config/sentry/route.ts diff --git a/docker-compose.yaml b/docker-compose.yaml index b0f599e..230de82 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -59,7 +59,7 @@ services: - app-network api: - image: ${REGISTRY:-dograhai}/dograh-api:latest + image: ${REGISTRY:-dograhai}/dograh-api:latest volumes: - shared-tmp:/tmp environment: @@ -169,22 +169,18 @@ services: ui: image: ${REGISTRY:-dograhai}/dograh-ui:latest environment: - NEXT_PUBLIC_NODE_ENV: "local" - NEXT_PUBLIC_AUTH_PROVIDER: "local" - # Client-side URL (from browser) - NEXT_PUBLIC_BACKEND_URL: "http://localhost:8000" # Server-side URL (SSR, internal Docker network) BACKEND_URL: "http://api:8000" - - # Controls some feature flags like voicemail detection - NEXT_PUBLIC_DEPLOYMENT_MODE: "oss" + NODE_ENV: "oss" # Posthog - NEXT_PUBLIC_ENABLE_POSTHOG: "true" - NEXT_PUBLIC_POSTHOG_KEY: "phc_st6dverimoydkpM5m0a9aeAr8znUYWznEaQa8v80E2D" + ENABLE_POSTHOG: "${ENABLE_POSTHOG:-true}" + POSTHOG_KEY: "phc_ItizB1dP6yv7ZYobbcqrpxTdbomDA8hJFSEmAMdYvIr" + POSTHOG_HOST: "https://us.posthog.com" # Sentry - NEXT_PUBLIC_ENABLE_SENTRY: "false" + ENABLE_SENTRY: "${ENABLE_SENTRY:-true}" + SENTRY_DSN: "https://d9387fed5f80e90781f1dbd9b2c0994c@o4509486225096704.ingest.us.sentry.io/4510124708200448" ports: - "3010:3000" depends_on: diff --git a/ui/Dockerfile b/ui/Dockerfile index 095f6de..9a6b16b 100644 --- a/ui/Dockerfile +++ b/ui/Dockerfile @@ -28,12 +28,12 @@ COPY public ./public COPY src ./src # Set build-time environment variables (needed for Next.js build) -ENV NEXT_PUBLIC_NODE_ENV=local -ENV NEXT_PUBLIC_AUTH_PROVIDER=local -ENV NEXT_PUBLIC_DEPLOYMENT_MODE=oss +ENV NEXT_PUBLIC_NODE_ENV="oss" +ENV NEXT_PUBLIC_AUTH_PROVIDER="local" +ENV NEXT_PUBLIC_DEPLOYMENT_MODE="oss" ENV NEXT_PUBLIC_BACKEND_URL="http://localhost:8000" ENV BACKEND_URL="http://api:8000" -ENV NEXT_TELEMETRY_DISABLED=1 +ENV NEXT_TELEMETRY_DISABLED="1" # Build the application with standalone mode RUN npm run build && \ diff --git a/ui/next.config.ts b/ui/next.config.ts index 2ece625..1b8a399 100644 --- a/ui/next.config.ts +++ b/ui/next.config.ts @@ -9,9 +9,9 @@ const nextConfig: NextConfig = { }, async rewrites() { return [ - // API proxy for backend calls + // API proxy for backend calls (excluding Next.js API routes) { - source: "/api/:path*", + source: "/api/:path((?!config|auth).*)*", destination: `${process.env.BACKEND_URL || 'http://localhost:8000'}/api/:path*`, }, { diff --git a/ui/src/app/api/config/posthog/route.ts b/ui/src/app/api/config/posthog/route.ts new file mode 100644 index 0000000..620b493 --- /dev/null +++ b/ui/src/app/api/config/posthog/route.ts @@ -0,0 +1,16 @@ +/* + Route to enable/ disable posthog from a NextJS backend route, + rather than NEXT_PUBLIC_* keys, since NEXT_PUBLIC_* keys are + injected during build time, and we need to provide the option + to OSS users to disable telemetry from docker-compose.yaml +*/ +import { NextResponse } from 'next/server'; + +export async function GET() { + return NextResponse.json({ + enabled: process.env.ENABLE_POSTHOG === 'true', + key: process.env.POSTHOG_KEY || '', + host: process.env.POSTHOG_HOST || '/ingest', + uiHost: process.env.POSTHOG_UI_HOST || 'https://us.posthog.com', + }); +} diff --git a/ui/src/app/api/config/sentry/route.ts b/ui/src/app/api/config/sentry/route.ts new file mode 100644 index 0000000..820432a --- /dev/null +++ b/ui/src/app/api/config/sentry/route.ts @@ -0,0 +1,9 @@ +import { NextResponse } from 'next/server'; + +export async function GET() { + return NextResponse.json({ + enabled: process.env.ENABLE_SENTRY === 'true', + dsn: process.env.SENTRY_DSN || '', + environment: process.env.NODE_ENV || 'development', + }); +} diff --git a/ui/src/instrumentation-client.ts b/ui/src/instrumentation-client.ts index 5074158..3cae7ec 100644 --- a/ui/src/instrumentation-client.ts +++ b/ui/src/instrumentation-client.ts @@ -5,53 +5,91 @@ import * as Sentry from "@sentry/nextjs"; import posthog from "posthog-js"; -// Only initialize Sentry if explicitly enabled and DSN is provided -const enableSentry = process.env.NEXT_PUBLIC_ENABLE_SENTRY === 'true' && - process.env.NEXT_PUBLIC_SENTRY_DSN; +// Initialize Sentry - prioritize NEXT_PUBLIC env vars, fallback to API +const initSentry = () => { + const hasPublicConfig = process.env.NEXT_PUBLIC_ENABLE_SENTRY === 'true' && + process.env.NEXT_PUBLIC_SENTRY_DSN; -if (enableSentry) { - Sentry.init({ - dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + if (hasPublicConfig) { + // Use client-side environment variables + Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + integrations: [Sentry.replayIntegration()], + replaysSessionSampleRate: 0.1, + replaysOnErrorSampleRate: 1.0, + debug: false, + enabled: process.env.NEXT_PUBLIC_NODE_ENV === 'production' + }); + console.log('Sentry initialized from NEXT_PUBLIC config'); + } else { + // Fallback to API-based configuration + fetch('/api/config/sentry') + .then(res => res.json()) + .then(config => { + if (config.enabled && config.dsn) { + Sentry.init({ + dsn: config.dsn, + integrations: [Sentry.replayIntegration()], + replaysSessionSampleRate: 0.1, + replaysOnErrorSampleRate: 1.0, + debug: false, + enabled: config.environment === 'production' + }); + console.log('Sentry initialized from API config'); + } else { + console.log('Sentry disabled (not enabled or DSN not configured)'); + } + }) + .catch(err => { + console.error('Failed to fetch Sentry configuration:', err); + }); + } +}; - // Add optional integrations for additional features - integrations: [ - Sentry.replayIntegration(), - ], +initSentry(); - // Define how likely Replay events are sampled. - // This sets the sample rate to be 10%. You may want this to be 100% while - // in development and sample at a lower rate in production - replaysSessionSampleRate: 0.1, +// Initialize PostHog - prioritize NEXT_PUBLIC env vars, fallback to API +const initPostHog = () => { + const hasPublicConfig = process.env.NEXT_PUBLIC_ENABLE_POSTHOG === 'true' && + process.env.NEXT_PUBLIC_POSTHOG_KEY; - // Define how likely Replay events are sampled when an error occurs. - replaysOnErrorSampleRate: 1.0, + if (hasPublicConfig) { + // Use client-side environment variables + posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, { + api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || '/ingest', + ui_host: process.env.NEXT_PUBLIC_POSTHOG_UI_HOST || 'https://us.posthog.com', + capture_pageview: 'history_change', + capture_pageleave: true, + capture_exceptions: true, + debug: process.env.NEXT_PUBLIC_NODE_ENV === 'development', + }); + console.log('PostHog initialized from NEXT_PUBLIC config'); + } else { + // Fallback to API-based configuration + fetch('/api/config/posthog') + .then(res => res.json()) + .then(config => { + if (config.enabled && config.key) { + posthog.init(config.key, { + api_host: config.host, + ui_host: config.uiHost, + capture_pageview: 'history_change', + capture_pageleave: true, + capture_exceptions: true, + debug: process.env.NEXT_PUBLIC_NODE_ENV === 'development', + }); + console.log('PostHog initialized from API config'); + } else { + console.log('PostHog disabled (not enabled or key not configured)'); + } + }) + .catch(err => { + console.error('Failed to fetch PostHog configuration:', err); + }); + } +}; - // Setting this option to true will print useful information to the console while you're setting up Sentry. - debug: false, - enabled: process.env.NEXT_PUBLIC_NODE_ENV === 'production' - }); - console.log('Sentry initialized for client-side error tracking'); -} else { - console.log('Sentry disabled (NEXT_PUBLIC_ENABLE_SENTRY=false or DSN not configured)'); -} - -// Only initialize PostHog if explicitly enabled and key is provided -const shouldEnablePostHog = process.env.NEXT_PUBLIC_ENABLE_POSTHOG === 'true' && - process.env.NEXT_PUBLIC_POSTHOG_KEY; - -if (shouldEnablePostHog) {//FIXME: remove default empty value - posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY||'', { - api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || "/ingest",//https://us.i.posthog.com - ui_host: process.env.NEXT_PUBLIC_POSTHOG_UI_HOST || "https://us.posthog.com", - capture_pageview: 'history_change', - capture_pageleave: true, // Enable pageleave capture - capture_exceptions: true, // Capture exceptions via Error Tracking - debug: process.env.NEXT_PUBLIC_NODE_ENV === 'development', // Enable debug in development - }); - console.log('PostHog analytics initialized'); -} else { - console.log('PostHog disabled (NEXT_PUBLIC_ENABLE_POSTHOG=false or key not configured)'); -} +initPostHog(); export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;