In Monitoring a SaaS in Production we wired up metrics and alerts so the team knows something is wrong within minutes of it happening. Metrics tell you a spike exists. They rarely tell you why. That's a logging problem, and it's the one we're solving here.

This is part of the Full Stack SaaS Masterclass, a build-it-for-real series taking a multi-tenant SaaS from an empty folder to production. Module 4 covers the operational concerns that separate a demo from a product a team can actually run. Logging sits at the base of that stack: incident response, support tickets, and audit trails all eventually route back to "what does the log say."

Most Node.js apps start with console.log and stay there far longer than they should, because it works fine on a laptop with one request at a time. It stops working the moment two requests are in flight concurrently and their log lines interleave in a shared terminal, or a customer support ticket needs an answer and the only tool available is grep against a wall of unstructured text. Structured logging fixes that, and it's cheap enough to set up early that there's little reason to defer it.

Why plain text logs stop working

A console.log call produces a string. Strings are fine for a human staring at a terminal, and actively hostile to any system trying to query logs at scale. Once logs move to CloudWatch, Datadog, or any aggregator, every downstream tool ends up parsing that string back apart with regex to extract the fields it actually needs: request ID, user ID, status code, duration. Regex-based parsing is brittle. A one-word change to a log message breaks every saved search and alert built against it.