2 * Copyright (C) 2014 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "InspectorConsoleAgent.h"
31 #include "ConsoleMessage.h"
32 #include "InjectedScriptManager.h"
33 #include "ScriptArguments.h"
34 #include "ScriptCallFrame.h"
35 #include "ScriptCallStack.h"
36 #include "ScriptCallStackFactory.h"
37 #include "ScriptObject.h"
38 #include <wtf/CurrentTime.h>
39 #include <wtf/text/StringBuilder.h>
40 #include <wtf/text/WTFString.h>
44 static const unsigned maximumConsoleMessages
= 1000;
45 static const int expireConsoleMessagesStep
= 100;
47 InspectorConsoleAgent::InspectorConsoleAgent(InjectedScriptManager
* injectedScriptManager
)
48 : InspectorAgentBase(ASCIILiteral("Console"))
49 , m_injectedScriptManager(injectedScriptManager
)
50 , m_previousMessage(nullptr)
51 , m_expiredConsoleMessageCount(0)
56 InspectorConsoleAgent::~InspectorConsoleAgent()
60 void InspectorConsoleAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel
* frontendChannel
, InspectorBackendDispatcher
* backendDispatcher
)
62 m_frontendDispatcher
= std::make_unique
<InspectorConsoleFrontendDispatcher
>(frontendChannel
);
63 m_backendDispatcher
= InspectorConsoleBackendDispatcher::create(backendDispatcher
, this);
66 void InspectorConsoleAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason
)
68 m_frontendDispatcher
= nullptr;
69 m_backendDispatcher
.clear();
72 disable(&errorString
);
75 void InspectorConsoleAgent::enable(ErrorString
*)
82 if (m_expiredConsoleMessageCount
) {
83 ConsoleMessage
expiredMessage(MessageSource::Other
, MessageType::Log
, MessageLevel::Warning
, String::format("%d console messages are not shown.", m_expiredConsoleMessageCount
));
84 expiredMessage
.addToFrontend(m_frontendDispatcher
.get(), m_injectedScriptManager
, false);
87 size_t messageCount
= m_consoleMessages
.size();
88 for (size_t i
= 0; i
< messageCount
; ++i
)
89 m_consoleMessages
[i
]->addToFrontend(m_frontendDispatcher
.get(), m_injectedScriptManager
, false);
92 void InspectorConsoleAgent::disable(ErrorString
*)
100 void InspectorConsoleAgent::clearMessages(ErrorString
*)
102 m_consoleMessages
.clear();
103 m_expiredConsoleMessageCount
= 0;
104 m_previousMessage
= nullptr;
106 m_injectedScriptManager
->releaseObjectGroup(ASCIILiteral("console"));
108 if (m_frontendDispatcher
&& m_enabled
)
109 m_frontendDispatcher
->messagesCleared();
112 void InspectorConsoleAgent::reset()
115 clearMessages(&error
);
121 void InspectorConsoleAgent::addMessageToConsole(MessageSource source
, MessageType type
, MessageLevel level
, const String
& message
, PassRefPtr
<ScriptCallStack
> callStack
, unsigned long requestIdentifier
)
123 if (!m_injectedScriptManager
->inspectorEnvironment().developerExtrasEnabled())
126 if (type
== MessageType::Clear
) {
128 clearMessages(&error
);
131 addConsoleMessage(std::make_unique
<ConsoleMessage
>(source
, type
, level
, message
, callStack
, requestIdentifier
));
134 void InspectorConsoleAgent::addMessageToConsole(MessageSource source
, MessageType type
, MessageLevel level
, const String
& message
, JSC::ExecState
* state
, PassRefPtr
<ScriptArguments
> arguments
, unsigned long requestIdentifier
)
136 if (!m_injectedScriptManager
->inspectorEnvironment().developerExtrasEnabled())
139 if (type
== MessageType::Clear
) {
141 clearMessages(&error
);
144 addConsoleMessage(std::make_unique
<ConsoleMessage
>(source
, type
, level
, message
, arguments
, state
, requestIdentifier
));
147 void InspectorConsoleAgent::addMessageToConsole(MessageSource source
, MessageType type
, MessageLevel level
, const String
& message
, const String
& scriptID
, unsigned lineNumber
, unsigned columnNumber
, JSC::ExecState
* state
, unsigned long requestIdentifier
)
149 if (!m_injectedScriptManager
->inspectorEnvironment().developerExtrasEnabled())
152 if (type
== MessageType::Clear
) {
154 clearMessages(&error
);
157 addConsoleMessage(std::make_unique
<ConsoleMessage
>(source
, type
, level
, message
, scriptID
, lineNumber
, columnNumber
, state
, requestIdentifier
));
160 Vector
<unsigned> InspectorConsoleAgent::consoleMessageArgumentCounts() const
162 Vector
<unsigned> result(m_consoleMessages
.size());
163 for (size_t i
= 0; i
< m_consoleMessages
.size(); i
++)
164 result
[i
] = m_consoleMessages
[i
]->argumentCount();
168 void InspectorConsoleAgent::startTiming(const String
& title
)
170 // Follow Firebug's behavior of requiring a title that is not null or
171 // undefined for timing functions
175 m_times
.add(title
, monotonicallyIncreasingTime());
178 void InspectorConsoleAgent::stopTiming(const String
& title
, PassRefPtr
<ScriptCallStack
> callStack
)
180 // Follow Firebug's behavior of requiring a title that is not null or
181 // undefined for timing functions
185 HashMap
<String
, double>::iterator it
= m_times
.find(title
);
186 if (it
== m_times
.end())
189 double startTime
= it
->value
;
192 double elapsed
= monotonicallyIncreasingTime() - startTime
;
193 String message
= title
+ String::format(": %.3fms", elapsed
* 1000);
194 addMessageToConsole(MessageSource::ConsoleAPI
, MessageType::Timing
, MessageLevel::Debug
, message
, callStack
);
197 void InspectorConsoleAgent::count(JSC::ExecState
* state
, PassRefPtr
<ScriptArguments
> arguments
)
199 RefPtr
<ScriptCallStack
> callStack(createScriptCallStackForConsole(state
, ScriptCallStack::maxCallStackSizeToCapture
));
200 const ScriptCallFrame
& lastCaller
= callStack
->at(0);
201 // Follow Firebug's behavior of counting with null and undefined title in
202 // the same bucket as no argument
204 arguments
->getFirstArgumentAsString(title
);
205 String identifier
= title
+ '@' + lastCaller
.sourceURL() + ':' + String::number(lastCaller
.lineNumber());
207 HashMap
<String
, unsigned>::iterator it
= m_counts
.find(identifier
);
209 if (it
== m_counts
.end())
212 count
= it
->value
+ 1;
216 m_counts
.add(identifier
, count
);
218 String message
= title
+ ": " + String::number(count
);
219 addMessageToConsole(MessageSource::ConsoleAPI
, MessageType::Log
, MessageLevel::Debug
, message
, callStack
);
222 static bool isGroupMessage(MessageType type
)
224 return type
== MessageType::StartGroup
225 || type
== MessageType::StartGroupCollapsed
226 || type
== MessageType::EndGroup
;
229 void InspectorConsoleAgent::addConsoleMessage(std::unique_ptr
<ConsoleMessage
> consoleMessage
)
231 ASSERT(m_injectedScriptManager
->inspectorEnvironment().developerExtrasEnabled());
232 ASSERT_ARG(consoleMessage
, consoleMessage
);
234 if (m_previousMessage
&& !isGroupMessage(m_previousMessage
->type()) && m_previousMessage
->isEqual(consoleMessage
.get())) {
235 m_previousMessage
->incrementCount();
236 if (m_frontendDispatcher
&& m_enabled
)
237 m_previousMessage
->updateRepeatCountInConsole(m_frontendDispatcher
.get());
239 m_previousMessage
= consoleMessage
.get();
240 m_consoleMessages
.append(WTF::move(consoleMessage
));
241 if (m_frontendDispatcher
&& m_enabled
)
242 m_previousMessage
->addToFrontend(m_frontendDispatcher
.get(), m_injectedScriptManager
, true);
245 if (!m_frontendDispatcher
&& m_consoleMessages
.size() >= maximumConsoleMessages
) {
246 m_expiredConsoleMessageCount
+= expireConsoleMessagesStep
;
247 m_consoleMessages
.remove(0, expireConsoleMessagesStep
);
251 } // namespace Inspector
253 #endif // ENABLE(INSPECTOR)