HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Wrapping around window.console

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
aroundwindowconsolewrapping

Problem

I'm working on an old application written in JavaScript. It's absolutely littered with console.* messages some of which are useful for development purposes.

At the very least I'd like to switch these off when a production flag is set. I would also like to stub off any unsupported console methods (trace on IE for example). Note: Assume that we will always have ES5 support.

Concerns:

-
I call into the initializer as soon as the constructor is instantiated. I like the idea of having a separate initializer method because it can be swapped out. I don't however like the idea that subsequent calls can be made. Any thoughts on this? I've seen it used a lot in Backbone's source.

-
As you can see I've tried to keep the production flag separate from the general 'enabled' flag. When in production I noop all of the methods instead of wrapping them (or nooping them if unsupported). Perhaps there's a better way of catching all calls to console (like a jasmine style spy) in production?

-
My hope with wrapping each supported method was to have a way of injecting pre-conditions/formatting before it's fired off. I also use this as an opportunity to check flags like enable. Is this over-contrived?

```
var Logger = function () {
this._methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml',
'error', 'exception', 'group', 'groupCollapsed', 'groupEnd',
'info', 'log', 'markTimeline', 'profile', 'profiles',
'profileEnd', 'show', 'table', 'time', 'timeEnd',
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
];

this.initialize.apply(this, arguments);
};

var console = window.console, p = Logger.prototype;

p.initialize = function (options) {
var noop = function () {};

this.options = options || {};

this._enabled = !this.options.production;

this._methods.forEach(function (method) {
if (this.options.production) {
this[method] = noop;
} else {
this[method] = conso

Solution

Interesting question,

I spent a bit of time coding different approaches before writing this. Initially I just was going to point to my SO answer but then I saw you have some more requirements that are not met.

Concern #1

I dislike libraries where I have to initialize stuff outside of the constructor, the constructor should initialize an object so that it is usable! Why give me a half baked object that I cannot use? The idea of being able to swap out a separate initializer is typical YAGNI.

Concern #2

In my mind, the caller should decide whether to enable or disable (possibly based on a production flag or not), for your code to take care of both concerns independantly seems overkill.

Concern #3

It seems over-contrived to me ;)

I did like though the idea of fool-proofing all console methods for an ancient legacy code base, and kept that with 2 simple methods to turn of or on all output in my approach:

function logController(){

  var methods = [
    'assert', 'clear', 'count', 'debug', 'dir', 'dirxml',
    'error', 'exception', 'group', 'groupCollapsed', 'groupEnd',
    'info', 'log', 'markTimeline', 'profile', 'profiles',
    'profileEnd', 'show', 'table', 'time', 'timeEnd',
    'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
  ];
  //The one acceptable time we can pollute the global namespace ;]
  console = console || {};

  function stop(){
    var _method;
    methods.forEach( function (method){
      _method = '_' + method;
      console[_method] = console[_method] || console[method];  
      console[ method] = function noLog(){};
    });
  }

  function start(){
    var _method;
    methods.forEach( function (method){
      _method = '_' + method;
      console[method] = console[_method] || console[method] || function noLog(){};
    });    
  }
  start();

  return {
    start: start,
    stop: stop
  };
}

flow = logController();
console.log( 'Normal logging, next is 123' );
console.log(  123 );
console.log( 'Start logging (which is default state), next is 123' );
flow.start();
console.log(  123 );
console.log( 'Stop logging (which is default state), next is "start logging again"' );
flow.stop();
console.log(  123 );
flow.start();
console.log( 'Started logging (which is default state), next is 123' );
console.log(  123 );


I will keep the exercise to make this work with AMD/UMD in your capable hands ;)

Code Snippets

function logController(){

  var methods = [
    'assert', 'clear', 'count', 'debug', 'dir', 'dirxml',
    'error', 'exception', 'group', 'groupCollapsed', 'groupEnd',
    'info', 'log', 'markTimeline', 'profile', 'profiles',
    'profileEnd', 'show', 'table', 'time', 'timeEnd',
    'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
  ];
  //The one acceptable time we can pollute the global namespace ;]
  console = console || {};

  function stop(){
    var _method;
    methods.forEach( function (method){
      _method = '_' + method;
      console[_method] = console[_method] || console[method];  
      console[ method] = function noLog(){};
    });
  }

  function start(){
    var _method;
    methods.forEach( function (method){
      _method = '_' + method;
      console[method] = console[_method] || console[method] || function noLog(){};
    });    
  }
  start();

  return {
    start: start,
    stop: stop
  };
}

flow = logController();
console.log( 'Normal logging, next is 123' );
console.log(  123 );
console.log( 'Start logging (which is default state), next is 123' );
flow.start();
console.log(  123 );
console.log( 'Stop logging (which is default state), next is "start logging again"' );
flow.stop();
console.log(  123 );
flow.start();
console.log( 'Started logging (which is default state), next is 123' );
console.log(  123 );

Context

StackExchange Code Review Q#70403, answer score: 4

Revisions (0)

No revisions yet.