• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
36WebInspector.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
49WebInspector.ConsoleModel.Events = {
50    ConsoleCleared: "ConsoleCleared",
51    MessageAdded: "MessageAdded",
52    CommandEvaluated: "CommandEvaluated",
53}
54
55WebInspector.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 */
166WebInspector.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 */
212WebInspector.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
239WebInspector.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 */
362WebInspector.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 */
379WebInspector.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 */
399WebInspector.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 */
412WebInspector.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 */
422WebInspector.ConsoleDispatcher = function(console)
423{
424    this._console = console;
425}
426
427WebInspector.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 */
468WebInspector.console;
469