JavaScript Logging with a bit of Sanity
Browsers have come a long way in giving web developers a set of useful tools for debugging JavaScript (JS): gone are the days of littering alert()
statements throughout your code. We now have inspectors, debuggers, and other tools that make things much easier. And you've probably encountered console.log
and the power of JS consoles. This can provide some good insight into what's going on with your code, but there is a catch.
- The console isn't alway present. Some browsers do not expose a console if the user has not enabled it (or doesn't have an extension that does that for them). This means that if you have some calls to
console.log
scattered in your code, this will break JS on that page. - Having your log statements run when you're not actively inspecting those logs (like when your code is in production) can slow down the JS on your site, affecting all your users.
Log smarter
To solve these two problems, here's a common template I use for JavaScript functionality:
/**
* My JS functionality
*/
(function() {
var my_functionality = {
// should we log messages to the console
debug: true,
// can we log messages to the console
can_log: (typeof console !== 'undefined' && typeof console.log !== 'undefined'),
/**
* Debug aware debugging
*/
log: function() {
if (!this.debug || !this.can_log) { return; }
console.log.apply(console, arguments);
}
};
})();
Now, we can use my_functionality.log
within our code:
awesome_functionality: function() {
my_functionality.log('awesome_functionality!');
}
When we're done with debugging, we can switch the debug
property to false
. What does this do? Well, primarily it will check to see if there is a console.log
to interact with before using it (fixing problem #1) and we also have a debug flag that allows us to turn off logging for production (fixing problem #2).
Working with teams
This works pretty well as-is but it can be a bit better. On projects with several people working on JS you may find yourself constantly changing those debug flags over to true
(or false
if you commit that to your codebase!). To help with this, let's change this based on local settings and then inject this into the site's JavaScript based on this.
This part will vary depending on your application stack, but here's an example of how to handle this for Drupal.
First, we want to add this to our sites/default/settings.php
file:
<span style="color: #0000ff;">$conf</span><span style="color: #66cc66;">[</span><span style="color: #ff0000;">'js_debug'</span><span style="color: #66cc66;">]</span> = <span style="color: #000000; font-weight: bold;">true</span>;
Next, we'll add a call to hook_js_alter
in our template.php
file in our theme. This will add the debug setting to Drupal.settings
.
/**
* Implements hook_js_alter().
*/
function my_theme_js_alter(&$javascript) {
drupal_add_js(
array('js_debug' => variable_get('js_debug', FALSE)),
'setting'
);
}
Finally, we'll update our template with:
// use the settings.php js_debug setting in my_functionality
jQuery(document).ready(function() {
if (typeof Drupal.settings.js_debug !== 'undefined') {
my_functionality.debug = Drupal.settings.js_debug;
}
});
For projects with multiple JS libraries and multiple "debug" settings, it may be worthwhile to make this js_debug
variable an array with settings for specific libraries.