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.
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 Tracking | Structured Logging | |
|---|---|---|
| Captures | Exceptions + stack trace + breadcrumbs | A running narrative at varying severity levels |
| Triggered by | Something going wrong | Every significant thing the app/server does |
| Primary audience | Engineers debugging a specific incident | Engineers reconstructing a sequence of events |
| Tools | Sentry, Bugsnag | Datadog, CloudWatch, Logtail |
| Correlated via | sessionId / requestId, shared across all three signals | sessionId / requestId |
Build It
Code Examples
Sentry setup with a correlated session/user context
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)
# .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
- 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.
- 2Add breadcrumbs to a multi-step flow (like the checkout example) and trigger a failure, then read the reconstructed breadcrumb trail in the dashboard.
- 3Design a sessionId propagation scheme (on paper) that would let you correlate a single user's frontend error with a corresponding backend log line.