Home | History | Annotate | Download | only in sdk
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /**
     32  * @constructor
     33  * @extends {WebInspector.TargetAwareObject}
     34  * @param {!WebInspector.Target} target
     35  */
     36 WebInspector.ConsoleModel = function(target)
     37 {
     38     WebInspector.TargetAwareObject.call(this, target);
     39 
     40     /** @type {!Array.<!WebInspector.ConsoleMessage>} */
     41     this.messages = [];
     42     this.warnings = 0;
     43     this.errors = 0;
     44     this._consoleAgent = target.consoleAgent();
     45     target.registerConsoleDispatcher(new WebInspector.ConsoleDispatcher(this));
     46     this._enableAgent();
     47 }
     48 
     49 WebInspector.ConsoleModel.Events = {
     50     ConsoleCleared: "ConsoleCleared",
     51     MessageAdded: "MessageAdded",
     52     CommandEvaluated: "CommandEvaluated",
     53 }
     54 
     55 WebInspector.ConsoleModel.prototype = {
     56     _enableAgent: function()
     57     {
     58         if (WebInspector.settings.monitoringXHREnabled.get())
     59             this._consoleAgent.setMonitoringXHREnabled(true);
     60 
     61         this._enablingConsole = true;
     62 
     63         /**
     64          * @this {WebInspector.ConsoleModel}
     65          */
     66         function callback()
     67         {
     68             delete this._enablingConsole;
     69         }
     70         this._consoleAgent.enable(callback.bind(this));
     71     },
     72 
     73     /**
     74      * @return {boolean}
     75      */
     76     enablingConsole: function()
     77     {
     78         return !!this._enablingConsole;
     79     },
     80 
     81     /**
     82      * @param {!WebInspector.ConsoleMessage} msg
     83      * @param {boolean=} isFromBackend
     84      */
     85     addMessage: function(msg, isFromBackend)
     86     {
     87         if (isFromBackend && WebInspector.NetworkManager.hasDevToolsRequestHeader(msg.request))
     88             return;
     89 
     90         msg.index = this.messages.length;
     91         this.messages.push(msg);
     92         this._incrementErrorWarningCount(msg);
     93 
     94         this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.MessageAdded, msg);
     95     },
     96 
     97     show: function()
     98     {
     99         WebInspector.Revealer.reveal(this);
    100     },
    101 
    102     /**
    103      * @param {string} messageText
    104      * @param {!WebInspector.ConsoleMessage.MessageLevel=} messageLevel
    105      * @param {boolean=} showConsole
    106      */
    107     log: function(messageText, messageLevel, showConsole)
    108     {
    109         var message = new WebInspector.ConsoleMessage(
    110             this.target(),
    111             WebInspector.ConsoleMessage.MessageSource.Other,
    112             messageLevel || WebInspector.ConsoleMessage.MessageLevel.Debug,
    113             messageText);
    114 
    115         this.addMessage(message);
    116         if (showConsole)
    117             this.show();
    118     },
    119 
    120     /**
    121      * @param {string} error
    122      */
    123     showErrorMessage: function(error)
    124     {
    125         this.log(error, WebInspector.ConsoleMessage.MessageLevel.Error, true);
    126     },
    127 
    128     /**
    129      * @param {!WebInspector.ConsoleMessage} msg
    130      */
    131     _incrementErrorWarningCount: function(msg)
    132     {
    133         switch (msg.level) {
    134             case WebInspector.ConsoleMessage.MessageLevel.Warning:
    135                 this.warnings++;
    136                 break;
    137             case WebInspector.ConsoleMessage.MessageLevel.Error:
    138                 this.errors++;
    139                 break;
    140         }
    141     },
    142 
    143     requestClearMessages: function()
    144     {
    145         this._consoleAgent.clearMessages();
    146         this.clearMessages();
    147     },
    148 
    149     clearMessages: function()
    150     {
    151         this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.ConsoleCleared);
    152 
    153         this.messages = [];
    154         this.errors = 0;
    155         this.warnings = 0;
    156     },
    157 
    158     __proto__: WebInspector.TargetAwareObject.prototype
    159 }
    160 
    161 /**
    162  * @param {!WebInspector.ExecutionContext} executionContext
    163  * @param {string} text
    164  * @param {boolean=} useCommandLineAPI
    165  */
    166 WebInspector.ConsoleModel.evaluateCommandInConsole = function(executionContext, text, useCommandLineAPI)
    167 {
    168     useCommandLineAPI = !!useCommandLineAPI;
    169     var target = executionContext.target();
    170 
    171     var commandMessage = new WebInspector.ConsoleMessage(target, WebInspector.ConsoleMessage.MessageSource.JS, null, text, WebInspector.ConsoleMessage.MessageType.Command);
    172     target.consoleModel.addMessage(commandMessage);
    173 
    174     /**
    175      * @param {?WebInspector.RemoteObject} result
    176      * @param {boolean} wasThrown
    177      * @param {?RuntimeAgent.RemoteObject=} valueResult
    178      * @this {WebInspector.ConsoleModel}
    179      */
    180     function printResult(result, wasThrown, valueResult)
    181     {
    182         if (!result)
    183             return;
    184 
    185         this.show();
    186         this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.CommandEvaluated, {result: result, wasThrown: wasThrown, text: text, commandMessage: commandMessage});
    187     }
    188 
    189     executionContext.evaluate(text, "console", useCommandLineAPI, false, false, true, printResult.bind(target.consoleModel));
    190 
    191     WebInspector.userMetrics.ConsoleEvaluated.record();
    192 }
    193 
    194 
    195 /**
    196  * @constructor
    197  * @param {?WebInspector.Target} target
    198  * @param {string} source
    199  * @param {?string} level
    200  * @param {string} messageText
    201  * @param {string=} type
    202  * @param {?string=} url
    203  * @param {number=} line
    204  * @param {number=} column
    205  * @param {!NetworkAgent.RequestId=} requestId
    206  * @param {!Array.<!RuntimeAgent.RemoteObject>=} parameters
    207  * @param {!Array.<!ConsoleAgent.CallFrame>=} stackTrace
    208  * @param {number=} timestamp
    209  * @param {boolean=} isOutdated
    210  * @param {!RuntimeAgent.ExecutionContextId=} executionContextId
    211  */
    212 WebInspector.ConsoleMessage = function(target, source, level, messageText, type, url, line, column, requestId, parameters, stackTrace, timestamp, isOutdated, executionContextId)
    213 {
    214     this._target = target;
    215     this.source = source;
    216     this.level = level;
    217     this.messageText = messageText;
    218     this.type = type || WebInspector.ConsoleMessage.MessageType.Log;
    219     this.url = url || null;
    220     this.line = line || 0;
    221     this.column = column || 0;
    222     this.parameters = parameters;
    223     this.stackTrace = stackTrace;
    224     this.timestamp = timestamp || Date.now();
    225     this.isOutdated = isOutdated;
    226     this.executionContextId = executionContextId || 0;
    227 
    228     this.request = requestId ? target.networkLog.requestForId(requestId) : null;
    229 
    230     if (this.request) {
    231         this.stackTrace = this.request.initiator.stackTrace;
    232         if (this.request.initiator && this.request.initiator.url) {
    233             this.url = this.request.initiator.url;
    234             this.line = this.request.initiator.lineNumber;
    235         }
    236     }
    237 }
    238 
    239 WebInspector.ConsoleMessage.prototype = {
    240     /**
    241      * @return {?WebInspector.Target}
    242      */
    243     target: function()
    244     {
    245         return this._target;
    246     },
    247 
    248     /**
    249      * @param {!WebInspector.ConsoleMessage} originatingMessage
    250      */
    251     setOriginatingMessage: function(originatingMessage)
    252     {
    253         this._originatingConsoleMessage = originatingMessage;
    254     },
    255 
    256     /**
    257      * @return {?WebInspector.ConsoleMessage}
    258      */
    259     originatingMessage: function()
    260     {
    261         return this._originatingConsoleMessage;
    262     },
    263 
    264     /**
    265      * @return {boolean}
    266      */
    267     isGroupMessage: function()
    268     {
    269         return this.type === WebInspector.ConsoleMessage.MessageType.StartGroup ||
    270             this.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed ||
    271             this.type === WebInspector.ConsoleMessage.MessageType.EndGroup;
    272     },
    273 
    274     /**
    275      * @return {boolean}
    276      */
    277     isGroupStartMessage: function()
    278     {
    279         return this.type === WebInspector.ConsoleMessage.MessageType.StartGroup ||
    280             this.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed;
    281     },
    282 
    283     /**
    284      * @return {boolean}
    285      */
    286     isErrorOrWarning: function()
    287     {
    288         return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
    289     },
    290 
    291     /**
    292      * @return {!WebInspector.ConsoleMessage}
    293      */
    294     clone: function()
    295     {
    296         return new WebInspector.ConsoleMessage(
    297             this.target(),
    298             this.source,
    299             this.level,
    300             this.messageText,
    301             this.type,
    302             this.url,
    303             this.line,
    304             this.column,
    305             this.request ? this.request.requestId : undefined,
    306             this.parameters,
    307             this.stackTrace,
    308             this.timestamp,
    309             this.isOutdated,
    310             this.executionContextId);
    311     },
    312 
    313     /**
    314      * @param {?WebInspector.ConsoleMessage} msg
    315      * @return {boolean}
    316      */
    317     isEqual: function(msg)
    318     {
    319         if (!msg)
    320             return false;
    321 
    322         if (this.stackTrace) {
    323             if (!msg.stackTrace || this.stackTrace.length !== msg.stackTrace.length)
    324                 return false;
    325 
    326             for (var i = 0; i < msg.stackTrace.length; ++i) {
    327                 if (this.stackTrace[i].url !== msg.stackTrace[i].url ||
    328                     this.stackTrace[i].functionName !== msg.stackTrace[i].functionName ||
    329                     this.stackTrace[i].lineNumber !== msg.stackTrace[i].lineNumber ||
    330                     this.stackTrace[i].columnNumber !== msg.stackTrace[i].columnNumber)
    331                     return false;
    332             }
    333         }
    334 
    335         if (this.parameters) {
    336             if (!msg.parameters || this.parameters.length !== msg.parameters.length)
    337                 return false;
    338 
    339             for (var i = 0; i < msg.parameters.length; ++i) {
    340                 // Never treat objects as equal - their properties might change over time.
    341                 if (this.parameters[i].type !== msg.parameters[i].type || msg.parameters[i].type === "object" || this.parameters[i].value !== msg.parameters[i].value)
    342                     return false;
    343             }
    344         }
    345 
    346         return (this.target() === msg.target())
    347             && (this.source === msg.source)
    348             && (this.type === msg.type)
    349             && (this.level === msg.level)
    350             && (this.line === msg.line)
    351             && (this.url === msg.url)
    352             && (this.messageText === msg.messageText)
    353             && (this.request === msg.request)
    354             && (this.executionContextId === msg.executionContextId);
    355     }
    356 }
    357 
    358 // Note: Keep these constants in sync with the ones in Console.h
    359 /**
    360  * @enum {string}
    361  */
    362 WebInspector.ConsoleMessage.MessageSource = {
    363     XML: "xml",
    364     JS: "javascript",
    365     Network: "network",
    366     ConsoleAPI: "console-api",
    367     Storage: "storage",
    368     AppCache: "appcache",
    369     Rendering: "rendering",
    370     CSS: "css",
    371     Security: "security",
    372     Other: "other",
    373     Deprecation: "deprecation"
    374 }
    375 
    376 /**
    377  * @enum {string}
    378  */
    379 WebInspector.ConsoleMessage.MessageType = {
    380     Log: "log",
    381     Dir: "dir",
    382     DirXML: "dirxml",
    383     Table: "table",
    384     Trace: "trace",
    385     Clear: "clear",
    386     StartGroup: "startGroup",
    387     StartGroupCollapsed: "startGroupCollapsed",
    388     EndGroup: "endGroup",
    389     Assert: "assert",
    390     Result: "result",
    391     Profile: "profile",
    392     ProfileEnd: "profileEnd",
    393     Command: "command"
    394 }
    395 
    396 /**
    397  * @enum {string}
    398  */
    399 WebInspector.ConsoleMessage.MessageLevel = {
    400     Log: "log",
    401     Info: "info",
    402     Warning: "warning",
    403     Error: "error",
    404     Debug: "debug"
    405 }
    406 
    407 /**
    408  * @param {!WebInspector.ConsoleMessage} a
    409  * @param {!WebInspector.ConsoleMessage} b
    410  * @return {number}
    411  */
    412 WebInspector.ConsoleMessage.timestampComparator = function (a, b)
    413 {
    414     return a.timestamp - b.timestamp;
    415 }
    416 
    417 /**
    418  * @constructor
    419  * @implements {ConsoleAgent.Dispatcher}
    420  * @param {!WebInspector.ConsoleModel} console
    421  */
    422 WebInspector.ConsoleDispatcher = function(console)
    423 {
    424     this._console = console;
    425 }
    426 
    427 WebInspector.ConsoleDispatcher.prototype = {
    428     /**
    429      * @param {!ConsoleAgent.ConsoleMessage} payload
    430      */
    431     messageAdded: function(payload)
    432     {
    433         var consoleMessage = new WebInspector.ConsoleMessage(
    434             this._console.target(),
    435             payload.source,
    436             payload.level,
    437             payload.text,
    438             payload.type,
    439             payload.url,
    440             payload.line,
    441             payload.column,
    442             payload.networkRequestId,
    443             payload.parameters,
    444             payload.stackTrace,
    445             payload.timestamp * 1000, // Convert to ms.
    446             this._console._enablingConsole,
    447             payload.executionContextId);
    448         this._console.addMessage(consoleMessage, true);
    449     },
    450 
    451     /**
    452      * @param {number} count
    453      */
    454     messageRepeatCountUpdated: function(count)
    455     {
    456     },
    457 
    458     messagesCleared: function()
    459     {
    460         if (!WebInspector.settings.preserveConsoleLog.get())
    461             this._console.clearMessages();
    462     }
    463 }
    464 
    465 /**
    466  * @type {!WebInspector.ConsoleModel}
    467  */
    468 WebInspector.console;
    469