Getting fancy with the console

The trusty console.log() method serves a great functional purpose to write messages to the developer console. But did you know the console object has around twenty other methods you can use? I rarely see developers tapping into the extra power the console provides other than using it as a non-blocking alert. Let’s change that.

I’ve put the following article ideas into real world practice by using Modernizr as a test subject since it uses a fair amount of the concepts discussed in this article. Make sure your console is open and you’re using a good browser.

Just a side note that since I’m doing some hefty logging and using ternary statements inside some of the logs, the actual execution speed of Modernizr is affected. Always remove logs from production code.

More than just messages

Before we dig into the other console methods let’s show some of the powerful functionality console.log() has, such as the ability to pass as many arguments as you want.

var foo = {baz: "tubular", goo: "rad"}, bar = "baz";
console.log("string",1,foo.goo,bar,foo.baz); // string 1 rad baz tubular

This will print out each argument and display it on the one line. That’s kinda useful but what would be better is if we could somehow intertwine all those arguments into a nicely formatted message in the console. Wait we can.

If you’re familiar with printf() in other languages console.log() shares some similarities. Taking the last example and passing in all those extra arguments we can reference them and create a nicely formatted string.

var foo = {baz: "tubular", goo: "rad"}, bar = "baz";
console.log(
     "%s theory is %d %s concept. I can only describe it as %s and %s",
      "string", 1, foo.goo, bar, foo.baz 
);
// string theory is 1 rad concept. I can only describe it as baz and tubular

What do those %s and %d do?

Glad you asked, these are special characters so we can do string formatting within our log message. Basically %s says print the argument as a string, %d says to print the argument as an integer you can also use %i or %f.

Each appearance of the string formatting operator will choose the corresponding argument. First replacement operator will use the first argument and so on so forth.

We can adjust the order in which an argument will appear within the string by using the $ parameter preceded by the argument we wish to print.

var foo = {baz: "tubular", goo: "rad"}, bar = "baz";
console.log(
     "%2$d theory is %d %s concept. I can only describe it as %s and %s",
     "string",1,foo.goo,bar,foo.baz
);
// 1 theory is 0 baz concept. I can only describe it as tubular and %s string

What this string replacement is saying is I’ll start at the second argument and progress from there which as you can see causes an issue.

Essentially the first argument gets appended to the end of our arguments giving us six arguments but we only specified five locations for the strings to be replaced in and since we started at argument two it only prints four of them followed by %s and string.

We can fix this by adjusting the above log message and reset the position so everything will be printed as expected.

var foo = {baz: "tubular", goo: "rad"}, bar = "baz";
console.log(
     "%2$d theory is %1$s %3$s concept. I can only describe it as %s and %s",
     "string",1,foo.goo,bar,foo.baz
);
// 1 theory is string rad concept. I can only describe it as baz and tubular

In order to get the arguments to print out correctly we need to change the starting order of the second and third replaced items. The others are in the correct order so we don’t need to adjust where they should start looking. The string will use the arguments in this order 2,1,3,4,5.

String formatting is a powerful tool and I’ve only scratched the surface. Try experimenting to see what you can get it to do and take a read of some of Joe Hewitts docs on the console.

Different kind of messages

Like log there a few other methods that will allows us to present a message to the console with different styling. Those are console.info(), console.warn() and console.error().

console.info("%s numbers %d, %d and %d","hello",1,2,3); // hello numbers 1, 2 and 3
console.warn("%s numbers %d, %d and %d","hello",1,2,3);
console.error("%s numbers %d, %d and %d","hello",1,2,3);

Firebug example of console.info, console.warn and console.error
Firebug example of console.info(), console.warn() and console.error()

All three can also use string formatting and be passed as many arguments as you want. These can obviously give you much clearer visual clues as to what is going on in your code.

Logging the DOM

When you log a reference to a DOM element the default behaviour is to provide a link to that DOM element with console.dir() and console.dirxml() methods we can inspect the elements properties or create a little subset of the html outline of the element.

console.dir(document.documentElement);
console.dirxml(document.documentElement);

Chrome example of console.dir and console.dirxml
Chrome example of console.dir() and console.dirxml()

Grouping

Sometimes it would be useful to be able to group a bunch console calls for easier referencing we can do that with console.group(), console.groupCollapsed() and console.groupEnd().

console.group("Overlord");
console.log("Overlord stuff");

console.group("Lord");
console.log("Overlord stuff");

console.group("Minion");
console.log("Minion stuff");
console.groupEnd();

console.groupCollapsed("Servant");
console.log("Servant stuff");

Safari example of console.group and console.groupEnd
Safari example of console.group() and console.groupEnd()

As you can see nesting console.group() will further nest the results, in order to end a particular group you use the console.groupEnd(). console.groupCollapsed() is the same as console.group() but the group and its related information will be collapsed.

Code timing and profiling

The console also allows you get fairly accurate timings useing console.time() and console.timeEnd(). These two methods need to be placed at the start and end of what you want to time in your code.

console.time("Execution time took");
// Some code to execute
console.timeEnd("Execution time took");

Firefox example of console.time and console.timeEnd
Firefox example of console.time() and console.timeEnd()

The timers are associated with each other via their labels, this way you can have multiple timers throughout your code. When a timer hits a console.timeEnd() it will output a message with your label and the time it took in milliseconds to execute.

Along with timings we can also profile a subset of your code and output the profile stack, giving lots of juicy information about how much time the browser spent where.

console.profile();
// Some code to execute
console.profileEnd();

Asserting your code

When you begin working on a complex project it’s important to start unit testing your code. This allows you to avoid simple mistakes and possible regressions. Luckily the console also includes assertions.

Assertions allow you to enforce rules in your code and to make sure the results it’s producing are the results you expect. The console.assert() method allows us to do rudimentary unit tests on our code, if something fails the console will throw an exception. The first argument can be anything, function, equality check or checking existence of an object.

var a = 1, b = "1";
console.assert(a === b, "A doesn't equal B");

Chrome example of console.assert
Chrome example of console.assert()

The assert method takes the assertion you want to enforce as the first argument, in this case a simple strict equality check, and the second argument is the message to display if it fails.

Browser support

Most of the following console methods discussed have quite good browser support. IE8+, Firefox with firebug, Opera or a webkit browser such as Safari or Chrome. There are a few differences between the browsers, Firefox, Safari and Chrome having the widest support. A good way of finding support is to do console.dir(console) which gives you nice look at the console object and it’s methods.

Opera with Dragonfly does support most of the methods on the console with the exception of string formatting so no fancy logging with argument re-ordering in dragonfly. There is no timing but no profiling (although there is profile and profileEnd available it will log saying this feature is not yet available).

iOS Safari also has pretty rubbish support, no string formatting, timing, profiling or grouping but the limited screen real estate could be the reason some of these aren’t supported. It does however support assertions.

IE8 has support for a pretty wide range too including string formatting and assertions but no timing, profiling, dir or dirxml.

Having said that using firebug lite can add some of the console methods to unsupporting browsers.

I haven’t discussed everything available in the console but what I did cover would be the most useful features available to make debugging and testing a much smoother process. Go forth and enrich you development with more than just string logging.

[link href=”http://cssn.in/ja/031″]