2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "core/inspector/InspectorConsoleAgent.h"
29 #include "bindings/core/v8/ScriptCallStackFactory.h"
30 #include "bindings/core/v8/ScriptController.h"
31 #include "bindings/core/v8/ScriptProfiler.h"
32 #include "core/frame/LocalFrame.h"
33 #include "core/frame/UseCounter.h"
34 #include "core/inspector/ConsoleMessage.h"
35 #include "core/inspector/ConsoleMessageStorage.h"
36 #include "core/inspector/IdentifiersFactory.h"
37 #include "core/inspector/InjectedScript.h"
38 #include "core/inspector/InjectedScriptHost.h"
39 #include "core/inspector/InjectedScriptManager.h"
40 #include "core/inspector/InspectorState.h"
41 #include "core/inspector/InspectorTimelineAgent.h"
42 #include "core/inspector/InstrumentingAgents.h"
43 #include "core/inspector/ScriptArguments.h"
44 #include "core/inspector/ScriptAsyncCallStack.h"
45 #include "core/inspector/ScriptCallFrame.h"
46 #include "core/inspector/ScriptCallStack.h"
47 #include "core/loader/DocumentLoader.h"
48 #include "core/page/Page.h"
49 #include "core/xmlhttprequest/XMLHttpRequest.h"
50 #include "platform/network/ResourceError.h"
51 #include "platform/network/ResourceResponse.h"
52 #include "wtf/CurrentTime.h"
53 #include "wtf/OwnPtr.h"
54 #include "wtf/PassOwnPtr.h"
55 #include "wtf/text/StringBuilder.h"
56 #include "wtf/text/WTFString.h"
60 namespace ConsoleAgentState {
61 static const char monitoringXHR[] = "monitoringXHR";
62 static const char consoleMessagesEnabled[] = "consoleMessagesEnabled";
63 static const char tracingBasedTimeline[] = "tracingBasedTimeline";
66 int InspectorConsoleAgent::s_enabledAgentCount = 0;
68 InspectorConsoleAgent::InspectorConsoleAgent(InspectorTimelineAgent* timelineAgent, InjectedScriptManager* injectedScriptManager)
69 : InspectorBaseAgent<InspectorConsoleAgent>("Console")
70 , m_timelineAgent(timelineAgent)
71 , m_injectedScriptManager(injectedScriptManager)
77 InspectorConsoleAgent::~InspectorConsoleAgent()
80 m_instrumentingAgents->setInspectorConsoleAgent(0);
84 void InspectorConsoleAgent::trace(Visitor* visitor)
86 visitor->trace(m_timelineAgent);
87 visitor->trace(m_injectedScriptManager);
88 InspectorBaseAgent::trace(visitor);
91 void InspectorConsoleAgent::enable(ErrorString*)
95 m_instrumentingAgents->setInspectorConsoleAgent(this);
97 if (!s_enabledAgentCount)
98 ScriptController::setCaptureCallStackForUncaughtExceptions(true);
99 ++s_enabledAgentCount;
101 m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, true);
103 ConsoleMessageStorage* storage = messageStorage();
104 if (storage->expiredCount()) {
105 RefPtrWillBeRawPtr<ConsoleMessage> expiredMessage = ConsoleMessage::create(OtherMessageSource, WarningMessageLevel, String::format("%d console messages are not shown.", storage->expiredCount()));
106 expiredMessage->setTimestamp(0);
107 sendConsoleMessageToFrontend(expiredMessage.get(), false);
110 size_t messageCount = storage->size();
111 for (size_t i = 0; i < messageCount; ++i)
112 sendConsoleMessageToFrontend(storage->at(i), false);
115 void InspectorConsoleAgent::disable(ErrorString*)
119 m_instrumentingAgents->setInspectorConsoleAgent(0);
121 if (!(--s_enabledAgentCount))
122 ScriptController::setCaptureCallStackForUncaughtExceptions(false);
123 m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, false);
124 m_state->setBoolean(ConsoleAgentState::tracingBasedTimeline, false);
127 void InspectorConsoleAgent::clearMessages(ErrorString*)
129 messageStorage()->clear();
132 void InspectorConsoleAgent::restore()
134 if (m_state->getBoolean(ConsoleAgentState::consoleMessagesEnabled)) {
135 m_frontend->messagesCleared();
141 void InspectorConsoleAgent::setFrontend(InspectorFrontend* frontend)
143 m_frontend = frontend->console();
146 void InspectorConsoleAgent::clearFrontend()
150 disable(&errorString);
153 void InspectorConsoleAgent::addMessageToConsole(ConsoleMessage* consoleMessage)
156 sendConsoleMessageToFrontend(consoleMessage, true);
159 void InspectorConsoleAgent::consoleMessagesCleared()
161 m_injectedScriptManager->releaseObjectGroup("console");
163 m_frontend->messagesCleared();
166 void InspectorConsoleAgent::setTracingBasedTimeline(ErrorString*, bool enabled)
168 m_state->setBoolean(ConsoleAgentState::tracingBasedTimeline, enabled);
171 void InspectorConsoleAgent::consoleTimeline(ExecutionContext* context, const String& title, ScriptState* scriptState)
173 UseCounter::count(context, UseCounter::DevToolsConsoleTimeline);
174 if (!m_state->getBoolean(ConsoleAgentState::tracingBasedTimeline))
175 m_timelineAgent->consoleTimeline(context, title, scriptState);
178 void InspectorConsoleAgent::consoleTimelineEnd(ExecutionContext* context, const String& title, ScriptState* scriptState)
180 if (!m_state->getBoolean(ConsoleAgentState::tracingBasedTimeline))
181 m_timelineAgent->consoleTimelineEnd(context, title, scriptState);
184 void InspectorConsoleAgent::didFinishXHRLoading(XMLHttpRequest*, ThreadableLoaderClient*, unsigned long requestIdentifier, ScriptString, const AtomicString& method, const String& url)
186 if (m_frontend && m_state->getBoolean(ConsoleAgentState::monitoringXHR)) {
187 String message = "XHR finished loading: " + method + " \"" + url + "\".";
188 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(NetworkMessageSource, DebugMessageLevel, message);
189 consoleMessage->setRequestIdentifier(requestIdentifier);
190 messageStorage()->reportMessage(consoleMessage.release());
194 void InspectorConsoleAgent::setMonitoringXHREnabled(ErrorString*, bool enabled)
196 m_state->setBoolean(ConsoleAgentState::monitoringXHR, enabled);
199 static TypeBuilder::Console::ConsoleMessage::Source::Enum messageSourceValue(MessageSource source)
202 case XMLMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Xml;
203 case JSMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Javascript;
204 case NetworkMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Network;
205 case ConsoleAPIMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Console_api;
206 case StorageMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Storage;
207 case AppCacheMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Appcache;
208 case RenderingMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Rendering;
209 case CSSMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Css;
210 case SecurityMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Security;
211 case OtherMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Other;
212 case DeprecationMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Deprecation;
214 return TypeBuilder::Console::ConsoleMessage::Source::Other;
218 static TypeBuilder::Console::ConsoleMessage::Type::Enum messageTypeValue(MessageType type)
221 case LogMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Log;
222 case ClearMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Clear;
223 case DirMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Dir;
224 case DirXMLMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Dirxml;
225 case TableMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Table;
226 case TraceMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Trace;
227 case StartGroupMessageType: return TypeBuilder::Console::ConsoleMessage::Type::StartGroup;
228 case StartGroupCollapsedMessageType: return TypeBuilder::Console::ConsoleMessage::Type::StartGroupCollapsed;
229 case EndGroupMessageType: return TypeBuilder::Console::ConsoleMessage::Type::EndGroup;
230 case AssertMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Assert;
231 case TimeEndMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Log;
232 case CountMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Log;
234 return TypeBuilder::Console::ConsoleMessage::Type::Log;
237 static TypeBuilder::Console::ConsoleMessage::Level::Enum messageLevelValue(MessageLevel level)
240 case DebugMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Debug;
241 case LogMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Log;
242 case WarningMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Warning;
243 case ErrorMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Error;
244 case InfoMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Info;
246 return TypeBuilder::Console::ConsoleMessage::Level::Log;
249 void InspectorConsoleAgent::sendConsoleMessageToFrontend(ConsoleMessage* consoleMessage, bool generatePreview)
251 if (consoleMessage->workerGlobalScopeProxy())
254 RefPtr<TypeBuilder::Console::ConsoleMessage> jsonObj = TypeBuilder::Console::ConsoleMessage::create()
255 .setSource(messageSourceValue(consoleMessage->source()))
256 .setLevel(messageLevelValue(consoleMessage->level()))
257 .setText(consoleMessage->message())
258 .setTimestamp(consoleMessage->timestamp());
259 // FIXME: only send out type for ConsoleAPI source messages.
260 jsonObj->setType(messageTypeValue(consoleMessage->type()));
261 jsonObj->setLine(static_cast<int>(consoleMessage->lineNumber()));
262 jsonObj->setColumn(static_cast<int>(consoleMessage->columnNumber()));
263 if (consoleMessage->scriptId())
264 jsonObj->setScriptId(String::number(consoleMessage->scriptId()));
265 jsonObj->setUrl(consoleMessage->url());
266 ScriptState* scriptState = consoleMessage->scriptState();
268 jsonObj->setExecutionContextId(m_injectedScriptManager->injectedScriptIdFor(scriptState));
269 if (consoleMessage->source() == NetworkMessageSource && consoleMessage->requestIdentifier())
270 jsonObj->setNetworkRequestId(IdentifiersFactory::requestId(consoleMessage->requestIdentifier()));
271 RefPtrWillBeRawPtr<ScriptArguments> arguments = consoleMessage->scriptArguments();
272 if (arguments && arguments->argumentCount()) {
273 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(arguments->scriptState());
274 if (!injectedScript.isEmpty()) {
275 RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::RemoteObject> > jsonArgs = TypeBuilder::Array<TypeBuilder::Runtime::RemoteObject>::create();
276 if (consoleMessage->type() == TableMessageType && generatePreview && arguments->argumentCount()) {
277 ScriptValue table = arguments->argumentAt(0);
278 ScriptValue columns = arguments->argumentCount() > 1 ? arguments->argumentAt(1) : ScriptValue();
279 RefPtr<TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapTable(table, columns);
280 if (!inspectorValue) {
281 ASSERT_NOT_REACHED();
284 jsonArgs->addItem(inspectorValue);
286 for (unsigned i = 0; i < arguments->argumentCount(); ++i) {
287 RefPtr<TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapObject(arguments->argumentAt(i), "console", generatePreview);
288 if (!inspectorValue) {
289 ASSERT_NOT_REACHED();
292 jsonArgs->addItem(inspectorValue);
295 jsonObj->setParameters(jsonArgs);
298 if (consoleMessage->callStack()) {
299 jsonObj->setStackTrace(consoleMessage->callStack()->buildInspectorArray());
300 RefPtrWillBeRawPtr<ScriptAsyncCallStack> asyncCallStack = consoleMessage->callStack()->asyncCallStack();
302 jsonObj->setAsyncStackTrace(asyncCallStack->buildInspectorObject());
304 m_frontend->messageAdded(jsonObj);
308 class InspectableHeapObject final : public InjectedScriptHost::InspectableObject {
310 explicit InspectableHeapObject(int heapObjectId) : m_heapObjectId(heapObjectId) { }
311 virtual ScriptValue get(ScriptState*) override
313 return ScriptProfiler::objectByHeapObjectId(m_heapObjectId);
319 void InspectorConsoleAgent::addInspectedHeapObject(ErrorString*, int inspectedHeapObjectId)
321 m_injectedScriptManager->injectedScriptHost()->addInspectedObject(adoptPtr(new InspectableHeapObject(inspectedHeapObjectId)));
324 void InspectorConsoleAgent::setLastEvaluationResult(ErrorString* errorString, const String& objectId)
326 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
327 if (injectedScript.isEmpty()) {
328 *errorString = "Inspected frame has gone";
331 injectedScript.setLastEvaluationResult(objectId);