Restoring console.log()

后端 未结 8 2390
粉色の甜心
粉色の甜心 2020-11-29 22:25

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. Writi

相关标签:
8条回答
  • 2020-11-29 22:34
    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

    0 讨论(0)
  • 2020-11-29 22:44

    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;
            },
        });
    }
    
    0 讨论(0)
  • 2020-11-29 22:46

    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.

    0 讨论(0)
  • 2020-11-29 22:50

    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() {}
    }
    
    0 讨论(0)
  • 2020-11-29 22:52

    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.

    0 讨论(0)
  • 2020-11-29 22:53

    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.

    0 讨论(0)
提交回复
热议问题