mediumEngineering Practices#80

Error logging service

Prompt

Create a simple error logging service that captures error messages, stack traces, and timestamps, storing them in memory and exposing a getAll method. It should handle both Error objects and plain string errors.

Solution

class ErrorLogger {
  constructor() {
    this.errors = []
  }
  log(error) {
    this.errors.push({
      message: error.message || String(error),
      stack: error.stack || null,
      timestamp: new Date().toISOString(),
    })
  }
  getAll() {
    return this.errors
  }
}
Mentor's take

This is a toy Sentry, and the reason to build the toy is to be able to say what the real thing does and why it must exist before the incident. Production observability is what turns "users say it's broken" into a stack trace with context — without it you're debugging blind on devices you don't own.

The structure of each entry is the lesson. Message alone is useless at scale ("undefined is not a function" times ten thousand); stack is what makes an error actionable — and the React Native-specific trap is that release-build stacks are minified Hermes frames, unreadable unless your release pipeline uploads source maps (and dSYMs/ProGuard mappings for native). Symbol upload is a CI step, not a manual chore. Timestamp is what lets you correlate an error spike with the release or backend deploy that caused it.

The defensive error.message || String(error) matters because JavaScript lets you throw 'oops' — a logger that assumes Error objects crashes on exactly the sloppy code most likely to throw strings. An error handler that itself throws is the worst bug class in observability.

Red flag: "we'd add logging to investigate" — that admits nothing was in place. The senior answer names crash reporting, breadcrumbs, and symbol upload as pre-launch infrastructure.

Say it: "I treat symbol upload as a release-pipeline gate and crash-free session rate as the rollout go/no-go — monitoring is configured before the incident, not during it."