A request failed in production at 02:14 and the only thing you have is console.log("error", err) somewhere in a route handler. You cannot tell which user hit it, which path, how long it took, or whether the three log lines you found even belong to the same request. That is the situation structured logging exists to prevent.

I run this site on a self-hosted VPS with Coolify — no platform log aggregation doing the work for me. Every request produces one JSON line on stdout, carries an ID I can grep for, and never prints a secret. This is the exact setup, straight from the codebase — not a toy example.

Why Structured, Not Strings

console.log gives you strings. Strings are fine until you need to answer a question like "show me every 500 on /api/contact in the last hour that took over a second." You cannot query a string. You end up writing fragile regexes against your own log format.

Structured logging means every log line is a JSON object with named fields: