Restoring console.log()
Asked Answered
G

8

70

For some reason, the prototype framework (or another JavaScript code) that is shipped with Magento is replacing standard console functions, so I can't debug anything. Writing down in JavaScript console console I get the following output:

> console
Object
assert: function () {}
count: function () {}
debug: function () {}
dir: function () {}
dirxml: function () {}
error: function () {}
group: function () {}
groupEnd: function () {}
info: function () {}
log: function () {}
profile: function () {}
profileEnd: function () {}
time: function () {}
timeEnd: function () {}
trace: function () {}
warn: function () {}

I'm using Google Chrome version 13.0.782.112 on Linux.

Prototype JavaScript framework, version 1.6.0.3

Is there a quick way to solve this?

Globose answered 17/8, 2011 at 7:52 Comment(3)
Have a look at #7081933Shrier
Looks like there's an open issue with Magento regarding this: magentocommerce.com/bug-tracking/issue/?issue=11312Determine
Yes, it seems like I have this problem, but I'm not intending to change magento code and for dev I'm ok with the accepted solution.Globose
B
48

For example,

delete console.log

would also restore console.log:

console.log = null;
console.log;         // null

delete console.log;
console.log;         // function log() { [native code] }
Biz answered 17/8, 2011 at 8:14 Comment(8)
Yes! This is even better! This is why I love stackoverflow :DGlobose
@Shoan: Works for me in Chrome 26.Biz
@Biz Actually you are right, it works even in v25. Unfortunately, in my case, the console.log was replaced with a empty function by an included script. In that scenario, this fix wouldn't work.Floccus
try delete window.console instead, that works for me in chrome 30.x;Sapsago
Doesn't work in Chrome 52 anymore. Can be tested on Twitter, for example: console.log -> function() {}, deleting either console.log or window.console.log will just remove it, without restoring the original behavior.Stereo
can confirm... it doesn't work in newer chrome. I am working on extending owncloud and they removed console.log (WTF?)Undaunted
Here's a trick that might help with Chrome not restoring the native log function when using delete console.log... If you are willing to install (or already have) TamperMonkey, then you just need a simple script... setTimeout(() => { unsafeWindow.console = window.console; }, 2000); Tampermonkey scripts get their own copy of a window object, so all you need to do is restore the original console object after a delay. Tweak as needed... (Make sure you remove the default // @grant none).Hospitalization
This answer no longer works; please change or update the answer or accepted answer.Villar
A
120

Since original console is in window.console object, try restoring window.console from iframe:

var i = document.createElement('iframe');
i.style.display = 'none';
document.body.appendChild(i);
window.console = i.contentWindow.console;
// with Chrome 60+ don't remove the child node
// i.parentNode.removeChild(i);

Works for me on Chrome 14.

Afebrile answered 17/8, 2011 at 8:2 Comment(11)
To anyone who's going to use this, please remember to clean up after yourselves. AKA: i.parentNode.removeChild(i);Teeming
I wonder why this is necessary at all, just resetting by unsetting works for me with no problems at all - https://mcmap.net/q/176121/-javascript-console-log-in-magentoOstentation
This answer actually works in current versions of Chrome (52+), while the accepted answer doesn't.Stereo
This is the most creative answer I've ever seen! Thank you.Benedictus
This is the good answer that worked for me. The "checked" one isnt workingLilytrotter
This is only storing a reference to the iframe's console object, you can't remove the iframe afterward or you'll end up with a broken reference (answer updated to reflect this).Gamez
@NickCoad It still works after last i.parentNode.removeChild(i), doesn't it?Unharness
@Xaerxess not in my testing (Chrome 59.0.3071.115)Gamez
I'm using Chrome 63 (Canary) and this answer works, but only without the line i.parentNode.removeChild(i);.Killoran
This works in firefox, but you won't see the messages in developper tools, because they are linked to the top window instance. You can still see the messages in the global console (Ctrl+Shift+j)Deguzman
Clean after yourselves only after you've finished using the console! It won't work properly without the child.Internecine
B
48

For example,

delete console.log

would also restore console.log:

console.log = null;
console.log;         // null

delete console.log;
console.log;         // function log() { [native code] }
Biz answered 17/8, 2011 at 8:14 Comment(8)
Yes! This is even better! This is why I love stackoverflow :DGlobose
@Shoan: Works for me in Chrome 26.Biz
@Biz Actually you are right, it works even in v25. Unfortunately, in my case, the console.log was replaced with a empty function by an included script. In that scenario, this fix wouldn't work.Floccus
try delete window.console instead, that works for me in chrome 30.x;Sapsago
Doesn't work in Chrome 52 anymore. Can be tested on Twitter, for example: console.log -> function() {}, deleting either console.log or window.console.log will just remove it, without restoring the original behavior.Stereo
can confirm... it doesn't work in newer chrome. I am working on extending owncloud and they removed console.log (WTF?)Undaunted
Here's a trick that might help with Chrome not restoring the native log function when using delete console.log... If you are willing to install (or already have) TamperMonkey, then you just need a simple script... setTimeout(() => { unsafeWindow.console = window.console; }, 2000); Tampermonkey scripts get their own copy of a window object, so all you need to do is restore the original console object after a delay. Tweak as needed... (Make sure you remove the default // @grant none).Hospitalization
This answer no longer works; please change or update the answer or accepted answer.Villar
L
12

Magento has the following code in /js/varien/js.js - comment it out & it will work.

if (!("console" in window) || !("firebug" in console))
{
    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];

    window.console = {};
    for (var i = 0; i < names.length; ++i)
        window.console[names[i]] = function() {}
}
Lundgren answered 22/2, 2012 at 5:58 Comment(0)
F
12

Just in case that someone face this same situation. I did not replied to the original answer for Xaerxess because I don't have enough reputation to do it. Looks like that is the correct answer, but for some reason I notice sometimes it works in my software and sometimes not...

So I tried completing deleting before running the script and looks like everything is working fine 100% of times.

if (!("console" in window) || !("firebug" in console))
{

  console.log = null;
  console.log;         // null

  delete console.log;

  // Original by Xaerxess
  var i = document.createElement('iframe');
  i.style.display = 'none';
  document.body.appendChild(i);
  window.console = i.contentWindow.console;

}

Thank you to everybody.

Fritzsche answered 9/3, 2019 at 16:47 Comment(2)
Shouldn't this be the accepted answer now as the original accepted answer doesn't work anymore on the latest Chrome or Firefox?Bland
This worked for me. just doing delete console.log did not work so this should be the accepted answer.Longwood
T
6

delete window.console restores the original console object in Firefox and Chrome.

How does this work? window is a hosted object and usually it is implemented with a common prototype between all instances (you have many tabs in the browser).

Some dumb developers of external libraries/frameworks (or Firebug, etc.) override property console of the window instance, but it doesn't corrupt window.prototype. By the delete operator we are back dispatching from the console.* methods to prototype code.

Tahsildar answered 5/12, 2013 at 11:5 Comment(0)
U
3
function restoreConsole() {
  // Create an iframe for start a new console session
  var iframe = document.createElement('iframe');
  // Hide iframe
  iframe.style.display = 'none';
  // Inject iframe on body document
  document.body.appendChild(iframe);
  // Reassign the global variable console with the new console session of the iframe 
  console = iframe.contentWindow.console;
  window.console = console;
  // Don't remove the iframe or console session will be closed
}

Tested on Chrome 71 and Firefox 65

Ulterior answered 20/11, 2018 at 11:44 Comment(3)
This is the same answer as @Xaerxess, if you look into the comments of his answer, you have that warning for new Chrome versions... you could just upvote his answer and upvote the comment as well, no need to duplicate.Pantywaist
@Pantywaist is not the same because this function don't remove the child then if you don't remove the child still working else the console won't print nothing :)Ulterior
just because you change one line of code, should not be a new answer... Stackoverflow is not to measure how writes better code, but to help the next one to get the right answer quickly.Pantywaist
A
1

Save a reference to the original console in a variable at the very start of the script and then either use this reference, or redefine console to point to the captured value.

Example:

var c = window.console;

window.console = {
    log :function(str) {
        alert(str);
    }
}

// alerts hello
console.log("hello");

// logs to the console
c.log("hello");
Anticathexis answered 17/8, 2011 at 8:0 Comment(1)
Sure I could do it, injecting some JS just before everything and I'm sure this solutions works, but I wanted a quick way to solve the problem. Thanks anywayGlobose
P
-1

The solutions given in this question no longer solve this problem correctly in new browsers. The only one that (sort of) work is grasping the console from an <iframe> as told by @Xaerxess.

I wrote an userscript that protects console from being overwritten. It doesn't break any tools that override the console - it calls both the overridden and original methods. It can of course also be included in web-page.

// ==UserScript==
// @name        Protect console
// @namespace   util
// @description Protect console methods from being overriden
// @include     *
// @version     1
// @grant       none
// @run-at      document-start
// ==/UserScript==
{

    /**
      * This object contains new methods assigned to console.
      * @type {{[x:string]:Function}} **/
    const consoleOverridenValues = {};
    /**
      * This object contains original methods copied from the console object
      * @type {{[x:string]:Function}} **/
    const originalConsole = {};
    window.originalConsole = originalConsole;
    // This is the original console object taken from window object
    const originalConsoleObject = console;
    /**
     * 
     * @param {string} name
     */
    function protectConsoleEntry(name) {
        const protectorSetter = function (newValue) {
            originalConsole.warn("Someone tried to change console." + name + " to ", newValue);
            consoleOverridenValues[name] = function () {
                /// call original console first
                originalConsole[name].apply(originalConsoleObject, arguments);
                if (typeof newValue == "function") {
                    /// call inherited console
                    newValue.apply(window.console, arguments);
                }
            }
        }
        const getter = function () {
            if (consoleOverridenValues[name])
                return consoleOverridenValues[name];
            else
                return originalConsole[name];
        }
        Object.defineProperty(console, name, {
            enumerable: true,
            configurable: false,
            get: getter,
            set: protectorSetter
        });
    }

    /*
     *** This section contains window.console protection
     *** It mirrors any properties of newly assigned values
     *** to the overridenConsoleValues
     *** so that they can be used properly
    */

    /** 
      * This is any new object assigned to window.console
      * @type {Object} **/
    var consoleOverridenObject = null;
    /// Separate boolean is used instead
    /// of checking consoleOverridenObject == null
    /// This allows null and undefined to be assigned with 
    /// expected result
    var consoleIsOverriden = false;

    for (var i in console) {
        originalConsole[i] = console[i];
        protectConsoleEntry(i);
    }

    Object.defineProperty(window, "console", {
        /// always returns the original console object
       /// get: function () { return consoleIsOverriden ? consoleOverridenObject : originalConsoleObject; },
        get: function () { return originalConsoleObject; },
        set: function (val) {
            originalConsole.log("Somebody tried to override window.console. I blocked this attempt."
                + " However the emulation is not perfect in this case because: \n"
                + "     window.console = myObject;\n"
                + "     window.console == myObject\n"
                + "returns false."
            )
            consoleIsOverriden = true;
            consoleOverridenObject = val;

            for (let propertyName in val) {
                consoleOverridenValues[propertyName] = val[propertyName];
            }
            return console;
        },
    });
}
Paresis answered 23/11, 2017 at 22:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.