Skip to content

Instantly share code, notes, and snippets.

@robatron
Last active October 27, 2024 14:01
Show Gist options
  • Select an option

  • Save robatron/5681424 to your computer and use it in GitHub Desktop.

Select an option

Save robatron/5681424 to your computer and use it in GitHub Desktop.
Wrapping `console.log` (et al.) in your own function to modify logging behavior.

JavaScript Log Wrapping

Wrapping console.log (et al.) in your own function to modify logging behavior.

Why?

You may want a simple way to:

  • Enable/disable logging with a flag, e.g., DEBUG = true
  • Prefix log messages with a common string to identify message origin, e.g., >>> [MyClass] Hello!
  • Shorter logging syntax, e.g., log("Hello!")
  • Etc.

We can acheive simple log wrappings by fiddling with the arguments object available in all JavaScript functions, and utilizing Function.prototype.apply.

Demo

For the impatient, a simple demo of these concepts can be found here.

Basic log wraps

The most basic log wrap to exactly mimic console.log behavior, e.g., to shorten logging syntax, looks like the following, which applies the arguments supplied to log when calling console.log.

var log = function(){
    console.log.apply(console, arguments);
}

Now you can do simple things like add a DEBUG flag to enable/disable logging:

var DEBUG=true; // Enable logging

var log = function(){
    if(DEBUG){
        console.log.apply(console, arguments);
    }
}

Modifying Log Messages

You may want to modify the log messages, e.g., add a prefix to all logged messages to determine where the message is coming from, e.g.,

var LOG_PREFIX = "[MyClass]"

var log = function(){

    // 1. Convert args to a normal array
    var args = Array.prototype.slice.call(arguments);
        
    // 2. Prepend log prefix log string
    args.unshift(LOG_PREFIX + " ");
        
    // 3. Pass along arguments to console.log
    console.log.apply(console, args);
}

We must convert the arguments object to a proper array to use Array.unshift. This is because the arguments object is only an "Array-like" object, i.e., you can use subscripts, e.g., arguments[0], and get its arguments.length property, but that's about it.

References

By Rob McGuire, May 2013

@lakmeer

lakmeer commented May 31, 2013

Copy link
Copy Markdown

Another useful trick: return arguments[0] at the end, to quickly echo values in the middle of expressions without disrupting the computation.

var z = myConst + someCalculation(x) / width;
// What is someCalculation(x)?
var z = myConst + log( someCalculation(x) ) / width;

@robatron

Copy link
Copy Markdown
Author

Smooth! Thanks for sharing!

@magnetikonline

Copy link
Copy Markdown

Somewhat related, to handle LOG_PREFIX style logging with Google Chrome, you should check out the console.group() and console.groupEnd() methods - really useful.

@tomprogers

tomprogers commented Sep 12, 2016

Copy link
Copy Markdown

Thanks for the gist!

The only real issue we've still got is that the line number reported in the log output always corresponds to the line where the custom log function ultimately invokes the native console.log, instead of the line elsewhere that invokes our custom log function. If anyone has suggestions for how to remedy that, I'd love to hear them.

One of these evenings I'm going to dig further into this post on SO to address the line number issue:

@kopax

kopax commented Dec 16, 2016

Copy link
Copy Markdown

There are rest parameters in ES2015.
We can use that feature for variadic functions instead of the arguments variable.

arguments does not have methods of Array.prototype, so it's a bit of an inconvenience.

Examples

Examples of deprecated code for this rule in ES6

function foo(action) {
    var args = Array.prototype.slice.call(arguments);
    action.apply(null, args);
}

Examples of correct code in ES6

function foo(...args) {
    console.log.apply(this, args);
}

@dfoverdx

dfoverdx commented Apr 1, 2018

Copy link
Copy Markdown

@tomprogers Did you ever figure out getting the line numbers correct?

@lacymorrow

lacymorrow commented Feb 23, 2020

Copy link
Copy Markdown

I've been trying to write a custom function to process the arguments and bind console log but I'm losing the line numbers.

If anyone can figure this out, please post!

I essentially want this, but to maintain the line number:

(...args) => {
    // do something with args...
    console.log.apply(this, args);
}

@louiechristie

Copy link
Copy Markdown

Typescript version?

@fstamour

Copy link
Copy Markdown

Typescript version:

log(...args: any[]) {
    if (this.debug) {
        console.log.apply(console, arguments);
    }
}

@JonFranklin301

Copy link
Copy Markdown

To log with line numbers you need to bind to the console.

var debug = console.log.bind(window.console);
// You could even do this:
console.debug = console.log.bind(window.console);

You can now call console.debug(...) and it will peform a console.log

debug('some message', 'with args');
// or
console.debug('some message', 'with args');

And you can add a switch like

var debugMode = true;

var debug = debugMode ? console.log.bind(window.console) : function(){};
// or
if(debugMode) {
    console.debug = console.log.bind(window.console);
}


// this will only log to the console when debugMode === true
debug('We are in debug mode!')
console.debug('Yay!');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment