blob: c7f51d705d876e1eee3c948620b3ca4fb5c38c63 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/inspector/InspectorLogAgent.h"
#include "bindings/core/v8/SourceLocation.h"
#include "core/frame/PerformanceMonitor.h"
#include "core/inspector/ConsoleMessage.h"
#include "core/inspector/ConsoleMessageStorage.h"
#include "core/inspector/IdentifiersFactory.h"
namespace blink {
namespace LogAgentState {
static const char logEnabled[] = "logEnabled";
static const char logViolations[] = "logViolations";
}
namespace {
String messageSourceValue(MessageSource source) {
DCHECK(source != ConsoleAPIMessageSource);
switch (source) {
case XMLMessageSource:
return protocol::Log::LogEntry::SourceEnum::Xml;
case JSMessageSource:
return protocol::Log::LogEntry::SourceEnum::Javascript;
case NetworkMessageSource:
return protocol::Log::LogEntry::SourceEnum::Network;
case StorageMessageSource:
return protocol::Log::LogEntry::SourceEnum::Storage;
case AppCacheMessageSource:
return protocol::Log::LogEntry::SourceEnum::Appcache;
case RenderingMessageSource:
return protocol::Log::LogEntry::SourceEnum::Rendering;
case SecurityMessageSource:
return protocol::Log::LogEntry::SourceEnum::Security;
case OtherMessageSource:
return protocol::Log::LogEntry::SourceEnum::Other;
case DeprecationMessageSource:
return protocol::Log::LogEntry::SourceEnum::Deprecation;
case WorkerMessageSource:
return protocol::Log::LogEntry::SourceEnum::Worker;
case ViolationMessageSource:
return protocol::Log::LogEntry::SourceEnum::Violation;
default:
return protocol::Log::LogEntry::SourceEnum::Other;
}
}
String messageLevelValue(MessageLevel level) {
switch (level) {
case DebugMessageLevel:
return protocol::Log::LogEntry::LevelEnum::Debug;
case LogMessageLevel:
return protocol::Log::LogEntry::LevelEnum::Log;
case WarningMessageLevel:
return protocol::Log::LogEntry::LevelEnum::Warning;
case ErrorMessageLevel:
return protocol::Log::LogEntry::LevelEnum::Error;
case InfoMessageLevel:
return protocol::Log::LogEntry::LevelEnum::Info;
}
return protocol::Log::LogEntry::LevelEnum::Log;
}
} // namespace
using protocol::Log::ViolationSetting;
InspectorLogAgent::InspectorLogAgent(ConsoleMessageStorage* storage,
PerformanceMonitor* performanceMonitor)
: m_enabled(false),
m_storage(storage),
m_performanceMonitor(performanceMonitor) {}
InspectorLogAgent::~InspectorLogAgent() {}
DEFINE_TRACE(InspectorLogAgent) {
visitor->trace(m_storage);
visitor->trace(m_performanceMonitor);
InspectorBaseAgent::trace(visitor);
PerformanceMonitor::Client::trace(visitor);
}
void InspectorLogAgent::restore() {
if (!m_state->booleanProperty(LogAgentState::logEnabled, false))
return;
enable();
protocol::Value* config = m_state->get(LogAgentState::logViolations);
if (config) {
protocol::ErrorSupport errors;
startViolationsReport(
protocol::Array<ViolationSetting>::fromValue(config, &errors));
}
}
void InspectorLogAgent::consoleMessageAdded(ConsoleMessage* message) {
DCHECK(m_enabled);
std::unique_ptr<protocol::Log::LogEntry> entry =
protocol::Log::LogEntry::create()
.setSource(messageSourceValue(message->source()))
.setLevel(messageLevelValue(message->level()))
.setText(message->message())
.setTimestamp(message->timestamp())
.build();
if (!message->location()->url().isEmpty())
entry->setUrl(message->location()->url());
std::unique_ptr<v8_inspector::protocol::Runtime::API::StackTrace> stackTrace =
message->location()->buildInspectorObject();
if (stackTrace)
entry->setStackTrace(std::move(stackTrace));
if (message->location()->lineNumber())
entry->setLineNumber(message->location()->lineNumber() - 1);
if (message->source() == WorkerMessageSource &&
!message->workerId().isEmpty())
entry->setWorkerId(message->workerId());
if (message->source() == NetworkMessageSource && message->requestIdentifier())
entry->setNetworkRequestId(
IdentifiersFactory::requestId(message->requestIdentifier()));
frontend()->entryAdded(std::move(entry));
frontend()->flush();
}
Response InspectorLogAgent::enable() {
if (m_enabled)
return Response::OK();
m_instrumentingAgents->addInspectorLogAgent(this);
m_state->setBoolean(LogAgentState::logEnabled, true);
m_enabled = true;
if (m_storage->expiredCount()) {
std::unique_ptr<protocol::Log::LogEntry> expired =
protocol::Log::LogEntry::create()
.setSource(protocol::Log::LogEntry::SourceEnum::Other)
.setLevel(protocol::Log::LogEntry::LevelEnum::Warning)
.setText(String::number(m_storage->expiredCount()) +
String(" log entires are not shown."))
.setTimestamp(0)
.build();
frontend()->entryAdded(std::move(expired));
frontend()->flush();
}
for (size_t i = 0; i < m_storage->size(); ++i)
consoleMessageAdded(m_storage->at(i));
return Response::OK();
}
Response InspectorLogAgent::disable() {
if (!m_enabled)
return Response::OK();
m_state->setBoolean(LogAgentState::logEnabled, false);
stopViolationsReport();
m_enabled = false;
m_instrumentingAgents->removeInspectorLogAgent(this);
return Response::OK();
}
Response InspectorLogAgent::clear() {
m_storage->clear();
return Response::OK();
}
static PerformanceMonitor::Violation parseViolation(const String& name) {
if (name == ViolationSetting::NameEnum::LongTask)
return PerformanceMonitor::kLongTask;
if (name == ViolationSetting::NameEnum::LongLayout)
return PerformanceMonitor::kLongLayout;
if (name == ViolationSetting::NameEnum::BlockedEvent)
return PerformanceMonitor::kBlockedEvent;
if (name == ViolationSetting::NameEnum::BlockedParser)
return PerformanceMonitor::kBlockedParser;
if (name == ViolationSetting::NameEnum::Handler)
return PerformanceMonitor::kHandler;
if (name == ViolationSetting::NameEnum::RecurringHandler)
return PerformanceMonitor::kRecurringHandler;
return PerformanceMonitor::kAfterLast;
}
Response InspectorLogAgent::startViolationsReport(
std::unique_ptr<protocol::Array<ViolationSetting>> settings) {
if (!m_enabled)
return Response::Error("Log is not enabled");
m_state->setValue(LogAgentState::logViolations, settings->toValue());
if (!m_performanceMonitor)
return Response::Error("Violations are not supported for this target");
m_performanceMonitor->unsubscribeAll(this);
for (size_t i = 0; i < settings->length(); ++i) {
PerformanceMonitor::Violation violation =
parseViolation(settings->get(i)->getName());
if (violation == PerformanceMonitor::kAfterLast)
continue;
m_performanceMonitor->subscribe(
violation, settings->get(i)->getThreshold() / 1000, this);
}
return Response::OK();
}
Response InspectorLogAgent::stopViolationsReport() {
m_state->remove(LogAgentState::logViolations);
if (!m_performanceMonitor)
return Response::Error("Violations are not supported for this target");
m_performanceMonitor->unsubscribeAll(this);
return Response::OK();
}
void InspectorLogAgent::reportLongLayout(double duration) {
String messageText =
String::format("Forced reflow while executing JavaScript took %ldms",
lround(duration * 1000));
ConsoleMessage* message = ConsoleMessage::create(
ViolationMessageSource, WarningMessageLevel, messageText);
consoleMessageAdded(message);
}
void InspectorLogAgent::reportGenericViolation(PerformanceMonitor::Violation,
const String& text,
double time,
SourceLocation* location) {
ConsoleMessage* message = ConsoleMessage::create(
ViolationMessageSource, WarningMessageLevel, text, location->clone());
consoleMessageAdded(message);
};
} // namespace blink