Debugging JavaScript with a Stack Trace

March 20, 2011

I was trying to work with some JavaScript that kept popping up alert boxes. The library was huge and not particularly well organised, so rather than hunting through thousands of lines of code, I wrapped the original `window.alert` with a version that shows a stack trace just before the real alert fires. You can adapt this technique to trace calls to any function -- just change what gets wrapped in the last four lines. ```javascript var original_alert = window.alert; var stacktrace = function() { var regex = /function\W+([\w-]+)/i; var callee = arguments.callee; var trace = ""; while(callee) { trace += (regex.exec(callee))[1] + '('; for (i = 0; i < callee.arguments.length - 1; i++) { trace += "'" + callee.arguments[i] + "', "; } if (arguments.length > 0) { trace += "'" + callee.arguments[i] + "'"; } trace += ")\n\n"; callee = callee.arguments.callee.caller; } original_alert(trace); } window.alert = function(msg) { stacktrace(); original_alert(msg); } ``` The approach is straightforward: save a reference to the real `window.alert`, then replace it with a wrapper that walks up the call stack using `arguments.callee.caller`, building a string of function names and their arguments as it goes. It pops up the trace in one alert, then lets the original alert through. A word of caution: `arguments.callee` is deprecated in strict mode and won't work in modern ES5+ strict code. For anything current, you'd want to use `console.trace()` or the browser's built-in debugger instead. But when you're stuck debugging a sprawling legacy codebase that predates those niceties, this trick can save you a lot of time.
Questions or thoughts? Get in touch.