Last Updated: December 26, 2018
·
2.478K
· nathansmith

Sensible console.log

// Debug on localhost
var host = window.location.hostname;
var debug = host.match(/localhost|127.0.0.1|staging.example.com/);

// Safely log things, if need be
function log() {
  if (debug && console && typeof console.log === 'function') {
    for (var i = 0, ii = arguments.length; i < ii; i++) {
      console.log(arguments[i]);
    }
  }
}

// This will do nothing, in production
log('Testing, testing...');

Gist on GitHub: https://gist.github.com/nathansmith/5631193

I threw this gist together, because destroying console.log seems like a heavy-handed solution to a problem that shouldn't exist (if you're doing debugging correctly)…

https://coderwall.com/p/omhqvw

Basically, rather than overwriting console.log you should be debugging only when it makes sense, to begin with.

So, here we're first checking if we're in some sort of debug mode (aka development).

Then, we're ensuring that console does indeed exist, and that console.log is a function.

Then, we loop through the arguments passed, and log them out safely.

The reason we don't want to just assume that console is there (checking only for debug) is that some versions of Internet Explorer – despite having developer tools – will throw errors if the dev tools are collapsed (shown/hidden via F12).

Anyway, you shouldn't log stuff in production. But if you do, ensure it won't throw errors to users.

7 Responses
Add your response

Neat solution. We assume that logging shouldn't be on in production, so at the top of our included javascript we have the following to prevent IE errors:

var console = console || { log: function() {} };

over 1 year ago ·

@solocommand

That would fix the issue of IE throwing errors when the dev tools are closed. However, it wouldn't prevent console.log messages from being emitted to anyone/everyone with their browser's dev tools open.

Your log messages would still be seen by anyone using the dev tools in Chrome, Safari, Firefox, Opera, IE, etc.

That is, unless you're stripping out console.log from your code before deployment. In which case, defining console as a variable isn't actually necessary.

over 1 year ago ·

@nathansmith

Good point. I guess we're not doing debugging correctly ;)

Ours only covers the IE issue, rather than addressing logging based on the environment, I guess I didn't read your post carefully enough.

Wouldn't your solution require developers to use log() rather than console.log() though? Could the same solution be achieved by extending console.log rather than creating a new function (forgetting for a moment that leaving logging statements in is doing it wrong), and assuming developers will use it?

over 1 year ago ·

@solocommand

Yes, my approach would require developers to use the log() function instead of console.log.

However, I was intrigued by your suggestion. So, I just threw this together.

Sadly, it doesn't work…

(function(window) {
  window.console = window.console || {};
  var log = window.console.log || function(){};
  var host = window.location.hostname;
  var debug = host.match(/localhost|127.0.0.1|staging.example.com/);

  // debug = true;

  window.console.log = function() {
    if !(debug) {
      return;
    }

    for (var i = 0, ii = arguments.length; i < ii; i++) {
      log(arguments[i]);
    }
  };
})(this);

It appears that while you can override window.console — which is seemingly just a pointer to an internal object, the actual console.log function is native to the browser and does not want to be overridden.

I get this error…

http://cl.ly/image/081T1H2C023A

"Illegal invocation."

Note the bit about [native code].

Anyway, I don't think it's possible to repurpose console.log itself.

Note: It is possible to edit things that live at the global scope. For instance, here's an example of how to force parseInt to use a base-10 radix…

https://gist.github.com/nathansmith/1027395

So, I don't think the approach is the problem. I guess that console.log is just impervious to tampering?

over 1 year ago ·

@nathansmith Wow, you put a lot more effort into that than I did!

Makes sense though, if console.log is native to the browser it shouldn't be able to be overridden. Would probably open a few security holes if third-party code could override core browser methods.

Currently we minify our JS before caching it, so I think for us the best solution would be to strip logging during that process. Unfortunately we still need to provide a fake console.log method for IE browsers because we can't control whether or not third-party ads will contain logging calls (and they fairly frequently do, unfortunately).

All that said, I like your approach. If only I could get the rest of our team on board :)

over 1 year ago ·

Yeah, I hear ya. Can't account for what others (3rd parties) might do.

Might I suggest (so you can call it from within whatever scope)…

window.console = window.console || {log:function(){}};

That way you can have it nested inside something else, if need be.

In terms of cut-and-paste handiness, that makes sure you're not creating a local var console somewhere.

Anyway, that's super nitpicky, I know.

:)

over 1 year ago ·

@solocommand

By the way, Paul Irish just pointed me in this direction. Seems to be a very robust solution (leaves line-numbers intact, for the origin of the log)…

https://gist.github.com/bgrins/5108712

over 1 year ago ·