padosoft-logging-disciplinelisted
Install: claude install-skill padosoft/skills
# Logging discipline
Three codebases that do not share a line of code — a Bun/Hono API, a React Native app and a Laravel monolith —
arrived independently at the same rules. That is not a convention: it is a property of the problem.
**The invariants are the rule. The mechanism is per stack, and copying the wrong one does damage** (§8).
---
## 1. A driver exception is not a loggable object
This is the one that bit all three, and the damage was different every time:
| Stack | The object | What it carries | Where it went |
|---|---|---|---|
| Node + mysql2 | `err.sql` | the query **already formatted**, bound values substituted | into the logs: the hash of an auth token |
| Laravel + PDO | `QueryException::getMessage()` | SQLSTATE, production DB host, database name, the full INSERT | onto the **user's screen**, with their personal data |
| React Native | a raw `Error` | message and stack | into the logs, and every crash collapsed into one issue |
```ts
logger.error("db lookup failed:", err); // ❌ err.sql goes with it
Log::error($e); // ❌ __toString() carries SQL and host
logger.error("[x]", err); // ❌ raw Error
```
**Never hand the exception object to the logger, and never put its native message in front of a user.**
⚠️ Grepping for the *name of the secret* does not find this. The two real leaking lines in the API were caught
only because their message happened to contain the word "token"; `logger.error("db lookup failed