RoadmapDay 54 / 80
System DesignMonth 3 · Week 11

Day 54: Analytics, Logging & Error Tracking Architectures (Sentry, Datadog)

Design an observability setup that lets you find and diagnose a production bug from a user report, without needing to reproduce it locally.

Mark this day complete

Study

Concepts

Three distinct signals: errors, logs, and analytics events

Error tracking (Sentry, Bugsnag) captures unhandled exceptions and manually-reported errors, automatically attaching a stack trace, breadcrumbs (a timeline of recent user actions/network calls leading up to the error), device/OS/app-version context, and (critically) SOURCE MAPS so a minified production stack trace resolves back to your actual source lines. Structured logging (Datadog, CloudWatch, or a simpler pipeline) captures a running narrative of what the app/server did, at varying severity levels (debug/info/warn/error), queryable after the fact — useful for reconstructing a sequence of events even when nothing technically "errored". Product analytics (Amplitude, Mixpanel, PostHog) captures user BEHAVIOR events (button clicked, screen viewed, checkout completed) for product decisions, not debugging — a different audience and purpose from the two above, even though the instrumentation code often lives side by side.

A mature setup correlates all three: attaching a `sessionId` or `requestId` to every log line, error report, and analytics event lets you pull the full story for one specific user's bad experience — "show me every log, error, and action for session X" — rather than three disconnected dashboards.

Source maps and breadcrumbs are what make production errors debuggable

Production JS is minified/bundled — a raw stack trace pointing to `main.a8f3.js:1:48213` is useless without a source map uploaded to your error-tracking provider that maps that minified position back to `CheckoutForm.tsx:142`. This upload step (usually automated in CI on each deploy) is the single most impactful, most commonly forgotten piece of frontend error-tracking setup — without it, every production error report is nearly undiagnosable.

Breadcrumbs (automatically captured clicks, navigation, console logs, and network requests leading up to an error) turn "TypeError: Cannot read property 'id' of undefined" into a reconstructable story: "user clicked Remove Item, then the cart API call returned a 500, then this error fired" — this context is usually more valuable for diagnosis than the stack trace itself.

See It

Visualizations

Visualization

Three observability signals

 Error TrackingStructured Logging
CapturesExceptions + stack trace + breadcrumbsA running narrative at varying severity levels
Triggered bySomething going wrongEvery significant thing the app/server does
Primary audienceEngineers debugging a specific incidentEngineers reconstructing a sequence of events
ToolsSentry, BugsnagDatadog, CloudWatch, Logtail
Correlated viasessionId / requestId, shared across all three signalssessionId / requestId

Build It

Code Examples

Sentry setup with a correlated session/user context

js
import * as Sentry from '@sentry/react';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  release: process.env.APP_VERSION, // must match the uploaded source map's release
  tracesSampleRate: 0.2, // sample performance traces, not just errors
});

function onLogin(user, sessionId) {
  Sentry.setUser({ id: user.id });
  Sentry.setTag('sessionId', sessionId); // now searchable across errors AND logs
}

function CheckoutButton() {
  async function handleClick() {
    Sentry.addBreadcrumb({ category: 'ui.click', message: 'Checkout button clicked' });
    try {
      await submitOrder();
    } catch (err) {
      Sentry.captureException(err, { extra: { cartId: currentCartId } });
      throw err;
    }
  }
  return <button onClick={handleClick}>Checkout</button>;
}

Uploading source maps in CI (the step most teams forget)

yaml
# .github/workflows/deploy.yml (excerpt)
- name: Build
  run: npm run build   # produces minified bundles + .map files

- name: Upload source maps to Sentry
  run: |
    npx @sentry/cli releases new "$APP_VERSION"
    npx @sentry/cli releases files "$APP_VERSION" upload-sourcemaps ./dist
    npx @sentry/cli releases finalize "$APP_VERSION"
  # Without this step, every production stack trace stays minified and unreadable.

Remember

Key Takeaways

  • Error tracking, structured logging, and product analytics are three distinct signals serving different questions — instrument all three deliberately.
  • Source maps must be uploaded on every deploy (matched by release/version) or production stack traces stay unreadable.
  • Breadcrumbs reconstruct the user's path to an error and are often more useful for diagnosis than the stack trace alone.
  • Correlating a sessionId/requestId across errors, logs, and analytics events turns three separate dashboards into one coherent story.
  • Sample performance traces (not just errors) to catch slow interactions that never technically throw an exception.

Do It

Practice

  1. 1Set up Sentry (or a free-tier equivalent) on a real project, trigger a real error, and trace it back to the exact source line via the uploaded source map.
  2. 2Add breadcrumbs to a multi-step flow (like the checkout example) and trigger a failure, then read the reconstructed breadcrumb trail in the dashboard.
  3. 3Design a sessionId propagation scheme (on paper) that would let you correlate a single user's frontend error with a corresponding backend log line.