How to properly override console.warn in JavaScript

Viewed 899

I am overriding console.warn to capture the warnings that are printed into the console of the web browser like this and the file in which I am doing this is track.js shown below. The code works absolutely fine.

File 1

// Filename - track.js

function getWarnStatements() {
  window.warnStatements = [];
  var oldWarn = console.warn;
  console.warn = function (message) {
  oldWarn.apply(console, arguments);
   window.warnStatements.push({
    type: 'console.warn',
    data: message,
   });  
 };
} 

File 2

// Filename - xyz.js

console.warn('Hello World');

Let's say I have used console.warn() in some other file which is xyz.js and both track.js and xyz.js runs at the same time. When we normally check the browser console for the warning we will see the file name on the right side of the warning in the console and when we click on the filename it will take us to the javascript file in which the console.warn was written.

ISSUE

Check the image below. Instead of showing xyz.js it is showing track.js. How can i prevent this behavior. I want it to take the user to the correct file where console.warn was used instead of the file where I am over riding it because it will result in misleading the other developers to the wrong file.

enter image description here

1 Answers

Taking a general view the problem is to intercept and capture arguments supplied in calls to console.warn and complete the intention of showing warnings on the console with an indication of where the warning arose in code.

First up you can't hide from a real console.warn call where the call was made from, so simplify matters by dropping all subterfuge. The two options that remain are to produce a full or partial trace of where calls to the substituted warn function are made from.

  1. Full trace.

    In the intercepted warn function make a console.trace call.

  2. Partial trace.

    In the intercepted warn function create a new Error object, slice one or more lines from the object's stack property and log them to the console without using console.warn.

The biggest problem with the second option is that errorObject.stack is not standardized in web standards - while you may test it and achieve outstanding results (with minor differences) in browsers tried, there is no guarantee that it will work in all browsers.

In conclusion solutions that you implement depend on the use case - is it for in-house testing, or if on the web do you need to sniff the presence of Error Object stack properties before using them.

As a side note, console.xxx functions accept multiple parameters which the posted substitute does not record.


Here's a quick example showing the console.warn intermediate function (anonymous in the post) being called directly. Which lines to slice may need fine tuning, and if emoji are not acceptable then substitute as needed:

function interWarn() {
    let args = arguments;
    // save arguments;
    let err = new Error( "trace");
    var stack = err.stack;
    if( !stack) try {
        throw err;
    }
    catch( err) {
        stack = err.stack;
    }
    if( stack) {
        stack = stack.split('\n').slice(1,3).join('\n');
        console.info('⚠️ Warning from\n%s\n%s', stack, '');
    }
    else console.trace();
    console.log.apply(console, args);
}
function foo() {
   interWarn("foo warning, %s", "okay?");
}
foo();

Related