Opening the book…
The symptom tells you what broke; the cause tells you why. A log line that says "payment failed" sends you searching, while one that carries the failing account, the amount, and the underlying gateway rejection points you straight at the fix. Most debugging time is spent reconstructing context that the failing code already had and threw away.
When you log or wrap an error, include the inputs and identifiers that let someone reproduce it, and preserve the original error as the cause rather than replacing it. Chain exceptions instead of flattening them. Log once, at the point where you have the most context, not at every layer on the way up.
catch (e) {
throw new Error('charge failed');
}catch (e) {
throw new Error(
`charge failed: acct=${acctId} amt=${amt}`,
{ cause: e });
}Do not log secrets, tokens, or personal data in the name of context; redact them. And in tight, hot loops, detailed logging can cost more than the failure it describes, so sample or aggregate instead.