InspectorConsoleAgent.cpp [plain text]
#include "config.h"
#include "InspectorConsoleAgent.h"
#if ENABLE(INSPECTOR)
#include "ConsoleMessage.h"
#include "InjectedScriptManager.h"
#include "ScriptArguments.h"
#include "ScriptCallFrame.h"
#include "ScriptCallStack.h"
#include "ScriptCallStackFactory.h"
#include "ScriptObject.h"
#include <wtf/CurrentTime.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/WTFString.h>
namespace Inspector {
static const unsigned maximumConsoleMessages = 1000;
static const int expireConsoleMessagesStep = 100;
InspectorConsoleAgent::InspectorConsoleAgent(InjectedScriptManager* injectedScriptManager)
: InspectorAgentBase(ASCIILiteral("Console"))
, m_injectedScriptManager(injectedScriptManager)
, m_previousMessage(nullptr)
, m_expiredConsoleMessageCount(0)
, m_enabled(false)
{
}
InspectorConsoleAgent::~InspectorConsoleAgent()
{
}
void InspectorConsoleAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
{
m_frontendDispatcher = std::make_unique<InspectorConsoleFrontendDispatcher>(frontendChannel);
m_backendDispatcher = InspectorConsoleBackendDispatcher::create(backendDispatcher, this);
}
void InspectorConsoleAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
{
m_frontendDispatcher = nullptr;
m_backendDispatcher.clear();
String errorString;
disable(&errorString);
}
void InspectorConsoleAgent::enable(ErrorString*)
{
if (m_enabled)
return;
m_enabled = true;
if (m_expiredConsoleMessageCount) {
ConsoleMessage expiredMessage(MessageSource::Other, MessageType::Log, MessageLevel::Warning, String::format("%d console messages are not shown.", m_expiredConsoleMessageCount));
expiredMessage.addToFrontend(m_frontendDispatcher.get(), m_injectedScriptManager, false);
}
size_t messageCount = m_consoleMessages.size();
for (size_t i = 0; i < messageCount; ++i)
m_consoleMessages[i]->addToFrontend(m_frontendDispatcher.get(), m_injectedScriptManager, false);
}
void InspectorConsoleAgent::disable(ErrorString*)
{
if (!m_enabled)
return;
m_enabled = false;
}
void InspectorConsoleAgent::clearMessages(ErrorString*)
{
m_consoleMessages.clear();
m_expiredConsoleMessageCount = 0;
m_previousMessage = nullptr;
m_injectedScriptManager->releaseObjectGroup(ASCIILiteral("console"));
if (m_frontendDispatcher && m_enabled)
m_frontendDispatcher->messagesCleared();
}
void InspectorConsoleAgent::reset()
{
ErrorString error;
clearMessages(&error);
m_times.clear();
m_counts.clear();
}
void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier)
{
if (!m_injectedScriptManager->inspectorEnvironment().developerExtrasEnabled())
return;
if (type == MessageType::Clear) {
ErrorString error;
clearMessages(&error);
}
addConsoleMessage(std::make_unique<ConsoleMessage>(source, type, level, message, callStack, requestIdentifier));
}
void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, JSC::ExecState* state, PassRefPtr<ScriptArguments> arguments, unsigned long requestIdentifier)
{
if (!m_injectedScriptManager->inspectorEnvironment().developerExtrasEnabled())
return;
if (type == MessageType::Clear) {
ErrorString error;
clearMessages(&error);
}
addConsoleMessage(std::make_unique<ConsoleMessage>(source, type, level, message, arguments, state, requestIdentifier));
}
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)
{
if (!m_injectedScriptManager->inspectorEnvironment().developerExtrasEnabled())
return;
if (type == MessageType::Clear) {
ErrorString error;
clearMessages(&error);
}
addConsoleMessage(std::make_unique<ConsoleMessage>(source, type, level, message, scriptID, lineNumber, columnNumber, state, requestIdentifier));
}
Vector<unsigned> InspectorConsoleAgent::consoleMessageArgumentCounts() const
{
Vector<unsigned> result(m_consoleMessages.size());
for (size_t i = 0; i < m_consoleMessages.size(); i++)
result[i] = m_consoleMessages[i]->argumentCount();
return result;
}
void InspectorConsoleAgent::startTiming(const String& title)
{
if (title.isNull())
return;
m_times.add(title, monotonicallyIncreasingTime());
}
void InspectorConsoleAgent::stopTiming(const String& title, PassRefPtr<ScriptCallStack> callStack)
{
if (title.isNull())
return;
HashMap<String, double>::iterator it = m_times.find(title);
if (it == m_times.end())
return;
double startTime = it->value;
m_times.remove(it);
double elapsed = monotonicallyIncreasingTime() - startTime;
String message = title + String::format(": %.3fms", elapsed * 1000);
addMessageToConsole(MessageSource::ConsoleAPI, MessageType::Timing, MessageLevel::Debug, message, callStack);
}
void InspectorConsoleAgent::count(JSC::ExecState* state, PassRefPtr<ScriptArguments> arguments)
{
RefPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(state, ScriptCallStack::maxCallStackSizeToCapture));
const ScriptCallFrame& lastCaller = callStack->at(0);
String title;
arguments->getFirstArgumentAsString(title);
String identifier = title + '@' + lastCaller.sourceURL() + ':' + String::number(lastCaller.lineNumber());
HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
int count;
if (it == m_counts.end())
count = 1;
else {
count = it->value + 1;
m_counts.remove(it);
}
m_counts.add(identifier, count);
String message = title + ": " + String::number(count);
addMessageToConsole(MessageSource::ConsoleAPI, MessageType::Log, MessageLevel::Debug, message, callStack);
}
static bool isGroupMessage(MessageType type)
{
return type == MessageType::StartGroup
|| type == MessageType::StartGroupCollapsed
|| type == MessageType::EndGroup;
}
void InspectorConsoleAgent::addConsoleMessage(std::unique_ptr<ConsoleMessage> consoleMessage)
{
ASSERT(m_injectedScriptManager->inspectorEnvironment().developerExtrasEnabled());
ASSERT_ARG(consoleMessage, consoleMessage);
if (m_previousMessage && !isGroupMessage(m_previousMessage->type()) && m_previousMessage->isEqual(consoleMessage.get())) {
m_previousMessage->incrementCount();
if (m_frontendDispatcher && m_enabled)
m_previousMessage->updateRepeatCountInConsole(m_frontendDispatcher.get());
} else {
m_previousMessage = consoleMessage.get();
m_consoleMessages.append(WTF::move(consoleMessage));
if (m_frontendDispatcher && m_enabled)
m_previousMessage->addToFrontend(m_frontendDispatcher.get(), m_injectedScriptManager, true);
}
if (!m_frontendDispatcher && m_consoleMessages.size() >= maximumConsoleMessages) {
m_expiredConsoleMessageCount += expireConsoleMessagesStep;
m_consoleMessages.remove(0, expireConsoleMessagesStep);
}
}
}
#endif // ENABLE(INSPECTOR)