trace(): the console.log I kept typing
Confession time. For years I had a VS Code snippet that dropped this at the top of a function:
console.log('Called: ', arguments.callee.name);
When something wasn't working, I'd sprinkle it everywhere, reload, and watch the console tell me which functions fired and in what order. Crude, but it works... until it doesn't.
Two problems
arguments.calleeis deprecated, and it throws. In strict mode, ES modules and class bodies (which is most JavaScript written today) it's an error, not a log line.- Those logs ship. You fix the bug, you forget three of them, and now your production console is chatting away to every visitor.
The fix
trace() is the grown-up version:
function loadUser(id) {
trace(); // → Called: loadUser
}
- It works out the function name itself by reading it off a stack trace, so there's nothing to type and no
arguments.callee. - It's silent by default. Nothing logs until you set
trace.enabled = true. - Anything you pass is handed straight to
console.log, so objects and DOM elements stay clickable in devtools.
The best part: drive the switch from the server, so it's on in development and off in production automatically, and can't ship "on" by accident:
<script>trace.enabled = <?= APP_ENV === 'dev' ? 'true' : 'false' ?>;</script>
Because it checks the flag every time it's called, you can also flip it on from the devtools console on a live site to see what's happening, with no deploy.
The trick worth remembering
Wrap your variables in an object and JavaScript keeps their names for you:
function applyDiscount(code) {
const total = 42.5;
const tier = 'gold';
trace({ code, total, tier });
}
// Called: applyDiscount { code: 'SPRING', total: 42.5, tier: 'gold' }
Compare that with trace(code, total, tier), which gives you SPRING 42.5 gold and leaves you guessing which number is which.
A lesson I learned the hard way
My first instinct was to put trace() on every function. On one app, one page load produced 692 lines of trace output, and almost half of them came from a single tiny helper that escapes text for HTML and runs once for every cell in a table. The useful story (page loads, data arrives, table builds) was buried.
So the rule now: trace the steps, not the atoms. If a function runs once per user action (a page setup, a data load, a click handler), trace it. If it runs once per item (per row, per cell), leave it alone.
Try it
It's one file, about 30 lines, zero dependencies.
- Drop it in: copy
trace.jsinto your project, or load it from the CDN:<script src="https://cdn.jsdelivr.net/gh/1978io/trace@1.0.0/trace.js"></script> - Live demo: bits.1978.io/trace
- Code: github.com/1978io/trace. MIT.
It's now standard in every new project I start.