Observability Overview: Sentry and PostHog
A deep dive into Odys's observability stack, covering error tracking with Sentry across three runtimes and product analytics with PostHog, including design choices and improvement opportunities.
Observability Overview: Sentry and PostHog
In the complex landscape of modern web applications, understanding how Odys behaves in production is paramount. This document provides a comprehensive look into Odys's observability strategy, focusing on two key tools: Sentry for error tracking and performance monitoring, and PostHog for product analytics. We'll explore the architectural decisions behind their integration, the trade-offs made, and concrete opportunities to enhance our insights into Odys's operations and user experience.
Overview
Odys employs a dual-pronged approach to observability, ensuring both technical stability and user engagement are closely monitored. Sentry is integrated across all three Next.js runtimes—Node.js server, Edge, and client-side browser—to provide a holistic view of application errors and performance bottlenecks. Complementing this, PostHog is utilized for product analytics, offering insights into user behavior and feature adoption, with a thoughtful implementation that respects user privacy through explicit consent.
Sentry: Comprehensive Error Tracking and Performance Monitoring
Sentry is Odys's chosen platform for capturing errors and monitoring application performance. The integration is designed to cover every facet of the application's execution environment, from server-side logic to client-side interactions.
Multi-Runtime Integration
To achieve comprehensive coverage, Sentry is configured to operate across three distinct runtimes within the Next.js framework:
- Node.js Server Runtime: The
src/instrumentation.tsfile conditionally imports the server-side Sentry configuration whenprocess.env.NEXT_RUNTIMEisnodejs. This ensures that any errors occurring in API routes, server-side rendering, or other Node.js specific processes are captured. - Edge Runtime: Similarly,
src/instrumentation.tshandles the Edge runtime by importing its specific configuration whenprocess.env.NEXT_RUNTIMEisedge. This is crucial for monitoring functions that run on the Edge, such as middleware or specific API routes optimized for low latency. - Client-Side Browser Runtime: The
src/instrumentation-client.tsfile is dedicated to configuring Sentry for the browser environment. This setup captures errors and performance data directly from the user's browser, providing insights into client-side JavaScript errors, network issues, and UI performance.
This multi-runtime strategy ensures that no matter where an issue arises within Odys, Sentry is equipped to detect and report it, providing a complete picture of the application's health.
Client-Side Configuration Details
The client-side Sentry configuration in src/instrumentation-client.ts is particularly rich, reflecting the complexity of browser environments:
- DSN: The
dsnis explicitly set tohttps://4c49acd323505a3be3603c5c4c7245ef@o4511124807417856.ingest.us.sentry.io/4511124816658432, directing all client-side events to the designated Sentry project. - Replay Integration: The
Sentry.replayIntegration()is enabled, allowing for session replays. This feature is invaluable for debugging, as it provides a visual reconstruction of user interactions leading up to an error, offering context that stack traces alone cannot. - Event Filtering (
beforeSend): AbeforeSendhook is implemented to filter out known noise. Specifically, events with messages containing "Object Not Found Matching" or "Non-Error promise rejection captured" are dropped. This helps keep the Sentry dashboard focused on actionable errors. - Sampling Rates:
tracesSampleRate: 1indicates that 100% of performance traces are sampled. This is a high rate, likely chosen to ensure comprehensive performance data collection.replaysSessionSampleRate: 0.1means 10% of user sessions are recorded for replay. This balances the need for visual debugging with potential performance and data storage considerations.replaysOnErrorSampleRate: 1.0ensures that 100% of sessions where an error occurs are recorded for replay, prioritizing debugging critical issues.
- Logging and PII:
enableLogs: trueensures that console logs are sent to Sentry, providing additional context.sendDefaultPii: trueis configured to include Personally Identifiable Information by default, which can be useful for debugging specific user-reported issues, but requires careful consideration regarding privacy regulations. - Router Transition Monitoring: The
onRouterTransitionStartexport, mapped toSentry.captureRouterTransitionStart, integrates Sentry with Next.js router events, allowing for performance monitoring of page navigations.
PostHog: Product Analytics with Privacy in Mind
PostHog is integrated into Odys to gather insights into how users interact with the application, helping to inform product development and user experience improvements. The implementation in src/components/posthog-provider.tsx demonstrates a clear focus on user consent.
Conditional Initialization
PostHog is not initialized immediately upon page load. Instead, its initialization is contingent on user consent:
- The
initPostHogfunction is called only if theodys_cookie_consentkey inlocalStorageis "accepted" or if theodys:cookie-acceptedcustom event is dispatched during the current session. This ensures that user tracking only begins after explicit permission. - The
posthog.initcall configures the analytics client with theNEXT_PUBLIC_POSTHOG_KEYandNEXT_PUBLIC_POSTHOG_HOST. It explicitly setscapture_pageview: false(as page views are handled separately) andcapture_pageleave: trueto track when users exit a page.persistence: "localStorage+cookie"ensures that user identity and session data are maintained across visits.
Page View Tracking
A dedicated PageViewTracker component, wrapped in Suspense, is responsible for capturing page view events. It leverages Next.js's usePathname and useSearchParams hooks. An useEffect hook triggers a ph.capture("$pageview") event whenever the pathname or searchParams change, effectively tracking navigation within the application. This separation allows for fine-grained control over page view events and ensures compatibility with Next.js's client-side routing.
Design decisions
The observability setup in Odys reflects several deliberate design choices:
- Comprehensive Error Coverage: The decision to integrate Sentry across all three Next.js runtimes (
nodejs,edge,client) was made to ensure that no error goes unnoticed, regardless of where it originates. This provides a complete picture of application health, which is critical for a robust application like Odys. - Focused Error Reporting: The
beforeSendfilter insrc/instrumentation-client.tsto drop "Object Not Found Matching" and "Non-Error promise rejection captured" messages is a pragmatic choice. It aims to reduce noise in the Sentry dashboard, allowing developers to focus on unique and actionable errors rather than common, often benign, browser-specific issues or unhandled promise rejections that might not indicate a critical bug. - Balanced Performance Monitoring: Setting
tracesSampleRate: 1for performance traces indicates a strong desire for detailed performance data, likely to identify and optimize bottlenecks proactively. The lowerreplaysSessionSampleRate: 0.1for general sessions, contrasted withreplaysOnErrorSampleRate: 1.0for error sessions, strikes a balance between gathering sufficient visual context for debugging and managing the overhead of recording and storing session replays. - Privacy-First Analytics: The conditional initialization of PostHog in
src/components/posthog-provider.tsx, dependent on theodys_cookie_consentkey and theodys:cookie-acceptedevent, is a crucial design decision driven by privacy considerations. It ensures compliance with data protection regulations and builds user trust by only tracking analytics after explicit consent. - Decoupled Page View Tracking: Creating a separate
PageViewTrackercomponent for PostHog, utilizingSuspense, was a technical decision to correctly integrate with Next.js's client-side routing anduseSearchParamshook, ensuring page views are accurately captured without blocking the main UI render.
Potential improvements
While the current observability setup is robust, there are always opportunities for refinement and enhancement:
- Dynamic Sentry Sampling Rates: The
tracesSampleRateandreplaysSessionSampleRateare currently static. Consider implementing dynamic sampling logic withinsrc/instrumentation-client.tsto adjust these rates based on factors like the environment (e.g., higher rates in staging, lower in production), user roles (e.g., 100% for internal team members), or even error volume. This could optimize Sentry costs while ensuring critical data is always captured. - Granular PostHog Event Tracking: Beyond page views, Odys could benefit from more explicit event tracking for key user actions. For instance, in
src/components/posthog-provider.tsx, afterph.capture("$pageview"), consider adding custom events for actions like "Appointment Booked", "Client Created", "Message Sent", or "Professional Profile Updated". This would provide deeper insights into user engagement with core features and conversion funnels. - Centralized Observability Configuration: Currently, Sentry's DSN and PostHog's key/host are managed via environment variables. While effective, consolidating all observability-related configurations (e.g., sampling rates,
beforeSendfilters, feature flags for observability tools) into a single, well-documented configuration file or object could improve maintainability and consistency acrosssrc/instrumentation.ts,src/instrumentation-client.ts, andsrc/components/posthog-provider.tsx. This would make it easier to audit and modify the observability strategy in one place.
References
src/instrumentation.tssrc/instrumentation-client.tssrc/components/posthog-provider.tsx