Like countless other developers, I decided to monkey-patch console.log
to implement the logger of our Angular application. You may or may not like this approach, but it worked flawlessly. The first time it broke was when we deployed it to production today.
What had happened?
After a while, we observed that the application works fine if we ran it after opening the developer tools. Closing the developer tools made the application crash again.
Internet Explorer 8 and 9
A quick research in the internet showed a possible explanation. console.log
is meant to be debug code. So the Microsoft developers considered it a good idea to create the console
object only if the developer tools are open. Close them, and the entire console
object is undefined
again.
As a remedy, you can use this polyfill:
if(!window.console) { var console = { log : function(){}, warn : function(){}, error : function(){}, time : function(){}, timeEnd : function(){} } }Excursion: Other browsers
It's a good idea to always add this polyfill. The console
object isn't part of JavaScript. Instead, it's an extension of the DOM. Most browsers implement it. Node.js implements it, too. But there's no obligation to do so. There are a few browsers that don't. For instance, there's no console
on Blackberry, Opera Mini and UC for Android.
Internet Explorer 10, 11, and Edge
Unfortunately, this polyfill didn't make any difference.
Since version 10, Internet Explorer always has a console
object. If the developer tools are closed, calls to the console
object are simply ignored. You can even monkey-patch the methods of the console
object:
You can even show the source code of console.log
, console.error
, console.warn
and so on:
In IE11, this shows a native function if the developer tools are closed and a JavaScript function if they are open. The Edge browser always shows a native method.
Now here's the catch. You can copy the method to a variable, but you cannot use the variable to call the method. So the traditional approach of Monkey Patching (store the old function, intercept the function by overriding it and call the original code at the end of the overriding function) doesn't work. Quite the contrary, it results in an exception:
alert(console.info); // shows "native function" const original = console.info; alert(original); // shows "native function" console.info("You ain't gonna see me, but never mind"); // silently ignored original("I'm gonna crash in production!"); // may result in an exceptionWrapping it up
The annoying thing about this bug is that it doesn't leave any traces. Internet Explorer and Edge assume you don't need any logs in production. From a performance perspective, that's a great idea, but other than that, it's annoying. The error message disappears into Nirvana without further ado.
So either you follow the advice of most experienced JavaScript programmers: avoid Monkey Patching, and use a dedicated logger class instead. Or you redirect the console messages without logging them redundantly to the console
object of the developer tools. That's what we did: Now every log message is sent to the server, using the awesome JSNLog library.